diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/s3c24x0_i2c.c | 273 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c2410_nand.c | 62 | ||||
-rw-r--r-- | drivers/mtd/onenand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/onenand/samsung.c | 636 | ||||
-rw-r--r-- | drivers/net/smc911x.c | 12 | ||||
-rw-r--r-- | drivers/rtc/s3c24x0_rtc.c | 130 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/serial_s3c24x0.c | 160 | ||||
-rw-r--r-- | drivers/serial/serial_s5pc1xx.c | 195 |
9 files changed, 1160 insertions, 310 deletions
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index f0c1aa3..55c6a12 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -32,6 +32,8 @@ #elif defined(CONFIG_S3C2410) #include <s3c2410.h> #endif + +#include <asm/io.h> #include <i2c.h> #ifdef CONFIG_HARD_I2C @@ -42,142 +44,139 @@ #define I2C_OK 0 #define I2C_NOK 1 #define I2C_NACK 2 -#define I2C_NOK_LA 3 /* Lost arbitration */ -#define I2C_NOK_TOUT 4 /* time out */ - -#define I2CSTAT_BSY 0x20 /* Busy bit */ -#define I2CSTAT_NACK 0x01 /* Nack bit */ -#define I2CCON_IRPND 0x10 /* Interrupt pending bit */ -#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */ -#define I2C_MODE_MR 0x80 /* Master Receive Mode */ -#define I2C_START_STOP 0x20 /* START / STOP */ -#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */ +#define I2C_NOK_LA 3 /* Lost arbitration */ +#define I2C_NOK_TOUT 4 /* time out */ -#define I2C_TIMEOUT 1 /* 1 second */ +#define I2CSTAT_BSY 0x20 /* Busy bit */ +#define I2CSTAT_NACK 0x01 /* Nack bit */ +#define I2CCON_IRPND 0x10 /* Interrupt pending bit */ +#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */ +#define I2C_MODE_MR 0x80 /* Master Receive Mode */ +#define I2C_START_STOP 0x20 /* START / STOP */ +#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */ +#define I2C_TIMEOUT 1 /* 1 second */ static int GetI2CSDA(void) { - S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #ifdef CONFIG_S3C2410 - return (gpio->GPEDAT & 0x8000) >> 15; + return (readl(&gpio->GPEDAT) & 0x8000) >> 15; #endif #ifdef CONFIG_S3C2400 - return (gpio->PGDAT & 0x0020) >> 5; + return (readl(&gpio->PGDAT) & 0x0020) >> 5; #endif } #if 0 static void SetI2CSDA(int x) { - rGPEDAT = (rGPEDAT & ~0x8000) | (x&1) << 15; + rGPEDAT = (rGPEDAT & ~0x8000) | (x & 1) << 15; } #endif static void SetI2CSCL(int x) { - S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #ifdef CONFIG_S3C2410 - gpio->GPEDAT = (gpio->GPEDAT & ~0x4000) | (x&1) << 14; + writel((readl(&gpio->GPEDAT) & ~0x4000) | (x & 1) << 14, &gpio->GPEDAT); #endif #ifdef CONFIG_S3C2400 - gpio->PGDAT = (gpio->PGDAT & ~0x0040) | (x&1) << 6; + writel((readl(&gpio->PGDAT) & ~0x0040) | (x & 1) << 6, &gpio->PGDAT); #endif } - -static int WaitForXfer (void) +static int WaitForXfer(void) { - S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); - int i, status; + struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); + int i; i = I2C_TIMEOUT * 10000; - status = i2c->IICCON; - while ((i > 0) && !(status & I2CCON_IRPND)) { - udelay (100); - status = i2c->IICCON; + while (!(readl(&i2c->IICCON) & I2CCON_IRPND) && (i > 0)) { + udelay(100); i--; } - return (status & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; + return (readl(&i2c->IICCON) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; } -static int IsACK (void) +static int IsACK(void) { - S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); + struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); - return (!(i2c->IICSTAT & I2CSTAT_NACK)); + return !(readl(&i2c->IICSTAT) & I2CSTAT_NACK); } -static void ReadWriteByte (void) +static void ReadWriteByte(void) { - S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); + struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); - i2c->IICCON &= ~I2CCON_IRPND; + writel(readl(&i2c->IICCON) & ~I2CCON_IRPND, &i2c->IICCON); } -void i2c_init (int speed, int slaveadd) +void i2c_init(int speed, int slaveadd) { - S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); - S3C24X0_GPIO *const gpio = S3C24X0_GetBase_GPIO (); + struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); + struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); ulong freq, pres = 16, div; - int i, status; + int i; /* wait for some time to give previous transfer a chance to finish */ i = I2C_TIMEOUT * 1000; - status = i2c->IICSTAT; - while ((i > 0) && (status & I2CSTAT_BSY)) { - udelay (1000); - status = i2c->IICSTAT; + while ((readl(&i2c->IICSTAT) && I2CSTAT_BSY) && (i > 0)) { + udelay(1000); i--; } - if ((status & I2CSTAT_BSY) || GetI2CSDA () == 0) { + if ((readl(&i2c->IICSTAT) & I2CSTAT_BSY) || GetI2CSDA() == 0) { #ifdef CONFIG_S3C2410 - ulong old_gpecon = gpio->GPECON; + ulong old_gpecon = readl(&gpio->GPECON); #endif #ifdef CONFIG_S3C2400 - ulong old_gpecon = gpio->PGCON; + ulong old_gpecon = readl(&gpio->PGCON); #endif - /* bus still busy probably by (most) previously interrupted transfer */ + /* bus still busy probably by (most) previously interrupted + transfer */ #ifdef CONFIG_S3C2410 /* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */ - gpio->GPECON = (gpio->GPECON & ~0xF0000000) | 0x10000000; + writel((readl(&gpio->GPECON) & ~0xF0000000) | 0x10000000, + &gpio->GPECON); #endif #ifdef CONFIG_S3C2400 /* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */ - gpio->PGCON = (gpio->PGCON & ~0x00003c00) | 0x00001000; + writel((readl(&gpio->PGCON) & ~0x00003c00) | 0x00001000, + &gpio->PGCON); #endif /* toggle I2CSCL until bus idle */ - SetI2CSCL (0); - udelay (1000); + SetI2CSCL(0); + udelay(1000); i = 10; - while ((i > 0) && (GetI2CSDA () != 1)) { - SetI2CSCL (1); - udelay (1000); - SetI2CSCL (0); - udelay (1000); + while ((i > 0) && (GetI2CSDA() != 1)) { + SetI2CSCL(1); + udelay(1000); + SetI2CSCL(0); + udelay(1000); i--; } - SetI2CSCL (1); - udelay (1000); + SetI2CSCL(1); + udelay(1000); /* restore pin functions */ #ifdef CONFIG_S3C2410 - gpio->GPECON = old_gpecon; + writel(old_gpecon, &gpio->GPECON); #endif #ifdef CONFIG_S3C2400 - gpio->PGCON = old_gpecon; + writel(old_gpecon, &gpio->PGCON); #endif } /* calculate prescaler and divisor values */ - freq = get_PCLK (); + freq = get_PCLK(); if ((freq / pres / (16 + 1)) > speed) /* set prescaler to 512 */ pres = 512; @@ -188,13 +187,13 @@ void i2c_init (int speed, int slaveadd) /* set prescaler, divisor according to freq, also set * ACKGEN, IRQ */ - i2c->IICCON = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0); + writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->IICCON); /* init to SLAVE REVEIVE and set slaveaddr */ - i2c->IICSTAT = 0; - i2c->IICADD = slaveadd; + writel(0, &i2c->IICSTAT); + writel(slaveadd, &i2c->IICADD); /* program Master Transmit (and implicit STOP) */ - i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA; + writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->IICSTAT); } @@ -206,107 +205,109 @@ void i2c_init (int speed, int slaveadd) * 0 we skip the address write cycle. */ static -int i2c_transfer (unsigned char cmd_type, - unsigned char chip, - unsigned char addr[], - unsigned char addr_len, - unsigned char data[], unsigned short data_len) +int i2c_transfer(unsigned char cmd_type, + unsigned char chip, + unsigned char addr[], + unsigned char addr_len, + unsigned char data[], unsigned short data_len) { - S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); - int i, status, result; + struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); + int i, result; if (data == 0 || data_len == 0) { /*Don't support data transfer of no length or to address 0 */ - printf ("i2c_transfer: bad call\n"); + printf("i2c_transfer: bad call\n"); return I2C_NOK; } /* Check I2C bus idle */ i = I2C_TIMEOUT * 1000; - status = i2c->IICSTAT; - while ((i > 0) && (status & I2CSTAT_BSY)) { - udelay (1000); - status = i2c->IICSTAT; + while ((readl(&i2c->IICSTAT) & I2CSTAT_BSY) && (i > 0)) { + udelay(1000); i--; } - if (status & I2CSTAT_BSY) + if (readl(&i2c->IICSTAT) & I2CSTAT_BSY) return I2C_NOK_TOUT; - i2c->IICCON |= 0x80; + writel(readl(&i2c->IICCON) | 0x80, &i2c->IICCON); result = I2C_OK; switch (cmd_type) { case I2C_WRITE: if (addr && addr_len) { - i2c->IICDS = chip; + writel(chip, &i2c->IICDS); /* send START */ - i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP; + writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->IICSTAT); i = 0; while ((i < addr_len) && (result == I2C_OK)) { - result = WaitForXfer (); - i2c->IICDS = addr[i]; - ReadWriteByte (); + result = WaitForXfer(); + writel(addr[i], &i2c->IICDS); + ReadWriteByte(); i++; } i = 0; while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer (); - i2c->IICDS = data[i]; - ReadWriteByte (); + result = WaitForXfer(); + writel(data[i], &i2c->IICDS); + ReadWriteByte(); i++; } } else { - i2c->IICDS = chip; + writel(chip, &i2c->IICDS); /* send START */ - i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP; + writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->IICSTAT); i = 0; while ((i < data_len) && (result = I2C_OK)) { - result = WaitForXfer (); - i2c->IICDS = data[i]; - ReadWriteByte (); + result = WaitForXfer(); + writel(data[i], &i2c->IICDS); + ReadWriteByte(); i++; } } if (result == I2C_OK) - result = WaitForXfer (); + result = WaitForXfer(); /* send STOP */ - i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA; - ReadWriteByte (); + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->IICSTAT); + ReadWriteByte(); break; case I2C_READ: if (addr && addr_len) { - i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA; - i2c->IICDS = chip; + writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->IICSTAT); + writel(chip, &i2c->IICDS); /* send START */ - i2c->IICSTAT |= I2C_START_STOP; - result = WaitForXfer (); - if (IsACK ()) { + writel(readl(&i2c->IICSTAT) | I2C_START_STOP, + &i2c->IICSTAT); + result = WaitForXfer(); + if (IsACK()) { i = 0; while ((i < addr_len) && (result == I2C_OK)) { - i2c->IICDS = addr[i]; - ReadWriteByte (); - result = WaitForXfer (); + writel(addr[i], &i2c->IICDS); + ReadWriteByte(); + result = WaitForXfer(); i++; } - i2c->IICDS = chip; + writel(chip, &i2c->IICDS); /* resend START */ - i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA | - I2C_START_STOP; - ReadWriteByte (); - result = WaitForXfer (); + writel(I2C_MODE_MR | I2C_TXRX_ENA | + I2C_START_STOP, &i2c->IICSTAT); + ReadWriteByte(); + result = WaitForXfer(); i = 0; while ((i < data_len) && (result == I2C_OK)) { /* disable ACK for final READ */ if (i == data_len - 1) - i2c->IICCON &= ~0x80; - ReadWriteByte (); - result = WaitForXfer (); - data[i] = i2c->IICDS; + writel(readl(&i2c->IICCON) + & ~0x80, &i2c->IICCON); + ReadWriteByte(); + result = WaitForXfer(); + data[i] = readl(&i2c->IICDS); i++; } } else { @@ -314,21 +315,23 @@ int i2c_transfer (unsigned char cmd_type, } } else { - i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA; - i2c->IICDS = chip; + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->IICSTAT); + writel(chip, &i2c->IICDS); /* send START */ - i2c->IICSTAT |= I2C_START_STOP; - result = WaitForXfer (); + writel(readl(&i2c->IICSTAT) | I2C_START_STOP, + &i2c->IICSTAT); + result = WaitForXfer(); - if (IsACK ()) { + if (IsACK()) { i = 0; while ((i < data_len) && (result == I2C_OK)) { /* disable ACK for final READ */ if (i == data_len - 1) - i2c->IICCON &= ~0x80; - ReadWriteByte (); - result = WaitForXfer (); - data[i] = i2c->IICDS; + writel(readl(&i2c->IICCON) & + ~0x80, &i2c->IICCON); + ReadWriteByte(); + result = WaitForXfer(); + data[i] = readl(&i2c->IICDS); i++; } } else { @@ -337,12 +340,12 @@ int i2c_transfer (unsigned char cmd_type, } /* send STOP */ - i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA; - ReadWriteByte (); + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->IICSTAT); + ReadWriteByte(); break; default: - printf ("i2c_transfer: bad call\n"); + printf("i2c_transfer: bad call\n"); result = I2C_NOK; break; } @@ -350,7 +353,7 @@ int i2c_transfer (unsigned char cmd_type, return (result); } -int i2c_probe (uchar chip) +int i2c_probe(uchar chip) { uchar buf[1]; @@ -361,16 +364,16 @@ int i2c_probe (uchar chip) * address was <ACK>ed (i.e. there was a chip at that address which * drove the data line low). */ - return (i2c_transfer (I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK); + return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; } -int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { uchar xaddr[4]; int ret; if (alen > 4) { - printf ("I2C read: addr len %d not supported\n", alen); + printf("I2C read: addr len %d not supported\n", alen); return 1; } @@ -394,23 +397,24 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) * hidden in the chip address. */ if (alen > 0) - chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); + chip |= ((addr >> (alen * 8)) & + CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif if ((ret = - i2c_transfer (I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len)) != 0) { - printf ("I2c read: failed %d\n", ret); + i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen, + buffer, len)) != 0) { + printf("I2c read: failed %d\n", ret); return 1; } return 0; } -int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { uchar xaddr[4]; if (alen > 4) { - printf ("I2C write: addr len %d not supported\n", alen); + printf("I2C write: addr len %d not supported\n", alen); return 1; } @@ -433,10 +437,11 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) * hidden in the chip address. */ if (alen > 0) - chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); + chip |= ((addr >> (alen * 8)) & + CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif return (i2c_transfer (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, len) != 0); } -#endif /* CONFIG_HARD_I2C */ +#endif /* CONFIG_HARD_I2C */ diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c index d27a625..f2f3e72 100644 --- a/drivers/mtd/nand/s3c2410_nand.c +++ b/drivers/mtd/nand/s3c2410_nand.c @@ -20,29 +20,10 @@ #include <common.h> -#if 0 -#define DEBUGN printf -#else -#define DEBUGN(x, args ...) {} -#endif - #include <nand.h> #include <s3c2410.h> #include <asm/io.h> -#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) @@ -58,11 +39,12 @@ static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *chip = mtd->priv; + struct s3c2410_nand *nand = s3c2410_get_base_nand(); - DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl); + debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl); if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = NF_BASE; + ulong IO_ADDR_W = (ulong)nand; if (!(ctrl & NAND_CLE)) IO_ADDR_W |= S3C2410_ADDR_NCLE; @@ -72,9 +54,11 @@ static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) chip->IO_ADDR_W = (void *)IO_ADDR_W; if (ctrl & NAND_NCE) - NFCONF &= ~S3C2410_NFCONF_nFCE; + writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, + &nand->NFCONF); else - NFCONF |= S3C2410_NFCONF_nFCE; + writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, + &nand->NFCONF); } if (cmd != NAND_CMD_NONE) @@ -83,15 +67,17 @@ static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) static int s3c2410_dev_ready(struct mtd_info *mtd) { - DEBUGN("dev_ready\n"); - return (NFSTAT & 0x01); + struct s3c2410_nand *nand = s3c2410_get_base_nand(); + debugX(1, "dev_ready\n"); + return readl(&nand->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; + struct s3c2410_nand *nand = s3c2410_get_base_nand(); + debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode); + writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF); } static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, @@ -100,8 +86,8 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, 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]); + debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n", + mtd , ecc_code[0], ecc_code[1], ecc_code[2]); return 0; } @@ -123,24 +109,26 @@ 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(); + struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); + struct s3c2410_nand *nand_reg = s3c2410_get_base_nand(); - DEBUGN("board_nand_init()\n"); + debugX(1, "board_nand_init()\n"); - clk_power->CLKCON |= (1 << 4); + writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON); /* initialize hardware */ - twrph0 = 3; twrph1 = 0; tacls = 0; + 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; + writel(cfg, &nand_reg->NFCONF); /* initialize nand_chip data structure */ - nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c; + nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ @@ -165,7 +153,7 @@ int board_nand_init(struct nand_chip *nand) nand->options = 0; #endif - DEBUGN("end of nand_init\n"); + debugX(1, "end of nand_init\n"); return 0; } diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index 1d35a57..2571df0 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libonenand.a COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o +COBJS-$(CONFIG_SAMSUNG_ONENAND) += samsung.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c new file mode 100644 index 0000000..f2be687 --- /dev/null +++ b/drivers/mtd/onenand/samsung.c @@ -0,0 +1,636 @@ +/* + * S3C64XX/S5PC100 OneNAND driver at U-Boot + * + * Copyright (C) 2008-2009 Samsung Electronics + * Kyungmin Park <kyungmin.park@samsung.com> + * + * Implementation: + * Emulate the pseudo BufferRAM + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <malloc.h> +#include <linux/mtd/compat.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/onenand.h> +#include <linux/mtd/samsung_onenand.h> + +#include <asm/io.h> +#include <asm/errno.h> + +#ifdef ONENAND_DEBUG +#define DPRINTK(format, args...) \ +do { \ + printf("%s[%d]: " format "\n", __func__, __LINE__, ##args); \ +} while (0) +#else +#define DPRINTK(...) do { } while (0) +#endif + +#define ONENAND_ERASE_STATUS 0x00 +#define ONENAND_MULTI_ERASE_SET 0x01 +#define ONENAND_ERASE_START 0x03 +#define ONENAND_UNLOCK_START 0x08 +#define ONENAND_UNLOCK_END 0x09 +#define ONENAND_LOCK_START 0x0A +#define ONENAND_LOCK_END 0x0B +#define ONENAND_LOCK_TIGHT_START 0x0C +#define ONENAND_LOCK_TIGHT_END 0x0D +#define ONENAND_UNLOCK_ALL 0x0E +#define ONENAND_OTP_ACCESS 0x12 +#define ONENAND_SPARE_ACCESS_ONLY 0x13 +#define ONENAND_MAIN_ACCESS_ONLY 0x14 +#define ONENAND_ERASE_VERIFY 0x15 +#define ONENAND_MAIN_SPARE_ACCESS 0x16 +#define ONENAND_PIPELINE_READ 0x4000 + +#if defined(CONFIG_S3C64XX) +#define MAP_00 (0x0 << 24) +#define MAP_01 (0x1 << 24) +#define MAP_10 (0x2 << 24) +#define MAP_11 (0x3 << 24) +#elif defined(CONFIG_S5PC1XX) +#define MAP_00 (0x0 << 26) +#define MAP_01 (0x1 << 26) +#define MAP_10 (0x2 << 26) +#define MAP_11 (0x3 << 26) +#endif + +/* read/write of XIP buffer */ +#define CMD_MAP_00(mem_addr) (MAP_00 | ((mem_addr) << 1)) +/* read/write to the memory device */ +#define CMD_MAP_01(mem_addr) (MAP_01 | (mem_addr)) +/* control special functions of the memory device */ +#define CMD_MAP_10(mem_addr) (MAP_10 | (mem_addr)) +/* direct interface(direct access) with the memory device */ +#define CMD_MAP_11(mem_addr) (MAP_11 | ((mem_addr) << 2)) + +struct s3c_onenand { + struct mtd_info *mtd; + void __iomem *base; + void __iomem *ahb_addr; + int bootram_command; + void __iomem *page_buf; + void __iomem *oob_buf; + unsigned int (*mem_addr)(int fba, int fpa, int fsa); + struct samsung_onenand *reg; +}; + +static struct s3c_onenand *onenand; + +static int s3c_read_cmd(unsigned int cmd) +{ + return readl(onenand->ahb_addr + cmd); +} + +static void s3c_write_cmd(int value, unsigned int cmd) +{ + writel(value, onenand->ahb_addr + cmd); +} + +/* + * MEM_ADDR + * + * fba: flash block address + * fpa: flash page address + * fsa: flash sector address + * + * return the buffer address on the memory device + * It will be combined with CMD_MAP_XX + */ +#if defined(CONFIG_S3C64XX) +static unsigned int s3c_mem_addr(int fba, int fpa, int fsa) +{ + return (fba << 12) | (fpa << 6) | (fsa << 4); +} +#elif defined(CONFIG_S5PC1XX) +static unsigned int s3c_mem_addr(int fba, int fpa, int fsa) +{ + return (fba << 13) | (fpa << 7) | (fsa << 5); +} +#endif + +static void s3c_onenand_reset(void) +{ + unsigned long timeout = 0x10000; + int stat; + + writel(ONENAND_MEM_RESET_COLD, &onenand->reg->mem_reset); + while (timeout--) { + stat = readl(&onenand->reg->int_err_stat); + if (stat & RST_CMP) + break; + } + stat = readl(&onenand->reg->int_err_stat); + writel(stat, &onenand->reg->int_err_ack); + + /* Clear interrupt */ + writel(0x0, &onenand->reg->int_err_ack); + /* Clear the ECC status */ + writel(0x0, &onenand->reg->ecc_err_stat); +} + +static unsigned short s3c_onenand_readw(void __iomem *addr) +{ + struct onenand_chip *this = onenand->mtd->priv; + int reg = addr - this->base; + int word_addr = reg >> 1; + int value; + + /* It's used for probing time */ + switch (reg) { + case ONENAND_REG_MANUFACTURER_ID: + return readl(&onenand->reg->manufact_id); + case ONENAND_REG_DEVICE_ID: + return readl(&onenand->reg->device_id); + case ONENAND_REG_VERSION_ID: + return readl(&onenand->reg->flash_ver_id); + case ONENAND_REG_DATA_BUFFER_SIZE: + return readl(&onenand->reg->data_buf_size); + case ONENAND_REG_TECHNOLOGY: + return readl(&onenand->reg->tech); + case ONENAND_REG_SYS_CFG1: + return readl(&onenand->reg->mem_cfg); + + /* Used at unlock all status */ + case ONENAND_REG_CTRL_STATUS: + return 0; + + case ONENAND_REG_WP_STATUS: + return ONENAND_WP_US; + + default: + break; + } + + /* BootRAM access control */ + if (reg < ONENAND_DATARAM && onenand->bootram_command) { + if (word_addr == 0) + return readl(&onenand->reg->manufact_id); + if (word_addr == 1) + return readl(&onenand->reg->device_id); + if (word_addr == 2) + return readl(&onenand->reg->flash_ver_id); + } + + value = s3c_read_cmd(CMD_MAP_11(word_addr)) & 0xffff; + printk(KERN_INFO "s3c_onenand_readw: Illegal access" + " at reg 0x%x, value 0x%x\n", word_addr, value); + return value; +} + +static void s3c_onenand_writew(unsigned short value, void __iomem *addr) +{ + struct onenand_chip *this = onenand->mtd->priv; + int reg = addr - this->base; + int word_addr = reg >> 1; + + /* It's used for probing time */ + switch (reg) { + case ONENAND_REG_SYS_CFG1: + writel(value, &onenand->reg->mem_cfg); + return; + + case ONENAND_REG_START_ADDRESS1: + case ONENAND_REG_START_ADDRESS2: + return; + + /* Lock/lock-tight/unlock/unlock_all */ + case ONENAND_REG_START_BLOCK_ADDRESS: + return; + + default: + break; + } + + /* BootRAM access control */ + if (reg < ONENAND_DATARAM) { + if (value == ONENAND_CMD_READID) { + onenand->bootram_command = 1; + return; + } + if (value == ONENAND_CMD_RESET) { + writel(ONENAND_MEM_RESET_COLD, + &onenand->reg->mem_reset); + onenand->bootram_command = 0; + return; + } + } + + printk(KERN_INFO "s3c_onenand_writew: Illegal access" + " at reg 0x%x, value 0x%x\n", word_addr, value); + + s3c_write_cmd(value, CMD_MAP_11(word_addr)); +} + +static int s3c_onenand_wait(struct mtd_info *mtd, int state) +{ + unsigned int flags = INT_ACT; + unsigned int stat, ecc; + unsigned long timeout = 0x100000; + + switch (state) { + case FL_READING: + flags |= BLK_RW_CMP | LOAD_CMP; + break; + case FL_WRITING: + flags |= BLK_RW_CMP | PGM_CMP; + break; + case FL_ERASING: + flags |= BLK_RW_CMP | ERS_CMP; + break; + case FL_LOCKING: + flags |= BLK_RW_CMP; + break; + default: + break; + } + + while (timeout--) { + stat = readl(&onenand->reg->int_err_stat); + if (stat & flags) + break; + } + + /* To get correct interrupt status in timeout case */ + stat = readl(&onenand->reg->int_err_stat); + writel(stat, &onenand->reg->int_err_ack); + + /* + * In the Spec. it checks the controller status first + * However if you get the correct information in case of + * power off recovery (POR) test, it should read ECC status first + */ + if (stat & LOAD_CMP) { + ecc = readl(&onenand->reg->ecc_err_stat); + if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) { + printk(KERN_INFO "%s: ECC error = 0x%04x\n", + __func__, ecc); + mtd->ecc_stats.failed++; + return -EBADMSG; + } + } + + if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) { + printk(KERN_INFO "%s: controller error = 0x%04x\n", + __func__, stat); + if (stat & LOCKED_BLK) + printk(KERN_INFO "%s: it's locked error = 0x%04x\n", + __func__, stat); + + return -EIO; + } + + return 0; +} + +static int s3c_onenand_command(struct mtd_info *mtd, int cmd, + loff_t addr, size_t len) +{ + struct onenand_chip *this = mtd->priv; + unsigned int *m, *s; + int fba, fpa, fsa = 0; + unsigned int mem_addr; + int i, mcount, scount; + int index; + + fba = (int) (addr >> this->erase_shift); + fpa = (int) (addr >> this->page_shift); + fpa &= this->page_mask; + + mem_addr = onenand->mem_addr(fba, fpa, fsa); + + switch (cmd) { + case ONENAND_CMD_READ: + case ONENAND_CMD_READOOB: + case ONENAND_CMD_BUFFERRAM: + ONENAND_SET_NEXT_BUFFERRAM(this); + default: + break; + } + + index = ONENAND_CURRENT_BUFFERRAM(this); + + /* + * Emulate Two BufferRAMs and access with 4 bytes pointer + */ + m = (unsigned int *) onenand->page_buf; + s = (unsigned int *) onenand->oob_buf; + + if (index) { + m += (this->writesize >> 2); + s += (mtd->oobsize >> 2); + } + + mcount = mtd->writesize >> 2; + scount = mtd->oobsize >> 2; + + switch (cmd) { + case ONENAND_CMD_READ: + /* Main */ + for (i = 0; i < mcount; i++) + *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr)); + return 0; + + case ONENAND_CMD_READOOB: + writel(TSRF, &onenand->reg->trans_spare); + /* Main */ + for (i = 0; i < mcount; i++) + *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr)); + + /* Spare */ + for (i = 0; i < scount; i++) + *s++ = s3c_read_cmd(CMD_MAP_01(mem_addr)); + + writel(0, &onenand->reg->trans_spare); + return 0; + + case ONENAND_CMD_PROG: + /* Main */ + for (i = 0; i < mcount; i++) + s3c_write_cmd(*m++, CMD_MAP_01(mem_addr)); + return 0; + + case ONENAND_CMD_PROGOOB: + writel(TSRF, &onenand->reg->trans_spare); + + /* Main - dummy write */ + for (i = 0; i < mcount; i++) + s3c_write_cmd(0xffffffff, CMD_MAP_01(mem_addr)); + + /* Spare */ + for (i = 0; i < scount; i++) + s3c_write_cmd(*s++, CMD_MAP_01(mem_addr)); + + writel(0, &onenand->reg->trans_spare); + return 0; + + case ONENAND_CMD_UNLOCK_ALL: + s3c_write_cmd(ONENAND_UNLOCK_ALL, CMD_MAP_10(mem_addr)); + return 0; + + case ONENAND_CMD_ERASE: + s3c_write_cmd(ONENAND_ERASE_START, CMD_MAP_10(mem_addr)); + return 0; + + case ONENAND_CMD_MULTIBLOCK_ERASE: + s3c_write_cmd(ONENAND_MULTI_ERASE_SET, CMD_MAP_10(mem_addr)); + return 0; + + case ONENAND_CMD_ERASE_VERIFY: + s3c_write_cmd(ONENAND_ERASE_VERIFY, CMD_MAP_10(mem_addr)); + return 0; + + default: + break; + } + + return 0; +} + +static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area) +{ + struct onenand_chip *this = mtd->priv; + int index = ONENAND_CURRENT_BUFFERRAM(this); + unsigned char *p; + + if (area == ONENAND_DATARAM) { + p = (unsigned char *) onenand->page_buf; + if (index == 1) + p += this->writesize; + } else { + p = (unsigned char *) onenand->oob_buf; + if (index == 1) + p += mtd->oobsize; + } + + return p; +} + +static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area, + unsigned char *buffer, int offset, + size_t count) +{ + unsigned char *p; + + p = s3c_get_bufferram(mtd, area); + memcpy(buffer, p + offset, count); + return 0; +} + +static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area, + const unsigned char *buffer, int offset, + size_t count) +{ + unsigned char *p; + + p = s3c_get_bufferram(mtd, area); + memcpy(p + offset, buffer, count); + return 0; +} + +static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state) +{ + struct samsung_onenand *reg = (struct samsung_onenand *)onenand->base; + unsigned int flags = INT_ACT | LOAD_CMP; + unsigned int stat; + unsigned long timeout = 0x10000; + + while (timeout--) { + stat = readl(®->int_err_stat); + if (stat & flags) + break; + } + /* To get correct interrupt status in timeout case */ + stat = readl(&onenand->reg->int_err_stat); + writel(stat, &onenand->reg->int_err_ack); + + if (stat & LD_FAIL_ECC_ERR) { + s3c_onenand_reset(); + return ONENAND_BBT_READ_ERROR; + } + + if (stat & LOAD_CMP) { + int ecc = readl(&onenand->reg->ecc_err_stat); + if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) { + s3c_onenand_reset(); + return ONENAND_BBT_READ_ERROR; + } + } + + return 0; +} + +static void s3c_onenand_check_lock_status(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + unsigned int block, end; + int tmp; + + end = this->chipsize >> this->erase_shift; + + for (block = 0; block < end; block++) { + tmp = s3c_read_cmd(CMD_MAP_01(onenand->mem_addr(block, 0, 0))); + + if (readl(&onenand->reg->int_err_stat) & LOCKED_BLK) { + printf("block %d is write-protected!\n", block); + writel(LOCKED_BLK, &onenand->reg->int_err_ack); + } + } +} + +static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, + size_t len, int cmd) +{ + struct onenand_chip *this = mtd->priv; + int start, end, start_mem_addr, end_mem_addr; + + start = ofs >> this->erase_shift; + start_mem_addr = onenand->mem_addr(start, 0, 0); + end = start + (len >> this->erase_shift) - 1; + end_mem_addr = onenand->mem_addr(end, 0, 0); + + if (cmd == ONENAND_CMD_LOCK) { + s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(start_mem_addr)); + s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(end_mem_addr)); + } else { + s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(start_mem_addr)); + s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(end_mem_addr)); + } + + this->wait(mtd, FL_LOCKING); +} + +static void s3c_onenand_unlock_all(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + loff_t ofs = 0; + size_t len = this->chipsize; + + /* FIXME workaround */ + this->subpagesize = mtd->writesize; + mtd->subpage_sft = 0; + + if (this->options & ONENAND_HAS_UNLOCK_ALL) { + /* Write unlock command */ + this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); + + /* No need to check return value */ + this->wait(mtd, FL_LOCKING); + + /* Workaround for all block unlock in DDP */ + if (!ONENAND_IS_DDP(this)) { + s3c_onenand_check_lock_status(mtd); + return; + } + + /* All blocks on another chip */ + ofs = this->chipsize >> 1; + len = this->chipsize >> 1; + } + + s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); + s3c_onenand_check_lock_status(mtd); +} + +#ifdef CONFIG_S3C64XX +static void s3c_set_width_regs(struct onenand_chip *this) +{ + int dev_id, density; + int fba, fpa, fsa; + int dbs_dfs; + + dev_id = DEVICE_ID0_REG; + + density = (dev_id >> ONENAND_DEVICE_DENSITY_SHIFT) & 0xf; + dbs_dfs = !!(dev_id & ONENAND_DEVICE_IS_DDP); + + fba = density + 7; + if (dbs_dfs) + fba--; /* Decrease the fba */ + fpa = 6; + if (density >= ONENAND_DEVICE_DENSITY_512Mb) + fsa = 2; + else + fsa = 1; + + DPRINTK("FBA %lu, FPA %lu, FSA %lu, DDP %lu", + FBA_WIDTH0_REG, FPA_WIDTH0_REG, FSA_WIDTH0_REG, + DDP_DEVICE_REG); + + DPRINTK("mem_cfg0 0x%lx, sync mode %lu, " + "dev_page_size %lu, BURST LEN %lu", + MEM_CFG0_REG, SYNC_MODE_REG, + DEV_PAGE_SIZE_REG, BURST_LEN0_REG); + + DEV_PAGE_SIZE_REG = 0x1; + + FBA_WIDTH0_REG = fba; + FPA_WIDTH0_REG = fpa; + FSA_WIDTH0_REG = fsa; + DBS_DFS_WIDTH0_REG = dbs_dfs; +} +#endif + +void s3c_onenand_init(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + u32 size = (4 << 10); /* 4 KiB */ + + onenand = malloc(sizeof(struct s3c_onenand)); + if (!onenand) + return; + + onenand->page_buf = malloc(size * sizeof(char)); + if (!onenand->page_buf) + return; + memset(onenand->page_buf, 0xff, size); + + onenand->oob_buf = malloc(128 * sizeof(char)); + if (!onenand->oob_buf) + return; + memset(onenand->oob_buf, 0xff, 128); + + onenand->mtd = mtd; + +#if defined(CONFIG_S3C64XX) + onenand->base = (void *)0x70100000; + onenand->ahb_addr = (void *)0x20000000; +#elif defined(CONFIG_S5PC1XX) + onenand->base = (void *)0xE7100000; + onenand->ahb_addr = (void *)0xB0000000; +#endif + onenand->mem_addr = s3c_mem_addr; + onenand->reg = (struct samsung_onenand *)onenand->base; + + this->read_word = s3c_onenand_readw; + this->write_word = s3c_onenand_writew; + + this->wait = s3c_onenand_wait; + this->bbt_wait = s3c_onenand_bbt_wait; + this->unlock_all = s3c_onenand_unlock_all; + this->command = s3c_onenand_command; + + this->read_bufferram = onenand_read_bufferram; + this->write_bufferram = onenand_write_bufferram; + + this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK; +} diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index b106ec9..df73478 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -249,6 +249,12 @@ int smc911x_initialize(u8 dev_num, int base_addr) dev->iobase = base_addr; + /* Try to detect chip. Will fail if not present. */ + if (smc911x_detect_chip(dev)) { + free(dev); + return 0; + } + addrh = smc911x_get_mac_csr(dev, ADDRH); addrl = smc911x_get_mac_csr(dev, ADDRL); dev->enetaddr[0] = addrl; @@ -264,12 +270,6 @@ int smc911x_initialize(u8 dev_num, int base_addr) dev->recv = smc911x_rx; sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); - /* Try to detect chip. Will fail if not present. */ - if (smc911x_detect_chip(dev)) { - free(dev); - return 0; - } - eth_register(dev); return 0; } diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c index e10db9a..1ce34e3 100644 --- a/drivers/rtc/s3c24x0_rtc.c +++ b/drivers/rtc/s3c24x0_rtc.c @@ -37,6 +37,7 @@ #endif #include <rtc.h> +#include <asm/io.h> /*#define DEBUG*/ @@ -48,112 +49,113 @@ typedef enum { static inline void SetRTC_Access(RTC_ACCESS a) { - S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc(); + switch (a) { - case RTC_ENABLE: - rtc->RTCCON |= 0x01; break; + case RTC_ENABLE: + writeb(readb(&rtc->RTCCON) | 0x01, &rtc->RTCCON); + break; - case RTC_DISABLE: - rtc->RTCCON &= ~0x01; break; + case RTC_DISABLE: + writeb(readb(&rtc->RTCCON) & ~0x01, &rtc->RTCCON); + break; } } /* ------------------------------------------------------------------------- */ -int rtc_get (struct rtc_time *tmp) +int rtc_get(struct rtc_time *tmp) { - S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc(); uchar sec, min, hour, mday, wday, mon, year; - uchar a_sec,a_min, a_hour, a_date, a_mon, a_year, a_armed; + uchar a_sec, a_min, a_hour, a_date, a_mon, a_year, a_armed; /* enable access to RTC registers */ SetRTC_Access(RTC_ENABLE); /* read RTC registers */ do { - sec = rtc->BCDSEC; - min = rtc->BCDMIN; - hour = rtc->BCDHOUR; - mday = rtc->BCDDATE; - wday = rtc->BCDDAY; - mon = rtc->BCDMON; - year = rtc->BCDYEAR; - } while (sec != rtc->BCDSEC); + sec = readb(&rtc->BCDSEC); + min = readb(&rtc->BCDMIN); + hour = readb(&rtc->BCDHOUR); + mday = readb(&rtc->BCDDATE); + wday = readb(&rtc->BCDDAY); + mon = readb(&rtc->BCDMON); + year = readb(&rtc->BCDYEAR); + } while (sec != readb(&rtc->BCDSEC)); /* read ALARM registers */ - a_sec = rtc->ALMSEC; - a_min = rtc->ALMMIN; - a_hour = rtc->ALMHOUR; - a_date = rtc->ALMDATE; - a_mon = rtc->ALMMON; - a_year = rtc->ALMYEAR; - a_armed = rtc->RTCALM; + a_sec = readb(&rtc->ALMSEC); + a_min = readb(&rtc->ALMMIN); + a_hour = readb(&rtc->ALMHOUR); + a_date = readb(&rtc->ALMDATE); + a_mon = readb(&rtc->ALMMON); + a_year = readb(&rtc->ALMYEAR); + a_armed = readb(&rtc->RTCALM); /* disable access to RTC registers */ SetRTC_Access(RTC_DISABLE); #ifdef RTC_DEBUG - printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " - "hr: %02x min: %02x sec: %02x\n", - year, mon, mday, wday, - hour, min, sec); - printf ( "Alarms: %02x: year: %02x month: %02x date: %02x hour: %02x min: %02x sec: %02x\n", - a_armed, - a_year, a_mon, a_date, - a_hour, a_min, a_sec); + printf("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, hour, min, sec); + printf("Alarms: %02x: year: %02x month: %02x date: %02x hour: " + "%02x min: %02x sec: %02x\n", + a_armed, a_year, a_mon, a_date, a_hour, a_min, a_sec); #endif - tmp->tm_sec = bcd2bin(sec & 0x7F); - tmp->tm_min = bcd2bin(min & 0x7F); + tmp->tm_sec = bcd2bin(sec & 0x7F); + tmp->tm_min = bcd2bin(min & 0x7F); tmp->tm_hour = bcd2bin(hour & 0x3F); tmp->tm_mday = bcd2bin(mday & 0x3F); tmp->tm_mon = bcd2bin(mon & 0x1F); tmp->tm_year = bcd2bin(year); tmp->tm_wday = bcd2bin(wday & 0x07); - if(tmp->tm_year<70) - tmp->tm_year+=2000; + if (tmp->tm_year < 70) + tmp->tm_year += 2000; else - tmp->tm_year+=1900; - tmp->tm_yday = 0; - tmp->tm_isdst= 0; + tmp->tm_year += 1900; + tmp->tm_yday = 0; + tmp->tm_isdst = 0; #ifdef RTC_DEBUG - printf ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + printf("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); #endif return 0; } -int rtc_set (struct rtc_time *tmp) +int rtc_set(struct rtc_time *tmp) { - S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc(); uchar sec, min, hour, mday, wday, mon, year; #ifdef RTC_DEBUG - printf ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + printf("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); #endif - year = bin2bcd(tmp->tm_year % 100); - mon = bin2bcd(tmp->tm_mon); - wday = bin2bcd(tmp->tm_wday); - mday = bin2bcd(tmp->tm_mday); - hour = bin2bcd(tmp->tm_hour); - min = bin2bcd(tmp->tm_min); - sec = bin2bcd(tmp->tm_sec); + year = bin2bcd(tmp->tm_year % 100); + mon = bin2bcd(tmp->tm_mon); + wday = bin2bcd(tmp->tm_wday); + mday = bin2bcd(tmp->tm_mday); + hour = bin2bcd(tmp->tm_hour); + min = bin2bcd(tmp->tm_min); + sec = bin2bcd(tmp->tm_sec); /* enable access to RTC registers */ SetRTC_Access(RTC_ENABLE); /* write RTC registers */ - rtc->BCDSEC = sec; - rtc->BCDMIN = min; - rtc->BCDHOUR = hour; - rtc->BCDDATE = mday; - rtc->BCDDAY = wday; - rtc->BCDMON = mon; - rtc->BCDYEAR = year; + writeb(sec, &rtc->BCDSEC); + writeb(min, &rtc->BCDMIN); + writeb(hour, &rtc->BCDHOUR); + writeb(mday, &rtc->BCDDATE); + writeb(wday, &rtc->BCDDAY); + writeb(mon, &rtc->BCDMON); + writeb(year, &rtc->BCDYEAR); /* disable access to RTC registers */ SetRTC_Access(RTC_DISABLE); @@ -161,12 +163,12 @@ int rtc_set (struct rtc_time *tmp) return 0; } -void rtc_reset (void) +void rtc_reset(void) { - S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc(); - rtc->RTCCON = (rtc->RTCCON & ~0x06) | 0x08; - rtc->RTCCON &= ~(0x08|0x01); + writeb((readb(&rtc->RTCCON) & ~0x06) | 0x08, &rtc->RTCCON); + writeb(readb(&rtc->RTCCON) & ~(0x08 | 0x01), &rtc->RTCCON); } #endif diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 64882a2..3c77a7c 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -33,6 +33,7 @@ COBJS-$(CONFIG_NS9750_UART) += ns9750_serial.o COBJS-$(CONFIG_SYS_NS16550) += ns16550.o COBJS-$(CONFIG_DRIVER_S3C4510_UART) += s3c4510b_uart.o COBJS-$(CONFIG_S3C64XX) += s3c64xx.o +COBJS-$(CONFIG_S5PC1XX) += serial_s5pc1xx.o COBJS-$(CONFIG_SYS_NS16550_SERIAL) += serial.o COBJS-$(CONFIG_CLPS7111_SERIAL) += serial_clps7111.o COBJS-$(CONFIG_IMX_SERIAL) += serial_imx.o diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c index 6d69c43..c2c72e4 100644 --- a/drivers/serial/serial_s3c24x0.c +++ b/drivers/serial/serial_s3c24x0.c @@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR; #elif defined(CONFIG_SERIAL3) # if defined(CONFIG_TRAB) -# #error "TRAB supports only CONFIG_SERIAL1" +# error "TRAB supports only CONFIG_SERIAL1" # endif #define UART_NR S3C24X0_UART2 @@ -46,51 +46,71 @@ DECLARE_GLOBAL_DATA_PTR; #error "Bad: you didn't configure serial ..." #endif +#include <asm/io.h> + #if defined(CONFIG_SERIAL_MULTI) #include <serial.h> /* 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, } + 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 */ +#ifdef CONFIG_HWFLOW +static int hwflow; +#endif + void _serial_setbrg(const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); + struct s3c24x0_uart *uart = s3c24x0_get_base_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++); + writel(reg, &uart->UBRDIV); + for (i = 0; i < 100; i++) + /* Delay */ ; } + #if defined(CONFIG_SERIAL_MULTI) -static inline void -serial_setbrg_dev(unsigned int dev_index) +static inline void serial_setbrg_dev(unsigned int dev_index) { _serial_setbrg(dev_index); } @@ -107,29 +127,33 @@ void serial_setbrg(void) */ static int serial_init_dev(const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); + struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); + +#ifdef CONFIG_HWFLOW + hwflow = 0; /* turned off by default */ +#endif /* FIFO enable, Tx/Rx FIFO clear */ - uart->UFCON = 0x07; - uart->UMCON = 0x0; + writel(0x07, &uart->UFCON); + writel(0x0, &uart->UMCON); /* Normal,No parity,1 stop,8 bit */ - uart->ULCON = 0x3; + writel(0x3, &uart->ULCON); /* * tx=level,rx=edge,disable timeout int.,enable rx error int., * normal,interrupt or polling */ - uart->UCON = 0x245; + writel(0x245, &uart->UCON); #ifdef CONFIG_HWFLOW - uart->UMCON = 0x1; /* RTS up */ + writel(0x1, &uart->UMCON); /* RTS up */ #endif /* 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; + writel(0x10, &uart->UMCON); #endif _serial_setbrg(dev_index); @@ -140,7 +164,7 @@ static int serial_init_dev(const int dev_index) /* Initialise the serial port. The settings are always 8 data bits, no parity, * 1 stop bit, no start bits. */ -int serial_init (void) +int serial_init(void) { return serial_init_dev(UART_NR); } @@ -151,40 +175,40 @@ int serial_init (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int _serial_getc (const int dev_index) +int _serial_getc(const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); + struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); - /* wait for character to arrive */ - while (!(uart->UTRSTAT & 0x1)); + while (!(readl(&uart->UTRSTAT) & 0x1)) + /* wait for character to arrive */ ; - return uart->URXH & 0xff; + return readb(&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) +int serial_getc(void) { return _serial_getc(UART_NR); } #endif #ifdef CONFIG_HWFLOW -static int hwflow = 0; /* turned off by default */ int hwflow_onoff(int on) { - switch(on) { + switch (on) { case 0: default: - break; /* return current */ + break; /* return current */ case 1: - hwflow = 1; /* turn on */ + hwflow = 1; /* turn on */ break; case -1: - hwflow = 0; /* turn off */ + hwflow = 0; /* turn off */ break; } return hwflow; @@ -208,29 +232,29 @@ void enable_putc(void) /* * Output a single byte to the serial port. */ -void _serial_putc (const char c, const int dev_index) +void _serial_putc(const char c, const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); + struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); #ifdef CONFIG_MODEM_SUPPORT if (be_quiet) return; #endif - /* wait for room in the tx FIFO */ - while (!(uart->UTRSTAT & 0x2)); + while (!(readl(&uart->UTRSTAT) & 0x2)) + /* wait for room in the tx FIFO */ ; #ifdef CONFIG_HWFLOW - /* Wait for CTS up */ - while(hwflow && !(uart->UMSTAT & 0x1)) - ; + while (hwflow && !(readl(&uart->UMSTAT) & 0x1)) + /* Wait for CTS up */ ; #endif - uart->UTXH = c; + writeb(c, &uart->UTXH); /* If \n, also do \r */ if (c == '\n') - serial_putc ('\r'); + serial_putc('\r'); } + #if defined(CONFIG_SERIAL_MULTI) static inline void serial_putc_dev(unsigned int dev_index, const char c) { @@ -249,13 +273,13 @@ void serial_putc(const char c) */ int _serial_tstc(const int dev_index) { - S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index); + struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); - return uart->UTRSTAT & 0x1; + return readl(&uart->UTRSTAT) & 0x1; } + #if defined(CONFIG_SERIAL_MULTI) -static inline int -serial_tstc_dev(unsigned int dev_index) +static inline int serial_tstc_dev(unsigned int dev_index) { return _serial_tstc(dev_index); } @@ -269,18 +293,17 @@ int serial_tstc(void) void _serial_puts(const char *s, const int dev_index) { while (*s) { - _serial_putc (*s++, dev_index); + _serial_putc(*s++, dev_index); } } + #if defined(CONFIG_SERIAL_MULTI) -static inline void -serial_puts_dev(int dev_index, const char *s) +static inline void serial_puts_dev(int dev_index, const char *s) { _serial_puts(s, dev_index); } #else -void -serial_puts (const char *s) +void serial_puts(const char *s) { _serial_puts(s, UART_NR); } @@ -289,12 +312,11 @@ serial_puts (const char *s) #if defined(CONFIG_SERIAL_MULTI) DECLARE_S3C_SERIAL_FUNCTIONS(0); struct serial_device s3c24xx_serial0_device = - INIT_S3C_SERIAL_STRUCTURE(0, "s3ser0", "S3UART1"); +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"); +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"); - +INIT_S3C_SERIAL_STRUCTURE(2, "s3ser2", "S3UART3"); #endif /* CONFIG_SERIAL_MULTI */ diff --git a/drivers/serial/serial_s5pc1xx.c b/drivers/serial/serial_s5pc1xx.c new file mode 100644 index 0000000..68c06a9 --- /dev/null +++ b/drivers/serial/serial_s5pc1xx.c @@ -0,0 +1,195 @@ +/* + * (C) Copyright 2009 SAMSUNG Electronics + * Minkyu Kang <mk7.kang@samsung.com> + * Heungjun Kim <riverful.kim@samsung.com> + * + * based on drivers/serial/s3c64xx.c + * + * 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 <common.h> +#include <asm/io.h> +#include <asm/arch/uart.h> +#include <asm/arch/clk.h> +#include <serial.h> + +static inline struct s5pc1xx_uart *s5pc1xx_get_base_uart(int dev_index) +{ + u32 offset = dev_index * sizeof(struct s5pc1xx_uart); + + if (cpu_is_s5pc100()) + return (struct s5pc1xx_uart *)(S5PC100_UART_BASE + offset); + else + return (struct s5pc1xx_uart *)(S5PC110_UART_BASE + offset); +} + +/* + * The coefficient, used to calculate the baudrate on S5PC1XX UARTs is + * calculated as + * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT + * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1, + * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants: + */ +static const int udivslot[] = { + 0, + 0x0080, + 0x0808, + 0x0888, + 0x2222, + 0x4924, + 0x4a52, + 0x54aa, + 0x5555, + 0xd555, + 0xd5d5, + 0xddd5, + 0xdddd, + 0xdfdd, + 0xdfdf, + 0xffdf, +}; + +void serial_setbrg_dev(const int dev_index) +{ + DECLARE_GLOBAL_DATA_PTR; + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + u32 pclk = get_pclk(); + u32 baudrate = gd->baudrate; + u32 val; + + val = pclk / baudrate; + + writel(val / 16 - 1, &uart->ubrdiv); + writew(udivslot[val % 16], &uart->udivslot); +} + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + */ +int serial_init_dev(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + /* reset and enable FIFOs, set triggers to the maximum */ + writel(0, &uart->ufcon); + writel(0, &uart->umcon); + /* 8N1 */ + writel(0x3, &uart->ulcon); + /* No interrupts, no DMA, pure polling */ + writel(0x245, &uart->ucon); + + serial_setbrg_dev(dev_index); + + return 0; +} + +static int serial_err_check(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + if (readl(&uart->uerstat) & 0xf) + return 1; + + return 0; +} + +/* + * 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_dev(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + /* wait for character to arrive */ + while (!(readl(&uart->utrstat) & 0x1)) { + if (serial_err_check(dev_index)) + return 0; + } + + return (int)(readl(&uart->urxh) & 0xff); +} + +/* + * Output a single byte to the serial port. + */ +void serial_putc_dev(const char c, const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + /* wait for room in the tx FIFO */ + while (!(readl(&uart->utrstat) & 0x2)) { + if (serial_err_check(dev_index)) + return; + } + + writel(c, &uart->utxh); + + /* If \n, also do \r */ + if (c == '\n') + serial_putc('\r'); +} + +/* + * Test whether a character is in the RX buffer + */ +int serial_tstc_dev(const int dev_index) +{ + struct s5pc1xx_uart *const uart = s5pc1xx_get_base_uart(dev_index); + + return (int)(readl(&uart->utrstat) & 0x1); +} + +void serial_puts_dev(const char *s, const int dev_index) +{ + while (*s) + serial_putc_dev(*s++, dev_index); +} + +/* Multi serial device functions */ +#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \ +int s5p_serial##port##_init(void) { return serial_init_dev(port); } \ +void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \ +int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \ +int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \ +void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \ +void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); } + +#define INIT_S5P_SERIAL_STRUCTURE(port, name, bus) { \ + name, \ + bus, \ + s5p_serial##port##_init, \ + s5p_serial##port##_setbrg, \ + s5p_serial##port##_getc, \ + s5p_serial##port##_tstc, \ + s5p_serial##port##_putc, \ + s5p_serial##port##_puts, } + +DECLARE_S5P_SERIAL_FUNCTIONS(0); +struct serial_device s5pc1xx_serial0_device = + INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0", "S5PUART0"); +DECLARE_S5P_SERIAL_FUNCTIONS(1); +struct serial_device s5pc1xx_serial1_device = + INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1", "S5PUART1"); +DECLARE_S5P_SERIAL_FUNCTIONS(2); +struct serial_device s5pc1xx_serial2_device = + INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2", "S5PUART2"); +DECLARE_S5P_SERIAL_FUNCTIONS(3); +struct serial_device s5pc1xx_serial3_device = + INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3", "S5PUART3"); |