diff options
author | Hung-Te Lin <hungte@chromium.org> | 2013-01-30 20:02:02 +0800 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2013-01-30 19:51:23 +0100 |
commit | 7e494050d6ae7626a2eef06fb9bdd1d25e0e74c4 (patch) | |
tree | a79ac7763ab06ee54c02c6bb66d5d4d1d59bdde9 /src/mainboard | |
parent | 6fe0cab205e131525efbfce4f59da344b1e76598 (diff) |
armv7: Add SPI driver for Exynos.
The SPI flash driver for Exynos chipset.
Verified to boot on snow/armv7.
Change-Id: I7eef67a9c57f825d09f13ea44c2b59b54345fa7b
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: http://review.coreboot.org/2229
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/mainboard')
-rw-r--r-- | src/mainboard/google/snow/bootblock.c | 251 |
1 files changed, 5 insertions, 246 deletions
diff --git a/src/mainboard/google/snow/bootblock.c b/src/mainboard/google/snow/bootblock.c index 5b3efa025c..3887e7e06d 100644 --- a/src/mainboard/google/snow/bootblock.c +++ b/src/mainboard/google/snow/bootblock.c @@ -17,11 +17,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define uchar unsigned char -#define uint unsigned int - #include <stdlib.h> #include <types.h> +#include <assert.h> +#include <arch/armv7/include/common.h> #include <arch/io.h> #include "cpu/samsung/exynos5250/clk.h" #include "cpu/samsung/exynos5250/cpu.h" @@ -46,87 +45,6 @@ /* TODO Move to Makefile.inc once we support adding bootblock stage files. */ #include "cpu/samsung/exynos5-common/spi.c" -/* FIXME(dhendrix): Can we move this SPI stuff elsewhere? */ -static void spi_rx_tx(struct exynos_spi *regs, int todo, - void *dinp, void const *doutp, int i) -{ - unsigned int *rxp = (unsigned int *)(dinp + (i * (32 * 1024))); - int rx_lvl, tx_lvl; - unsigned int out_bytes, in_bytes; - - out_bytes = in_bytes = todo; - setbits_le32(®s->ch_cfg, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_CH_RST); - writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt); - - while (in_bytes) { - uint32_t spi_sts; - int temp; - - spi_sts = readl(®s->spi_sts); - rx_lvl = ((spi_sts >> 15) & 0x7f); - tx_lvl = ((spi_sts >> 6) & 0x7f); - while (tx_lvl < 32 && out_bytes) { - temp = 0xffffffff; - writel(temp, ®s->tx_data); - out_bytes -= 4; - tx_lvl += 4; - } - while (rx_lvl >= 4 && in_bytes) { - temp = readl(®s->rx_data); - if (rxp) - *rxp++ = temp; - in_bytes -= 4; - rx_lvl -= 4; - } - } -} - -#if 0 -void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor) -{ - struct exynos5_clock *clk = - (struct exynos5_clock *)samsung_get_base_clock(); - unsigned shift; - unsigned mask = 0xff; - u32 *reg; - - /* - * For now we only handle a very small subset of peipherals here. - * Others will need to (and do) mangle the clock registers - * themselves, At some point it is hoped that this function can work - * from a table or calculated register offset / mask. For now this - * is at least better than spreading clock control code around - * U-Boot. - */ - switch (periph_id) { - case PERIPH_ID_SPI0: - reg = &clk->div_peric1; - shift = 8; - break; - case PERIPH_ID_SPI1: - reg = &clk->div_peric1; - shift = 24; - break; - case PERIPH_ID_SPI2: - reg = &clk->div_peric2; - shift = 8; - break; - case PERIPH_ID_SPI3: - reg = &clk->sclk_div_isp; - shift = 4; - break; - case PERIPH_ID_SPI4: - reg = &clk->sclk_div_isp; - shift = 16; - break; - default: - debug("%s: Unsupported peripheral ID %d\n", __func__, - periph_id); - return; - } -} -#endif void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor) { struct exynos5_clock *clk = @@ -140,43 +58,6 @@ void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor) clrsetbits_le32(reg, mask << shift, (divisor & mask) << shift); } -#if 0 -void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor) -{ - struct exynos5_clock *clk = - (struct exynos5_clock *)samsung_get_base_clock(); - unsigned shift; - unsigned mask = 0xff; - u32 *reg; - - switch (periph_id) { - case PERIPH_ID_SPI0: - reg = &clk->div_peric1; - shift = 0; - break; - case PERIPH_ID_SPI1: - reg = &clk->div_peric1; - shift = 16; - break; - case PERIPH_ID_SPI2: - reg = &clk->div_peric2; - shift = 0; - break; - case PERIPH_ID_SPI3: - reg = &clk->sclk_div_isp; - shift = 0; - break; - case PERIPH_ID_SPI4: - reg = &clk->sclk_div_isp; - shift = 12; - break; - default: - debug("%s: Unsupported peripheral ID %d\n", __func__, - periph_id); - return; - } -} -#endif void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor) { struct exynos5_clock *clk = @@ -253,44 +134,6 @@ static int clock_calc_best_scalar(unsigned int main_scaler_bits, return best_main_scalar; } -#if 0 -int clock_set_rate(enum periph_id periph_id, unsigned int rate) -{ - int main; - unsigned int fine; - - switch (periph_id) { - case PERIPH_ID_SPI0: - case PERIPH_ID_SPI1: - case PERIPH_ID_SPI2: - case PERIPH_ID_SPI3: - case PERIPH_ID_SPI4: - main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); - if (main < 0) { - debug("%s: Cannot set clock rate for periph %d", - __func__, periph_id); - return -1; - } - clock_ll_set_ratio(periph_id, main - 1); - clock_ll_set_pre_ratio(periph_id, fine - 1); - break; - default: - debug("%s: Unsupported peripheral ID %d\n", __func__, - periph_id); - return -1; - } - main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); - if (main < 0) { - debug("%s: Cannot set clock rate for periph %d", - __func__, periph_id); - return -1; - } - clock_ll_set_ratio(PERIPH_ID_SPI1, main - 1); - clock_ll_set_pre_ratio(PERIPH_ID_SPI1, fine - 1); - - return 0; -} -#endif int clock_set_rate(enum periph_id periph_id, unsigned int rate) { int main; @@ -362,77 +205,6 @@ void gpio_cfg_pin(int gpio, int cfg) writel(value, &bank->con); } -//static void exynos_spi_copy(unsigned int uboot_size) -static void copy_romstage(uint32_t spi_addr, uint32_t sram_addr, unsigned int len) -{ - int upto, todo; - int i; -// struct exynos_spi *regs = (struct exynos_spi *)samsung_get_base_spi1(); - struct exynos_spi *regs = (struct exynos_spi *)0x12d30000; - - clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ - /* set the spi1 GPIO */ -// exynos_pinmux_config(PERIPH_ID_SPI1, PINMUX_FLAG_NONE); - gpio_cfg_pin(GPIO_A24, 0x2); - gpio_cfg_pin(GPIO_A25, 0x2); - gpio_cfg_pin(GPIO_A26, 0x2); - gpio_cfg_pin(GPIO_A27, 0x2); - - /* set pktcnt and enable it */ - writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt); - /* set FB_CLK_SEL */ - writel(SPI_FB_DELAY_180, ®s->fb_clk); - /* set CH_WIDTH and BUS_WIDTH as word */ - setbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | - SPI_MODE_BUS_WIDTH_WORD); - clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */ - - /* clear rx and tx channel if set priveously */ - clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON); - - setbits_le32(®s->swap_cfg, SPI_RX_SWAP_EN | - SPI_RX_BYTE_SWAP | - SPI_RX_HWORD_SWAP); - - /* do a soft reset */ - setbits_le32(®s->ch_cfg, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_CH_RST); - - /* now set rx and tx channel ON */ - setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN); - clrbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */ - - /* Send read instruction (0x3h) followed by a 24 bit addr */ - writel((SF_READ_DATA_CMD << 24) | spi_addr, ®s->tx_data); - - /* waiting for TX done */ - while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE)); - - for (upto = 0, i = 0; upto < len; upto += todo, i++) { - todo = MIN(len - upto, (1 << 15)); - spi_rx_tx(regs, todo, (void *)(sram_addr), - (void *)(spi_addr), i); - } - - setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */ - - /* - * Let put controller mode to BYTE as - * SPI driver does not support WORD mode yet - */ - clrbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | - SPI_MODE_BUS_WIDTH_WORD); - writel(0, ®s->swap_cfg); - - /* - * Flush spi tx, rx fifos and reset the SPI controller - * and clear rx/tx channel - */ - clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); -} - /* Pull mode */ #define EXYNOS_GPIO_PULL_NONE 0x0 #define EXYNOS_GPIO_PULL_DOWN 0x1 @@ -854,21 +626,15 @@ void do_barriers(void) ); } -void sdelay(unsigned long loops); -void sdelay(unsigned long loops) -{ - __asm__ volatile ("1:\n" "subs %0, %1, #1\n" - "bne 1b":"=r" (loops):"0"(loops)); -} - /* is this right? meh, it seems to work well enough... */ void my_udelay(unsigned int n); void my_udelay(unsigned int n) { - sdelay(n * 1000); + n *= 1000; + __asm__ volatile ("1:\n" "subs %0, %1, #1\n" + "bne 1b":"=r" (n):"0"(n)); } - void i2c_init(int speed, int slaveadd) { struct s3c24x0_i2c_bus *i2c = &i2c0; @@ -2145,13 +1911,6 @@ void bootblock_mainboard_init(void) do_serial(); printk(BIOS_INFO, "%s: UART initialized\n", __func__); - /* Copy romstage data from SPI ROM to SRAM */ - printk(BIOS_INFO, "Copying romstage:\n" - "\tSPI offset: 0x%06x\n" - "\tiRAM offset: 0x%08x\n" - "\tSize: 0x%x\n", - 0, CONFIG_SPI_IMAGE_HACK, CONFIG_ROMSTAGE_SIZE); - copy_romstage(0x0, CONFIG_SPI_IMAGE_HACK, CONFIG_ROMSTAGE_SIZE); #if 0 /* FIXME: dump SRAM content for sanity checking */ uint32_t u; |