From c95219fae2a7add7daa2f91aedca65b1698465c7 Mon Sep 17 00:00:00 2001 From: stefano babic Date: Tue, 20 Nov 2007 10:40:24 +0100 Subject: MMC for PXA 27X (resubmit) MMC support for X_Scale PXA is broken and does not work. Mainly, the mmc_init() function cannot recognize current SD/MMC cards. There were already some patches around the world but none of them was merged into the official u-boot tree. This patch makes order fixing this issue. Resubmit after code cleanup. Applied and tested on PXA 270 (TrizepsIV module). Signed-off-by: Stefano Babic --- cpu/pxa/mmc.c | 499 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 336 insertions(+), 163 deletions(-) (limited to 'cpu') diff --git a/cpu/pxa/mmc.c b/cpu/pxa/mmc.c index d76e0cdfe3..c0cfe65fb0 100644 --- a/cpu/pxa/mmc.c +++ b/cpu/pxa/mmc.c @@ -30,14 +30,13 @@ #ifdef CONFIG_MMC -extern int -fat_register_device(block_dev_desc_t *dev_desc, int part_no); +extern int fat_register_device(block_dev_desc_t * dev_desc, int part_no); static block_dev_desc_t mmc_dev; -block_dev_desc_t * mmc_get_dev(int dev) +block_dev_desc_t *mmc_get_dev(int dev) { - return (dev == 0) ? &mmc_dev : NULL; + return ((block_dev_desc_t *) & mmc_dev); } /* @@ -45,72 +44,59 @@ block_dev_desc_t * mmc_get_dev(int dev) * and other parameters */ static uchar mmc_buf[MMC_BLOCK_SIZE]; -static mmc_csd_t mmc_csd; +static uchar spec_ver; static int mmc_ready = 0; +static int wide = 0; - -static uchar * +static uint32_t * /****************************************************/ mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat) /****************************************************/ { - static uchar resp[20]; + static uint32_t resp[4], a, b, c; ulong status; - int words, i; + int i; - debug("mmc_cmd %x %x %x %x\n", cmd, argh, argl, cmdat); + debug("mmc_cmd %u 0x%04x 0x%04x 0x%04x\n", cmd, argh, argl, + cmdat | wide); MMC_STRPCL = MMC_STRPCL_STOP_CLK; MMC_I_MASK = ~MMC_I_MASK_CLK_IS_OFF; - while (!(MMC_I_REG & MMC_I_REG_CLK_IS_OFF)); - MMC_CMD = cmd; - MMC_ARGH = argh; - MMC_ARGL = argl; - MMC_CMDAT = cmdat; + while (!(MMC_I_REG & MMC_I_REG_CLK_IS_OFF)) ; + MMC_CMD = cmd; + MMC_ARGH = argh; + MMC_ARGL = argl; + MMC_CMDAT = cmdat | wide; MMC_I_MASK = ~MMC_I_MASK_END_CMD_RES; MMC_STRPCL = MMC_STRPCL_START_CLK; - while (!(MMC_I_REG & MMC_I_REG_END_CMD_RES)); + while (!(MMC_I_REG & MMC_I_REG_END_CMD_RES)) ; status = MMC_STAT; - debug("MMC status %x\n", status); + debug("MMC status 0x%08x\n", status); if (status & MMC_STAT_TIME_OUT_RESPONSE) { return 0; } - switch (cmdat & 0x3) { - case MMC_CMDAT_R1: - case MMC_CMDAT_R3: - words = 3; - break; - - case MMC_CMDAT_R2: - words = 8; - break; - - default: - return 0; + /* Linux says: + * Did I mention this is Sick. We always need to + * discard the upper 8 bits of the first 16-bit word. + */ + a = (MMC_RES & 0xffff); + for (i = 0; i < 4; i++) { + b = (MMC_RES & 0xffff); + c = (MMC_RES & 0xffff); + resp[i] = (a << 24) | (b << 8) | (c >> 8); + a = c; + debug("MMC resp[%d] = %#08x\n", i, resp[i]); } - for (i = words-1; i >= 0; i--) { - ulong res_fifo = MMC_RES; - int offset = i << 1; - resp[offset] = ((uchar *)&res_fifo)[0]; - resp[offset+1] = ((uchar *)&res_fifo)[1]; - } -#ifdef MMC_DEBUG - for (i=0; i> 16; argl = len & 0xffff; /* set block len */ - resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); + mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); /* send read command */ argh = src >> 16; @@ -133,17 +119,17 @@ mmc_block_read(uchar *dst, ulong src, ulong len) MMC_RDTO = 0xffff; MMC_NOB = 1; MMC_BLKLEN = len; - resp = mmc_cmd(MMC_CMD_READ_BLOCK, argh, argl, - MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN); - + mmc_cmd(MMC_CMD_READ_BLOCK, argh, argl, + MMC_CMDAT_R1 | MMC_CMDAT_READ | MMC_CMDAT_BLOCK | + MMC_CMDAT_DATA_EN); MMC_I_MASK = ~MMC_I_MASK_RXFIFO_RD_REQ; while (len) { if (MMC_I_REG & MMC_I_REG_RXFIFO_RD_REQ) { #ifdef CONFIG_PXA27X int i; - for (i=min(len,32); i; i--) { - *dst++ = * ((volatile uchar *) &MMC_RXFIFO); + for (i = min(len, 32); i; i--) { + *dst++ = *((volatile uchar *)&MMC_RXFIFO); len--; } #else @@ -158,7 +144,7 @@ mmc_block_read(uchar *dst, ulong src, ulong len) } } MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE; - while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)); + while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)) ; status = MMC_STAT; if (status & MMC_STAT_ERRORS) { printf("MMC_STAT error %lx\n", status); @@ -169,10 +155,9 @@ mmc_block_read(uchar *dst, ulong src, ulong len) int /****************************************************/ -mmc_block_write(ulong dst, uchar *src, int len) +mmc_block_write(ulong dst, uchar * src, int len) /****************************************************/ { - uchar *resp; ushort argh, argl; ulong status; @@ -180,13 +165,13 @@ mmc_block_write(ulong dst, uchar *src, int len) return 0; } - debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong)src, len); + debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong) src, len); argh = len >> 16; argl = len & 0xffff; /* set block len */ - resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); + mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); /* send write command */ argh = dst >> 16; @@ -194,15 +179,16 @@ mmc_block_write(ulong dst, uchar *src, int len) MMC_STRPCL = MMC_STRPCL_STOP_CLK; MMC_NOB = 1; MMC_BLKLEN = len; - resp = mmc_cmd(MMC_CMD_WRITE_BLOCK, argh, argl, - MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN); + mmc_cmd(MMC_CMD_WRITE_BLOCK, argh, argl, + MMC_CMDAT_R1 | MMC_CMDAT_WRITE | MMC_CMDAT_BLOCK | + MMC_CMDAT_DATA_EN); MMC_I_MASK = ~MMC_I_MASK_TXFIFO_WR_REQ; while (len) { if (MMC_I_REG & MMC_I_REG_TXFIFO_WR_REQ) { - int i, bytes = min(32,len); + int i, bytes = min(32, len); - for (i=0; i> __shft; \ + if (__size + __shft > 32) \ + __res |= resp[__off-1] << ((32 - __shft) % 32); \ + __res & __mask; \ + }) + +/* + * Given the decoded CSD structure, decode the raw CID to our CID structure. + */ +static void mmc_decode_cid(uint32_t * resp) +{ + if (IF_TYPE_SD == mmc_dev.if_type) { + /* + * SD doesn't currently have a version field so we will + * have to assume we can parse this. + */ + sprintf((char *)mmc_dev.vendor, + "Man %02x OEM %c%c \"%c%c%c%c%c\" Date %02u/%04u", + UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, 112, 8), + UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, 96, 8), + UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, 80, 8), + UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, 64, 8), + UNSTUFF_BITS(resp, 8, 4), UNSTUFF_BITS(resp, 12, + 8) + 2000); + sprintf((char *)mmc_dev.revision, "%d.%d", + UNSTUFF_BITS(resp, 60, 4), UNSTUFF_BITS(resp, 56, 4)); + sprintf((char *)mmc_dev.product, "%u", + UNSTUFF_BITS(resp, 24, 32)); + } else { + /* + * The selection of the format here is based upon published + * specs from sandisk and from what people have reported. + */ + switch (spec_ver) { + case 0: /* MMC v1.0 - v1.2 */ + case 1: /* MMC v1.4 */ + sprintf((char *)mmc_dev.vendor, + "Man %02x%02x%02x \"%c%c%c%c%c%c%c\" Date %02u/%04u", + UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, + 112, + 8), + UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, + 96, 8), + UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, + 80, 8), + UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, + 64, 8), + UNSTUFF_BITS(resp, 56, 8), UNSTUFF_BITS(resp, + 48, 8), + UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8, + 4) + + 1997); + sprintf((char *)mmc_dev.revision, "%d.%d", + UNSTUFF_BITS(resp, 44, 4), UNSTUFF_BITS(resp, + 40, 4)); + sprintf((char *)mmc_dev.product, "%u", + UNSTUFF_BITS(resp, 16, 24)); + break; + + case 2: /* MMC v2.0 - v2.2 */ + case 3: /* MMC v3.1 - v3.3 */ + case 4: /* MMC v4 */ + sprintf((char *)mmc_dev.vendor, + "Man %02x OEM %04x \"%c%c%c%c%c%c\" Date %02u/%04u", + UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, + 104, + 16), + UNSTUFF_BITS(resp, 96, 8), UNSTUFF_BITS(resp, + 88, 8), + UNSTUFF_BITS(resp, 80, 8), UNSTUFF_BITS(resp, + 72, 8), + UNSTUFF_BITS(resp, 64, 8), UNSTUFF_BITS(resp, + 56, 8), + UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8, + 4) + + 1997); + sprintf((char *)mmc_dev.product, "%u", + UNSTUFF_BITS(resp, 16, 32)); + sprintf((char *)mmc_dev.revision, "N/A"); + break; + + default: + printf("MMC card has unknown MMCA version %d\n", + spec_ver); + break; + } + } + printf("%s card.\nVendor: %s\nProduct: %s\nRevision: %s\n", + (IF_TYPE_SD == mmc_dev.if_type) ? "SD" : "MMC", mmc_dev.vendor, + mmc_dev.product, mmc_dev.revision); +} + +/* + * Given a 128-bit response, decode to our card CSD structure. + */ +static void mmc_decode_csd(uint32_t * resp) +{ + unsigned int mult, csd_struct; + + if (IF_TYPE_SD == mmc_dev.if_type) { + csd_struct = UNSTUFF_BITS(resp, 126, 2); + if (csd_struct != 0) { + printf("SD: unrecognised CSD structure version %d\n", + csd_struct); + return; + } + } else { + /* + * We only understand CSD structure v1.1 and v1.2. + * v1.2 has extra information in bits 15, 11 and 10. + */ + csd_struct = UNSTUFF_BITS(resp, 126, 2); + if (csd_struct != 1 && csd_struct != 2) { + printf("MMC: unrecognised CSD structure version %d\n", + csd_struct); + return; + } + + spec_ver = UNSTUFF_BITS(resp, 122, 4); + mmc_dev.if_type = IF_TYPE_MMC; + } + + mult = 1 << (UNSTUFF_BITS(resp, 47, 3) + 2); + mmc_dev.lba = (1 + UNSTUFF_BITS(resp, 62, 12)) * mult; + mmc_dev.blksz = 1 << UNSTUFF_BITS(resp, 80, 4); + + /* FIXME: The following just makes assumes that's the partition type -- should really read it */ + mmc_dev.part_type = PART_TYPE_DOS; + mmc_dev.dev = 0; + mmc_dev.lun = 0; + mmc_dev.type = DEV_TYPE_HARDDISK; + mmc_dev.removable = 0; + mmc_dev.block_read = mmc_bread; + + printf("Detected: %u blocks of %u bytes (%uMB) ", mmc_dev.lba, + mmc_dev.blksz, mmc_dev.lba * mmc_dev.blksz / (1024 * 1024)); +} + int /****************************************************/ mmc_init(int verbose) /****************************************************/ { - int retries, rc = -ENODEV; - uchar *resp; + int retries, rc = -ENODEV; + uint32_t cid_resp[4]; + uint32_t *resp; + uint16_t rca = 0; + + /* Reset device interface type */ + mmc_dev.if_type = IF_TYPE_UNKNOWN; -#ifdef CONFIG_LUBBOCK - set_GPIO_mode( GPIO6_MMCCLK_MD ); - set_GPIO_mode( GPIO8_MMCCS0_MD ); +#if defined (CONFIG_LUBBOCK) || (defined (CONFIG_GUMSTIX) && !defined(CONFIG_PXA27X)) + set_GPIO_mode(GPIO6_MMCCLK_MD); + set_GPIO_mode(GPIO8_MMCCS0_MD); #endif - CKEN |= CKEN12_MMC; /* enable MMC unit clock */ + CKEN |= CKEN12_MMC; /* enable MMC unit clock */ #if defined(CONFIG_ADSVIX) /* turn on the power */ GPCR(114) = GPIO_bit(114); udelay(1000); #endif - mmc_csd.c_size = 0; - - MMC_CLKRT = MMC_CLKRT_0_3125MHZ; - MMC_RESTO = MMC_RES_TO_MAX; - MMC_SPI = MMC_SPI_DISABLE; + MMC_CLKRT = MMC_CLKRT_0_3125MHZ; + MMC_RESTO = MMC_RES_TO_MAX; + MMC_SPI = MMC_SPI_DISABLE; /* reset */ - retries = 10; - resp = mmc_cmd(0, 0, 0, 0); - resp = mmc_cmd(1, 0x00ff, 0xc000, MMC_CMDAT_INIT|MMC_CMDAT_BUSY|MMC_CMDAT_R3); - while (retries-- && resp && !(resp[4] & 0x80)) { - debug("resp %x %x\n", resp[0], resp[1]); + mmc_cmd(MMC_CMD_RESET, 0, 0, MMC_CMDAT_INIT | MMC_CMDAT_R0); + udelay(200000); + retries = 3; + while (retries--) { + resp = mmc_cmd(MMC_CMD_APP_CMD, 0, 0, MMC_CMDAT_R1); + if (!(resp[0] & 0x00000020)) { /* Card does not support APP_CMD */ + debug("Card does not support APP_CMD\n"); + break; + } + + resp = mmc_cmd(SD_CMD_APP_OP_COND, 0x0020, 0, MMC_CMDAT_R3 | (retries < 2 ? 0 : MMC_CMDAT_INIT)); /* Select 3.2-3.3 and 3.3-3.4V */ + if (resp[0] & 0x80000000) { + mmc_dev.if_type = IF_TYPE_SD; + debug("Detected SD card\n"); + break; + } #ifdef CONFIG_PXA27X udelay(10000); #else - udelay(50); + udelay(200000); #endif - resp = mmc_cmd(1, 0x00ff, 0xff00, MMC_CMDAT_BUSY|MMC_CMDAT_R3); + } + + if (retries <= 0 || !(IF_TYPE_SD == mmc_dev.if_type)) { + debug("Failed to detect SD Card, trying MMC\n"); + resp = + mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, MMC_CMDAT_R3); + + retries = 10; + while (retries-- && resp && !(resp[0] & 0x80000000)) { +#ifdef CONFIG_PXA27X + udelay(10000); +#else + udelay(200000); +#endif + resp = + mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, + MMC_CMDAT_R3); + } } /* try to get card id */ - resp = mmc_cmd(2, 0, 0, MMC_CMDAT_R2); + resp = + mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, 0, MMC_CMDAT_R2 | MMC_CMDAT_BUSY); if (resp) { - /* TODO configure mmc driver depending on card attributes */ - mmc_cid_t *cid = (mmc_cid_t *)resp; - if (verbose) { - printf("MMC found. Card desciption is:\n"); - printf("Manufacturer ID = %02x%02x%02x\n", - cid->id[0], cid->id[1], cid->id[2]); - printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev); - cid->hwrev = cid->fwrev = 0; /* null terminate string */ - printf("Product Name = %s\n",cid->name); - printf("Serial Number = %02x%02x%02x\n", - cid->sn[0], cid->sn[1], cid->sn[2]); - printf("Month = %d\n",cid->month); - printf("Year = %d\n",1997 + cid->year); - } - /* fill in device description */ - mmc_dev.if_type = IF_TYPE_MMC; - mmc_dev.part_type = PART_TYPE_DOS; - mmc_dev.dev = 0; - mmc_dev.lun = 0; - mmc_dev.type = 0; - /* FIXME fill in the correct size (is set to 32MByte) */ - mmc_dev.blksz = 512; - mmc_dev.lba = 0x10000; - sprintf((char*)mmc_dev.vendor,"Man %02x%02x%02x Snr %02x%02x%02x", - cid->id[0], cid->id[1], cid->id[2], - cid->sn[0], cid->sn[1], cid->sn[2]); - sprintf((char*)mmc_dev.product,"%s",cid->name); - sprintf((char*)mmc_dev.revision,"%x %x",cid->hwrev, cid->fwrev); - mmc_dev.removable = 0; - mmc_dev.block_read = mmc_bread; + memcpy(cid_resp, resp, sizeof(cid_resp)); /* MMC exists, get CSD too */ - resp = mmc_cmd(MMC_CMD_SET_RCA, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R1); - resp = mmc_cmd(MMC_CMD_SEND_CSD, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R2); + resp = mmc_cmd(MMC_CMD_SET_RCA, 0, 0, MMC_CMDAT_R1); + if (IF_TYPE_SD == mmc_dev.if_type) + rca = ((resp[0] & 0xffff0000) >> 16); + resp = mmc_cmd(MMC_CMD_SEND_CSD, rca, 0, MMC_CMDAT_R2); if (resp) { - mmc_csd_t *csd = (mmc_csd_t *)resp; - memcpy(&mmc_csd, csd, sizeof(csd)); + mmc_decode_csd(resp); rc = 0; mmc_ready = 1; - /* FIXME add verbose printout for csd */ } + + mmc_decode_cid(cid_resp); } + MMC_CLKRT = 0; /* 20 MHz */ + resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca, 0, MMC_CMDAT_R1); + #ifdef CONFIG_PXA27X - MMC_CLKRT = 1; /* 10 MHz - see Intel errata */ -#else - MMC_CLKRT = 0; /* 20 MHz */ + if (IF_TYPE_SD == mmc_dev.if_type) { + resp = mmc_cmd(MMC_CMD_APP_CMD, rca, 0, MMC_CMDAT_R1); + resp = mmc_cmd(SD_CMD_APP_SET_BUS_WIDTH, 0, 2, MMC_CMDAT_R1); + wide = MMC_CMDAT_SD_4DAT; + } #endif - resp = mmc_cmd(7, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R1); - fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */ + fat_register_device(&mmc_dev, 1); /* partitions start counting with 1 */ return rc; } -int -mmc_ident(block_dev_desc_t *dev) +int mmc_ident(block_dev_desc_t * dev) { return 0; } -int -mmc2info(ulong addr) +int mmc2info(ulong addr) { - /* FIXME hard codes to 32 MB device */ - if (addr >= CFG_MMC_BASE && addr < CFG_MMC_BASE + 0x02000000) { + if (addr >= CFG_MMC_BASE + && addr < CFG_MMC_BASE + (mmc_dev.lba * mmc_dev.blksz)) { return 1; } return 0; } -#endif /* CONFIG_MMC */ +#endif /* CONFIG_MMC */ -- cgit From be19bd5cd0f454b63298844a0b5377e029b2caad Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 Dec 2007 14:19:38 +0100 Subject: ARM: arm920/s3c24xx: IRQ demulitplexer callback This patch adds a IRQ demultiplexer callback to the arm920 cpu core code, plus a stub implementation of it for the S3C2410. The purpose is to allow arm920t implementations such as the s3c24x0 to implement interrupt handlers in u-boot without having to touch core arm920t code. Signed-off-by: Harald Welte --- cpu/arm920t/interrupts.c | 7 ++++++- cpu/arm920t/s3c24x0/interrupts.c | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'cpu') diff --git a/cpu/arm920t/interrupts.c b/cpu/arm920t/interrupts.c index a43a3ed4fe..0a6d94f74f 100644 --- a/cpu/arm920t/interrupts.c +++ b/cpu/arm920t/interrupts.c @@ -161,11 +161,16 @@ void do_fiq (struct pt_regs *pt_regs) void do_irq (struct pt_regs *pt_regs) { -#if defined (CONFIG_USE_IRQ) && defined (CONFIG_ARCH_INTEGRATOR) +#if defined (CONFIG_USE_IRQ) +#if defined (ARM920_IRQ_CALLBACK) + ARM920_IRQ_CALLBACK(); + return; +#elif defined (CONFIG_ARCH_INTEGRATOR) /* ASSUMED to be a timer interrupt */ /* Just clear it - count handled in */ /* integratorap.c */ *(volatile ulong *)(CFG_TIMERBASE + 0x0C) = 0; +#endif /* ARCH_INTEGRATOR */ #else printf ("interrupt request\n"); show_regs (pt_regs); diff --git a/cpu/arm920t/s3c24x0/interrupts.c b/cpu/arm920t/s3c24x0/interrupts.c index 1b364123dc..7ad9fcbd5b 100644 --- a/cpu/arm920t/s3c24x0/interrupts.c +++ b/cpu/arm920t/s3c24x0/interrupts.c @@ -216,4 +216,13 @@ void reset_cpu (ulong ignored) /*NOTREACHED*/ } +#ifdef CONFIG_USE_IRQ +void s3c2410_irq(void) +{ + S3C24X0_INTERRUPT * irq = S3C24X0_GetBase_INTERRUPT(); + u_int32_t intpnd = irq->INTPND; + +} +#endif /* USE_IRQ */ + #endif /* defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) */ -- cgit From a25f72f1f73a11de68251fb88c89991e202e68fa Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 Dec 2007 14:16:57 +0100 Subject: ARM: arm920t: Allow use of 'gd' pointer from IRQ This patch allows us to use the 'gd' pointer (and thus environment and everything else associated with it) from interrupt context on arm920t. Signed-off-by: Harald Welte --- cpu/arm920t/start.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'cpu') diff --git a/cpu/arm920t/start.S b/cpu/arm920t/start.S index aefcdd1552..ae86002a8f 100644 --- a/cpu/arm920t/start.S +++ b/cpu/arm920t/start.S @@ -329,12 +329,12 @@ cpu_init_crit: .macro irq_save_user_regs sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ Calling r0-r12 - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ @ Calling SP, LR - str lr, [r8, #0] @ Save calling PC + add r7, sp, #S_PC + stmdb r7, {sp, lr}^ @ Calling SP, LR + str lr, [r7, #0] @ Save calling PC mrs r6, spsr - str r6, [r8, #4] @ Save CPSR - str r0, [r8, #8] @ Save OLD_R0 + str r6, [r7, #4] @ Save CPSR + str r0, [r7, #8] @ Save OLD_R0 mov r0, sp .endm -- cgit From a7c185ed3d9f8ebd85cfc286e1ffee72e4803163 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 Dec 2007 14:24:40 +0100 Subject: ARM: s3c24xx: Multiple serial port support This patch adds support for CONFIG_SERIAL_MULTI on s3c24x0 CPU's Signed-off-by: Harald Welte --- cpu/arm920t/s3c24x0/serial.c | 164 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 143 insertions(+), 21 deletions(-) (limited to 'cpu') diff --git a/cpu/arm920t/s3c24x0/serial.c b/cpu/arm920t/s3c24x0/serial.c index 36851ad5ca..6e853b87ac 100644 --- a/cpu/arm920t/s3c24x0/serial.c +++ b/cpu/arm920t/s3c24x0/serial.c @@ -48,18 +48,74 @@ DECLARE_GLOBAL_DATA_PTR; #error "Bad: you didn't configure serial ..." #endif -void serial_setbrg (void) +#if defined(CONFIG_SERIAL_MULTI) +#include + +/* Multi serial device functions */ +#define DECLARE_S3C_SERIAL_FUNCTIONS(port) \ + int s3serial##port##_init (void) {\ + return serial_init_dev(port);}\ + void s3serial##port##_setbrg (void) {\ + serial_setbrg_dev(port);}\ + int s3serial##port##_getc (void) {\ + return serial_getc_dev(port);}\ + int s3serial##port##_tstc (void) {\ + return serial_tstc_dev(port);}\ + void s3serial##port##_putc (const char c) {\ + serial_putc_dev(port, c);}\ + void s3serial##port##_puts (const char *s) {\ + serial_puts_dev(port, s);} + +#define INIT_S3C_SERIAL_STRUCTURE(port,name,bus) {\ + name,\ + bus,\ + s3serial##port##_init,\ + s3serial##port##_setbrg,\ + s3serial##port##_getc,\ + s3serial##port##_tstc,\ + s3serial##port##_putc,\ + s3serial##port##_puts, } + +#endif /* CONFIG_SERIAL_MULTI */ + +void _serial_setbrg(const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); - int i; + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); unsigned int reg = 0; + int i; /* value is calculated so : (int)(PCLK/16./baudrate) -1 */ reg = get_PCLK() / (16 * gd->baudrate) - 1; + uart->UBRDIV = reg; + for (i = 0; i < 100; i++); +} +#if defined(CONFIG_SERIAL_MULTI) +static inline void +serial_setbrg_dev(unsigned int dev_index) +{ + _serial_setbrg(dev_index); +} +#else +void serial_setbrg(void) +{ + _serial_setbrg(UART_NR); +} +#endif + + +/* Initialise the serial port. The settings are always 8 data bits, no parity, + * 1 stop bit, no start bits. + */ +static int serial_init_dev(const int dev_index) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); + int i; + /* FIFO enable, Tx/Rx FIFO clear */ uart->UFCON = 0x07; uart->UMCON = 0x0; + /* Normal,No parity,1 stop,8 bit */ uart->ULCON = 0x3; /* @@ -67,40 +123,57 @@ void serial_setbrg (void) * normal,interrupt or polling */ uart->UCON = 0x245; - uart->UBRDIV = reg; #ifdef CONFIG_HWFLOW uart->UMCON = 0x1; /* RTS up */ #endif - for (i = 0; i < 100; i++); + + /* FIXME: This is sooooooooooooooooooo ugly */ +#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2) + /* we need auto hw flow control on the gsm and gps port */ + if (dev_index == 0 || dev_index == 1) + uart->UMCON = 0x10; +#endif + _serial_setbrg(dev_index); + + return (0); } -/* - * Initialise the serial port with the given baudrate. The settings - * are always 8 data bits, no parity, 1 stop bit, no start bits. - * +#if !defined(CONFIG_SERIAL_MULTI) +/* Initialise the serial port. The settings are always 8 data bits, no parity, + * 1 stop bit, no start bits. */ int serial_init (void) { - serial_setbrg (); - - return (0); + return serial_init_dev(UART_NR); } +#endif /* * Read a single byte from the serial port. Returns 1 on success, 0 * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc (void) +int _serial_getc (const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); /* wait for character to arrive */ while (!(uart->UTRSTAT & 0x1)); return uart->URXH & 0xff; } +#if defined(CONFIG_SERIAL_MULTI) +static inline int serial_getc_dev(unsigned int dev_index) +{ + return _serial_getc(dev_index); +} +#else +int serial_getc (void) +{ + return _serial_getc(UART_NR); +} +#endif #ifdef CONFIG_HWFLOW static int hwflow = 0; /* turned off by default */ @@ -138,9 +211,9 @@ void enable_putc(void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +void _serial_putc (const char c, const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); #ifdef CONFIG_MODEM_SUPPORT if (be_quiet) return; @@ -161,23 +234,72 @@ void serial_putc (const char c) if (c == '\n') serial_putc ('\r'); } +#if defined(CONFIG_SERIAL_MULTI) +static inline void serial_putc_dev(unsigned int dev_index, const char c) +{ + _serial_putc(c, dev_index); +} +#else +void serial_putc(const char c) +{ + _serial_putc(c, UART_NR); +} +#endif + /* * Test whether a character is in the RX buffer */ -int serial_tstc (void) +int _serial_tstc(const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); return uart->UTRSTAT & 0x1; } +#if defined(CONFIG_SERIAL_MULTI) +static inline int +serial_tstc_dev(unsigned int dev_index) +{ + return _serial_tstc(dev_index); +} +#else +int serial_tstc(void) +{ + return _serial_tstc(UART_NR); +} +#endif -void -serial_puts (const char *s) +void _serial_puts(const char *s, const int dev_index) { while (*s) { - serial_putc (*s++); + _serial_putc (*s++, dev_index); } } +#if defined(CONFIG_SERIAL_MULTI) +static inline void +serial_puts_dev(int dev_index, const char *s) +{ + _serial_puts(s, dev_index); +} +#else +void +serial_puts (const char *s) +{ + _serial_puts(s, UART_NR); +} +#endif + +#if defined(CONFIG_SERIAL_MULTI) +DECLARE_S3C_SERIAL_FUNCTIONS(0); +struct serial_device s3c24xx_serial0_device = + INIT_S3C_SERIAL_STRUCTURE(0, "s3ser0", "S3UART1"); +DECLARE_S3C_SERIAL_FUNCTIONS(1); +struct serial_device s3c24xx_serial1_device = + INIT_S3C_SERIAL_STRUCTURE(1, "s3ser1", "S3UART2"); +DECLARE_S3C_SERIAL_FUNCTIONS(2); +struct serial_device s3c24xx_serial2_device = + INIT_S3C_SERIAL_STRUCTURE(2, "s3ser2", "S3UART3"); + +#endif /* CONFIG_SERIAL_MULTI */ #endif /* defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) */ -- cgit From 16158778b5f52f201e95ded2d2d9084b0ed5670d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 Dec 2007 15:10:52 +0100 Subject: ARM: S3C24x0 SoC NAND controller support This patch adds NAND support to the S3C24x0 SoC code in u-boot Signed-off-by: Harald Welte --- cpu/arm920t/s3c24x0/Makefile | 2 +- cpu/arm920t/s3c24x0/nand.c | 179 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 cpu/arm920t/s3c24x0/nand.c (limited to 'cpu') diff --git a/cpu/arm920t/s3c24x0/Makefile b/cpu/arm920t/s3c24x0/Makefile index 1ed9bf307c..676492025a 100644 --- a/cpu/arm920t/s3c24x0/Makefile +++ b/cpu/arm920t/s3c24x0/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).a COBJS = i2c.o interrupts.o serial.o speed.o \ - usb.o usb_ohci.o + usb.o usb_ohci.o nand.o SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/arm920t/s3c24x0/nand.c b/cpu/arm920t/s3c24x0/nand.c new file mode 100644 index 0000000000..e1bf128157 --- /dev/null +++ b/cpu/arm920t/s3c24x0/nand.c @@ -0,0 +1,179 @@ +/* + * (C) Copyright 2006 OpenMoko, Inc. + * Author: Harald Welte + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#if 0 +#define DEBUGN printf +#else +#define DEBUGN(x, args ...) {} +#endif + +#if defined(CONFIG_CMD_NAND) +#if !defined(CFG_NAND_LEGACY) + +#include +#include + +#define __REGb(x) (*(volatile unsigned char *)(x)) +#define __REGi(x) (*(volatile unsigned int *)(x)) + +#define NF_BASE 0x4e000000 +#define NFCONF __REGi(NF_BASE + 0x0) +#define NFCMD __REGb(NF_BASE + 0x4) +#define NFADDR __REGb(NF_BASE + 0x8) +#define NFDATA __REGb(NF_BASE + 0xc) +#define NFSTAT __REGb(NF_BASE + 0x10) +#define NFECC0 __REGb(NF_BASE + 0x14) +#define NFECC1 __REGb(NF_BASE + 0x15) +#define NFECC2 __REGb(NF_BASE + 0x16) + +#define S3C2410_NFCONF_EN (1<<15) +#define S3C2410_NFCONF_512BYTE (1<<14) +#define S3C2410_NFCONF_4STEP (1<<13) +#define S3C2410_NFCONF_INITECC (1<<12) +#define S3C2410_NFCONF_nFCE (1<<11) +#define S3C2410_NFCONF_TACLS(x) ((x)<<8) +#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) +#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) + +static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *chip = mtd->priv; + + DEBUGN("hwcontrol(): 0x%02x: ", cmd); + + switch (cmd) { + case NAND_CTL_SETNCE: + NFCONF &= ~S3C2410_NFCONF_nFCE; + DEBUGN("NFCONF=0x%08x\n", NFCONF); + break; + case NAND_CTL_CLRNCE: + NFCONF |= S3C2410_NFCONF_nFCE; + DEBUGN("NFCONF=0x%08x\n", NFCONF); + break; + case NAND_CTL_SETALE: + chip->IO_ADDR_W = NF_BASE + 0x8; + DEBUGN("SETALE\n"); + break; + case NAND_CTL_SETCLE: + chip->IO_ADDR_W = NF_BASE + 0x4; + DEBUGN("SETCLE\n"); + break; + default: + chip->IO_ADDR_W = NF_BASE + 0xc; + break; + } + return; +} + +static int s3c2410_dev_ready(struct mtd_info *mtd) +{ + DEBUGN("dev_ready\n"); + return (NFSTAT & 0x01); +} + +#ifdef CONFIG_S3C2410_NAND_HWECC +void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd ,mode); + NFCONF |= S3C2410_NFCONF_INITECC; +} + +static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + ecc_code[0] = NFECC0; + ecc_code[1] = NFECC1; + ecc_code[2] = NFECC2; + DEBUGN("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n", + mtd , ecc_code[0], ecc_code[1], ecc_code[2]); + + return 0; +} + +static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + if (read_ecc[0] == calc_ecc[0] && + read_ecc[1] == calc_ecc[1] && + read_ecc[2] == calc_ecc[2]) + return 0; + + printf("s3c2410_nand_correct_data: not implemented\n"); + return -1; +} +#endif + +int board_nand_init(struct nand_chip *nand) +{ + u_int32_t cfg; + u_int8_t tacls, twrph0, twrph1; + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + + DEBUGN("board_nand_init()\n"); + + clk_power->CLKCON |= (1 << 4); + + /* initialize hardware */ + twrph0 = 3; twrph1 = 0; tacls = 0; + + cfg = S3C2410_NFCONF_EN; + cfg |= S3C2410_NFCONF_TACLS(tacls - 1); + cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); + cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); + + NFCONF = cfg; + + /* initialize nand_chip data structure */ + nand->IO_ADDR_R = nand->IO_ADDR_W = 0x4e00000c; + + /* read_buf and write_buf are default */ + /* read_byte and write_byte are default */ + + /* hwcontrol always must be implemented */ + nand->hwcontrol = s3c2410_hwcontrol; + + nand->dev_ready = s3c2410_dev_ready; + +#ifdef CONFIG_S3C2410_NAND_HWECC + nand->enable_hwecc = s3c2410_nand_enable_hwecc; + nand->calculate_ecc = s3c2410_nand_calculate_ecc; + nand->correct_data = s3c2410_nand_correct_data; + nand->eccmode = NAND_ECC_HW3_512; +#else + nand->eccmode = NAND_ECC_SOFT; +#endif + +#ifdef CONFIG_S3C2410_NAND_BBT + nand->options = NAND_USE_FLASH_BBT; +#else + nand->options = 0; +#endif + + DEBUGN("end of nand_init\n"); + + return 0; +} + +#else + #error "U-Boot legacy NAND support not available for S3C2410" +#endif +#endif -- cgit From ac9152830d7fdebace8a260b7737ef2870c21ca0 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Wed, 30 Jan 2008 13:36:57 -0700 Subject: Device tree updates Changes to match 5121 device tree going mainline in 2.6.25. Change OF_SOC from "soc5121" to plain "soc". Remove unneeded "ref-frequency" fixups. Remove "address" enetaddr fixup. Add bus-frequency fixup for old OF_SOC so old kernels with old device trees will work with new u-boot with 66MHz IPS clock Signed-off-by: John Rigby --- cpu/mpc512x/cpu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'cpu') diff --git a/cpu/mpc512x/cpu.c b/cpu/mpc512x/cpu.c index 6421a511e4..bed77acaa9 100644 --- a/cpu/mpc512x/cpu.c +++ b/cpu/mpc512x/cpu.c @@ -138,11 +138,11 @@ void ft_cpu_setup(void *blob, bd_t *bd) do_fixup_by_path_u32(blob, cpu_path, "timebase-frequency", OF_TBCLK, 1); do_fixup_by_path_u32(blob, cpu_path, "bus-frequency", bd->bi_busfreq, 1); - do_fixup_by_path_u32(blob, cpu_path, "ref-frequency", CFG_MPC512X_CLKIN, 1); do_fixup_by_path_u32(blob, cpu_path, "clock-frequency", bd->bi_intfreq, 1); do_fixup_by_path_u32(blob, "/" OF_SOC, "bus-frequency", bd->bi_ipsfreq, 1); - do_fixup_by_path_u32(blob, "/" OF_SOC, "ref-frequency", CFG_MPC512X_CLKIN, 1); - do_fixup_by_path(blob, eth_path, "address", bd->bi_enetaddr, 6, 0); do_fixup_by_path(blob, eth_path, "local-mac-address", bd->bi_enetaddr, 6, 0); + + /* this is so old kernels with old device trees will boot */ + do_fixup_by_path_u32(blob, "/" OF_SOC_OLD, "bus-frequency", bd->bi_ipsfreq, 0); } #endif -- cgit From 69018ce2e086e9caf35b914d675b82bc4888f077 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 17 Jan 2008 08:25:45 -0600 Subject: QE: Move FDT support into a common file Move the flat device tree setup for QE related devices into a common file shared between 83xx & 85xx platforms that have QE's. Signed-off-by: Kumar Gala --- cpu/mpc83xx/fdt.c | 13 +++---------- cpu/mpc85xx/fdt.c | 8 +++----- 2 files changed, 6 insertions(+), 15 deletions(-) (limited to 'cpu') diff --git a/cpu/mpc83xx/fdt.c b/cpu/mpc83xx/fdt.c index 909171fd4f..6f55932da2 100644 --- a/cpu/mpc83xx/fdt.c +++ b/cpu/mpc83xx/fdt.c @@ -30,6 +30,8 @@ #include #include +extern void ft_qe_setup(void *blob); + DECLARE_GLOBAL_DATA_PTR; void ft_cpu_setup(void *blob, bd_t *bd) @@ -48,16 +50,7 @@ void ft_cpu_setup(void *blob, bd_t *bd) do_fixup_by_prop_u32(blob, "device_type", "soc", 4, "bus-frequency", bd->bi_busfreq, 1); #ifdef CONFIG_QE - do_fixup_by_prop_u32(blob, "device_type", "qe", 4, - "bus-frequency", gd->qe_clk, 1); - do_fixup_by_prop_u32(blob, "device_type", "qe", 4, - "brg-frequency", gd->brg_clk, 1); - do_fixup_by_compat_u32(blob, "fsl,qe", - "clock-frequency", gd->qe_clk, 1); - do_fixup_by_compat_u32(blob, "fsl,qe", - "bus-frequency", gd->qe_clk, 1); - do_fixup_by_compat_u32(blob, "fsl,qe", - "brg-frequency", gd->brg_clk, 1); + ft_qe_setup(blob); #endif #ifdef CFG_NS16550 diff --git a/cpu/mpc85xx/fdt.c b/cpu/mpc85xx/fdt.c index 0ce17e7f57..a6b014cec0 100644 --- a/cpu/mpc85xx/fdt.c +++ b/cpu/mpc85xx/fdt.c @@ -27,6 +27,8 @@ #include #include +extern void ft_qe_setup(void *blob); + void ft_cpu_setup(void *blob, bd_t *bd) { #if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\ @@ -43,11 +45,7 @@ void ft_cpu_setup(void *blob, bd_t *bd) do_fixup_by_prop_u32(blob, "device_type", "soc", 4, "bus-frequency", bd->bi_busfreq, 1); #ifdef CONFIG_QE - do_fixup_by_prop_u32(blob, "device_type", "qe", 4, - "bus-frequency", bd->bi_busfreq, 1); - do_fixup_by_prop_u32(blob, "device_type", "qe", 4, - "brg-frequency", bd->bi_busfreq / 2, 1); - fdt_fixup_qe_firmware(blob); + ft_qe_setup(blob); #endif #ifdef CFG_NS16550 -- cgit