diff options
Diffstat (limited to 'cpu/ppc4xx')
-rw-r--r-- | cpu/ppc4xx/4xx_pci.c | 253 | ||||
-rw-r--r-- | cpu/ppc4xx/4xx_pcie.c | 119 | ||||
-rw-r--r-- | cpu/ppc4xx/cmd_chip_config.c | 6 | ||||
-rw-r--r-- | cpu/ppc4xx/config.mk | 3 | ||||
-rw-r--r-- | cpu/ppc4xx/cpu.c | 2 | ||||
-rw-r--r-- | cpu/ppc4xx/i2c.c | 199 | ||||
-rw-r--r-- | cpu/ppc4xx/u-boot.lds | 169 |
7 files changed, 634 insertions, 117 deletions
diff --git a/cpu/ppc4xx/4xx_pci.c b/cpu/ppc4xx/4xx_pci.c index fa521f0415..eed4534e5f 100644 --- a/cpu/ppc4xx/4xx_pci.c +++ b/cpu/ppc4xx/4xx_pci.c @@ -73,23 +73,30 @@ #include <common.h> #include <command.h> -#if !defined(CONFIG_440) #include <asm/4xx_pci.h> -#endif #include <asm/processor.h> +#include <asm/io.h> #include <pci.h> #ifdef CONFIG_PCI DECLARE_GLOBAL_DATA_PTR; +#if defined(CONFIG_405GP) || defined(CONFIG_405EP) + +#if defined(CONFIG_PMC405) +ushort pmc405_pci_subsys_deviceid(void); +#endif + +/*#define DEBUG*/ + /* * Board-specific pci initialization * Platform code can reimplement pci_pre_init() if needed */ int __pci_pre_init(struct pci_controller *hose) { -#if defined (CONFIG_405EP) +#if defined(CONFIG_405EP) /* * Enable the internal PCI arbiter by default. * @@ -105,15 +112,8 @@ int __pci_pre_init(struct pci_controller *hose) return 1; } -int pci_pre_init(struct pci_controller *hose) __attribute__((weak, alias("__pci_pre_init"))); - -#if defined(CONFIG_405GP) || defined(CONFIG_405EP) - -#if defined(CONFIG_PMC405) -ushort pmc405_pci_subsys_deviceid(void); -#endif - -/*#define DEBUG*/ +int pci_pre_init(struct pci_controller *hose) + __attribute__((weak, alias("__pci_pre_init"))); int __is_pci_host(struct pci_controller *hose) { @@ -231,7 +231,7 @@ void pci_405gp_init(struct pci_controller *hose) pciauto_region_init(hose->pci_fb); /* Let board change/modify hose & do initial checks */ - if (pci_pre_init (hose) == 0) { + if (pci_pre_init(hose) == 0) { printf("PCI: Board-specific initialization failed.\n"); printf("PCI: Configuration aborted.\n"); return; @@ -478,6 +478,231 @@ void pci_init_board(void) static struct pci_controller ppc440_hose = {0}; +/* + * This routine is called to determine if a pci scan should be + * performed. With various hardware environments (especially cPCI and + * PPMC) it's insufficient to depend on the state of the arbiter enable + * bit in the strap register, or generic host/adapter assumptions. + * + * Rather than hard-code a bad assumption in the general 440 code, the + * 440 pci code requires the board to decide at runtime. + * + * Return 0 for adapter mode, non-zero for host (monarch) mode. + * + * Weak default implementation: "Normal" boards implement the PCI + * host functionality. This can be overridden for PCI adapter boards. + */ +int __is_pci_host(struct pci_controller *hose) +{ + return 1; +} +int is_pci_host(struct pci_controller *hose) + __attribute__((weak, alias("__is_pci_host"))); + +#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \ + defined(CONFIG_440GR) || defined(CONFIG_440GRX) + +#if defined(CONFIG_SYS_PCI_TARGET_INIT) +/* + * pci_target_init + * + * The bootstrap configuration provides default settings for the pci + * inbound map (PIM). But the bootstrap config choices are limited and + * may not be sufficient for a given board. + */ +void __pci_target_init(struct pci_controller *hose) +{ + /* + * Set up Direct MMIO registers + */ + + /* + * PowerPC440 EP PCI Master configuration. + * Map one 1Gig range of PLB/processor addresses to PCI memory space. + * PLB address 0xA0000000-0xDFFFFFFF ==> PCI address 0xA0000000-0xDFFFFFFF + * Use byte reversed out routines to handle endianess. + * Make this region non-prefetchable. + */ + /* PMM0 Mask/Attribute - disabled b4 setting */ + out_le32((void *)PCIL0_PMM0MA, 0x00000000); + /* PMM0 Local Address */ + out_le32((void *)PCIL0_PMM0LA, CONFIG_SYS_PCI_MEMBASE); + /* PMM0 PCI Low Address */ + out_le32((void *)PCIL0_PMM0PCILA, CONFIG_SYS_PCI_MEMBASE); + /* PMM0 PCI High Address */ + out_le32((void *)PCIL0_PMM0PCIHA, 0x00000000); + /* 512M + No prefetching, and enable region */ + out_le32((void *)PCIL0_PMM0MA, 0xE0000001); + + /* PMM1 Mask/Attribute - disabled b4 setting */ + out_le32((void *)PCIL0_PMM1MA, 0x00000000); + /* PMM1 Local Address */ + out_le32((void *)PCIL0_PMM1LA, CONFIG_SYS_PCI_MEMBASE2); + /* PMM1 PCI Low Address */ + out_le32((void *)PCIL0_PMM1PCILA, CONFIG_SYS_PCI_MEMBASE2); + /* PMM1 PCI High Address */ + out_le32((void *)PCIL0_PMM1PCIHA, 0x00000000); + /* 512M + No prefetching, and enable region */ + out_le32((void *)PCIL0_PMM1MA, 0xE0000001); + + out_le32((void *)PCIL0_PTM1MS, 0x00000001); /* Memory Size/Attribute */ + out_le32((void *)PCIL0_PTM1LA, 0); /* Local Addr. Reg */ + out_le32((void *)PCIL0_PTM2MS, 0); /* Memory Size/Attribute */ + out_le32((void *)PCIL0_PTM2LA, 0); /* Local Addr. Reg */ + + /* + * Set up Configuration registers + */ + + /* Program the board's subsystem id/vendor id */ + pci_write_config_word(0, PCI_SUBSYSTEM_VENDOR_ID, + CONFIG_SYS_PCI_SUBSYS_VENDORID); + pci_write_config_word(0, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_ID); + + /* Configure command register as bus master */ + pci_write_config_word(0, PCI_COMMAND, PCI_COMMAND_MASTER); + + /* 240nS PCI clock */ + pci_write_config_word(0, PCI_LATENCY_TIMER, 1); + + /* No error reporting */ + pci_write_config_word(0, PCI_ERREN, 0); + + pci_write_config_dword(0, PCI_BRDGOPT2, 0x00000101); +} +#endif /* CONFIG_SYS_PCI_TARGET_INIT */ + +/* + * pci_pre_init + * + * This routine is called just prior to registering the hose and gives + * the board the opportunity to check things. Returning a value of zero + * indicates that things are bad & PCI initialization should be aborted. + * + * Different boards may wish to customize the pci controller structure + * (add regions, override default access routines, etc) or perform + * certain pre-initialization actions. + * + */ +int __pci_pre_init(struct pci_controller *hose) +{ + u32 reg; + + /* + * Set priority for all PLB3 devices to 0. + * Set PLB3 arbiter to fair mode. + */ + mfsdr(SD0_AMP1, reg); + mtsdr(SD0_AMP1, (reg & 0x000000FF) | 0x0000FF00); + reg = mfdcr(PLB3_ACR); + mtdcr(PLB3_ACR, reg | 0x80000000); + + /* + * Set priority for all PLB4 devices to 0. + */ + mfsdr(SD0_AMP0, reg); + mtsdr(SD0_AMP0, (reg & 0x000000FF) | 0x0000FF00); + reg = mfdcr(PLB4_ACR) | 0xa0000000; + mtdcr(PLB4_ACR, reg); + + /* + * Set Nebula PLB4 arbiter to fair mode. + */ + /* Segment0 */ + reg = (mfdcr(PLB0_ACR) & ~PLB0_ACR_PPM_MASK) | PLB0_ACR_PPM_FAIR; + reg = (reg & ~PLB0_ACR_HBU_MASK) | PLB0_ACR_HBU_ENABLED; + reg = (reg & ~PLB0_ACR_RDP_MASK) | PLB0_ACR_RDP_4DEEP; + reg = (reg & ~PLB0_ACR_WRP_MASK) | PLB0_ACR_WRP_2DEEP; + mtdcr(PLB0_ACR, reg); + + /* Segment1 */ + reg = (mfdcr(PLB1_ACR) & ~PLB1_ACR_PPM_MASK) | PLB1_ACR_PPM_FAIR; + reg = (reg & ~PLB1_ACR_HBU_MASK) | PLB1_ACR_HBU_ENABLED; + reg = (reg & ~PLB1_ACR_RDP_MASK) | PLB1_ACR_RDP_4DEEP; + reg = (reg & ~PLB1_ACR_WRP_MASK) | PLB1_ACR_WRP_2DEEP; + mtdcr(PLB1_ACR, reg); + +#if defined(CONFIG_SYS_PCI_BOARD_FIXUP_IRQ) + hose->fixup_irq = board_pci_fixup_irq; +#endif + + return 1; +} + +#else /* defined(CONFIG_440EP) ... */ + +#if defined(CONFIG_SYS_PCI_TARGET_INIT) +void __pci_target_init(struct pci_controller * hose) +{ + /* + * Disable everything + */ + out_le32((void *)PCIL0_PIM0SA, 0); /* disable */ + out_le32((void *)PCIL0_PIM1SA, 0); /* disable */ + out_le32((void *)PCIL0_PIM2SA, 0); /* disable */ + out_le32((void *)PCIL0_EROMBA, 0); /* disable expansion rom */ + + /* + * Map all of SDRAM to PCI address 0x0000_0000. Note that the 440 + * strapping options do not support sizes such as 128/256 MB. + */ + out_le32((void *)PCIL0_PIM0LAL, CONFIG_SYS_SDRAM_BASE); + out_le32((void *)PCIL0_PIM0LAH, 0); + out_le32((void *)PCIL0_PIM0SA, ~(gd->ram_size - 1) | 1); + out_le32((void *)PCIL0_BAR0, 0); + + /* + * Program the board's subsystem id/vendor id + */ + out_le16((void *)PCIL0_SBSYSVID, CONFIG_SYS_PCI_SUBSYS_VENDORID); + out_le16((void *)PCIL0_SBSYSID, CONFIG_SYS_PCI_SUBSYS_DEVICEID); + + out_le16((void *)PCIL0_CMD, in_le16((void *)PCIL0_CMD) | + PCI_COMMAND_MEMORY); +} +#endif /* CONFIG_SYS_PCI_TARGET_INIT */ + +int __pci_pre_init(struct pci_controller *hose) +{ + /* + * This board is always configured as the host & requires the + * PCI arbiter to be enabled. + */ + if (!pci_arbiter_enabled()) { + printf("PCI: PCI Arbiter disabled!\n"); + return 0; + } + + return 1; +} + +#endif /* defined(CONFIG_440EP) ... */ + +#if defined(CONFIG_SYS_PCI_TARGET_INIT) +void pci_target_init(struct pci_controller * hose) + __attribute__((weak, alias("__pci_target_init"))); +#endif /* CONFIG_SYS_PCI_TARGET_INIT */ + +int pci_pre_init(struct pci_controller *hose) + __attribute__((weak, alias("__pci_pre_init"))); + +#if defined(CONFIG_SYS_PCI_MASTER_INIT) +void __pci_master_init(struct pci_controller *hose) +{ + u16 reg; + + /* + * Write the PowerPC440 EP PCI Configuration regs. + * Enable PowerPC440 EP to be a master on the PCI bus (PMM). + * Enable PowerPC440 EP to act as a PCI memory target (PTM). + */ + pci_read_config_word(0, PCI_COMMAND, ®); + pci_write_config_word(0, PCI_COMMAND, reg | + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); +} +void pci_master_init(struct pci_controller *hose) + __attribute__((weak, alias("__pci_master_init"))); +#endif /* CONFIG_SYS_PCI_MASTER_INIT */ int pci_440_init (struct pci_controller *hose) { @@ -548,7 +773,7 @@ int pci_440_init (struct pci_controller *hose) pci_setup_indirect(hose, PCIL0_CFGADR, PCIL0_CFGDATA); /* Let board change/modify hose & do initial checks */ - if (pci_pre_init (hose) == 0) { + if (pci_pre_init(hose) == 0) { printf("PCI: Board-specific initialization failed.\n"); printf("PCI: Configuration aborted.\n"); return -1; diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 19d2c7dd2f..d9605c30b5 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -48,6 +48,125 @@ enum { LNKW_X8 = 0x8 }; +static struct pci_controller pcie_hose[CONFIG_SYS_PCIE_NR_PORTS]; + +/* + * Per default, all cards are present, so we need to check if the + * link comes up. + */ +int __board_pcie_card_present(int port) +{ + return 1; +} +int board_pcie_card_present(int port) + __attribute__((weak, alias("__board_pcie_card_present"))); + +/* + * Some boards have runtime detection of the first and last PCIe + * slot used, so let's provide weak default functions for the + * common version. + */ +int __board_pcie_first(void) +{ + return 0; +} +int board_pcie_first(void) + __attribute__((weak, alias("__board_pcie_first"))); + +int __board_pcie_last(void) +{ + return CONFIG_SYS_PCIE_NR_PORTS - 1; +} +int board_pcie_last(void) + __attribute__((weak, alias("__board_pcie_last"))); + +void __board_pcie_setup_port(int port, int rootpoint) +{ + /* noting in this weak default implementation */ +} +void board_pcie_setup_port(int port, int rootpoint) + __attribute__((weak, alias("__board_pcie_setup_port"))); + +void pcie_setup_hoses(int busno) +{ + struct pci_controller *hose; + int i, bus; + int ret = 0; + char *env; + unsigned int delay; + int first = board_pcie_first(); + int last = board_pcie_last(); + + /* + * Assume we're called after the PCI(X) hose(s) are initialized, + * which takes bus ID 0... and therefore start numbering PCIe's + * from the next number. + */ + bus = busno; + + for (i = first; i <= last; i++) { + /* + * Some boards (e.g. Katmai) can detects via hardware + * if a PCIe card is plugged, so let's check this. + */ + if (!board_pcie_card_present(i)) + continue; + + if (is_end_point(i)) { + board_pcie_setup_port(i, 0); + ret = ppc4xx_init_pcie_endport(i); + } else { + board_pcie_setup_port(i, 1); + ret = ppc4xx_init_pcie_rootport(i); + } + if (ret == -ENODEV) + continue; + if (ret) { + printf("PCIE%d: initialization as %s failed\n", i, + is_end_point(i) ? "endpoint" : "root-complex"); + continue; + } + + hose = &pcie_hose[i]; + hose->first_busno = bus; + hose->last_busno = bus; + hose->current_busno = bus; + + /* setup mem resource */ + pci_set_region(hose->regions + 0, + CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE, + CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE, + CONFIG_SYS_PCIE_MEMSIZE, + PCI_REGION_MEM); + hose->region_count = 1; + pci_register_hose(hose); + + if (is_end_point(i)) { + ppc4xx_setup_pcie_endpoint(hose, i); + /* + * Reson for no scanning is endpoint can not generate + * upstream configuration accesses. + */ + } else { + ppc4xx_setup_pcie_rootpoint(hose, i); + env = getenv ("pciscandelay"); + if (env != NULL) { + delay = simple_strtoul(env, NULL, 10); + if (delay > 5) + printf("Warning, expect noticable delay before " + "PCIe scan due to 'pciscandelay' value!\n"); + mdelay(delay * 1000); + } + + /* + * Config access can only go down stream + */ + hose->last_busno = pci_hose_scan(hose); + bus = hose->last_busno + 1; + } + } +} + static int validate_endpoint(struct pci_controller *hose) { if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE0_CFGBASE) diff --git a/cpu/ppc4xx/cmd_chip_config.c b/cpu/ppc4xx/cmd_chip_config.c index d360d5beec..ba57211dd0 100644 --- a/cpu/ppc4xx/cmd_chip_config.c +++ b/cpu/ppc4xx/cmd_chip_config.c @@ -52,6 +52,12 @@ static int do_chip_config(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) int cur_config_nr = -1; u8 cur_config[CONFIG_4xx_CONFIG_BLOCKSIZE]; + /* + * First switch to correct I2C bus. This is I2C bus 0 + * for all currently available 4xx derivats. + */ + I2C_SET_BUS(0); + #ifdef CONFIG_CMD_EEPROM ret = eeprom_read(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR, CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET, diff --git a/cpu/ppc4xx/config.mk b/cpu/ppc4xx/config.mk index 00ad39b602..979004b7db 100644 --- a/cpu/ppc4xx/config.mk +++ b/cpu/ppc4xx/config.mk @@ -32,3 +32,6 @@ PLATFORM_CPPFLAGS += -Wa,-m440 -mcpu=440 else PLATFORM_CPPFLAGS += -Wa,-m405 -mcpu=405 endif + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/cpu/ppc4xx/u-boot.lds diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c index e1b00a74c7..73d4d06afc 100644 --- a/cpu/ppc4xx/cpu.c +++ b/cpu/ppc4xx/cpu.c @@ -81,7 +81,7 @@ static int pci_async_enabled(void) #if defined(CONFIG_PCI) && !defined(CONFIG_IOP480) && \ !defined(CONFIG_405) && !defined(CONFIG_405EX) -static int pci_arbiter_enabled(void) +int pci_arbiter_enabled(void) { #if defined(CONFIG_405GP) return (mfdcr(CPC0_PSR) & PSR_PCI_ARBIT_EN); diff --git a/cpu/ppc4xx/i2c.c b/cpu/ppc4xx/i2c.c index e3e1bab64f..7976e75e0b 100644 --- a/cpu/ppc4xx/i2c.c +++ b/cpu/ppc4xx/i2c.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2007 + * (C) Copyright 2007-2009 * Stefan Roese, DENX Software Engineering, sr@denx.de. * * based on work by Anne Sophie Harnois <anne-sophie.harnois@nextream.fr> @@ -37,7 +37,8 @@ DECLARE_GLOBAL_DATA_PTR; #if defined(CONFIG_I2C_MULTI_BUS) -/* Initialize the bus pointer to whatever one the SPD EEPROM is on. +/* + * Initialize the bus pointer to whatever one the SPD EEPROM is on. * Default is bus 0. This is necessary because the DDR initialization * runs from ROM, and we can't switch buses because we can't modify * the global variables. @@ -45,59 +46,63 @@ DECLARE_GLOBAL_DATA_PTR; #ifndef CONFIG_SYS_SPD_BUS_NUM #define CONFIG_SYS_SPD_BUS_NUM 0 #endif -static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = CONFIG_SYS_SPD_BUS_NUM; +static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = + CONFIG_SYS_SPD_BUS_NUM; #endif /* CONFIG_I2C_MULTI_BUS */ static void _i2c_bus_reset(void) { + struct ppc4xx_i2c *i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR; int i; u8 dc; /* Reset status register */ /* write 1 in SCMP and IRQA to clear these fields */ - out_8((u8 *)IIC_STS, 0x0A); + out_8(&i2c->sts, 0x0A); /* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */ - out_8((u8 *)IIC_EXTSTS, 0x8F); + out_8(&i2c->extsts, 0x8F); /* Place chip in the reset state */ - out_8((u8 *)IIC_XTCNTLSS, IIC_XTCNTLSS_SRST); + out_8(&i2c->xtcntlss, IIC_XTCNTLSS_SRST); /* Check if bus is free */ - dc = in_8((u8 *)IIC_DIRECTCNTL); + dc = in_8(&i2c->directcntl); if (!DIRCTNL_FREE(dc)){ /* Try to set bus free state */ - out_8((u8 *)IIC_DIRECTCNTL, IIC_DIRCNTL_SDAC | IIC_DIRCNTL_SCC); + out_8(&i2c->directcntl, IIC_DIRCNTL_SDAC | IIC_DIRCNTL_SCC); /* Wait until we regain bus control */ for (i = 0; i < 100; ++i) { - dc = in_8((u8 *)IIC_DIRECTCNTL); + dc = in_8(&i2c->directcntl); if (DIRCTNL_FREE(dc)) break; /* Toggle SCL line */ dc ^= IIC_DIRCNTL_SCC; - out_8((u8 *)IIC_DIRECTCNTL, dc); + out_8(&i2c->directcntl, dc); udelay(10); dc ^= IIC_DIRCNTL_SCC; - out_8((u8 *)IIC_DIRECTCNTL, dc); + out_8(&i2c->directcntl, dc); } } /* Remove reset */ - out_8((u8 *)IIC_XTCNTLSS, 0); + out_8(&i2c->xtcntlss, 0); } -void i2c_init(int speed, int slaveadd) +void i2c_init(int speed, int slaveaddr) { - unsigned long freqOPB; + struct ppc4xx_i2c *i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR; int val, divisor; int bus; #ifdef CONFIG_SYS_I2C_INIT_BOARD - /* call board specific i2c bus reset routine before accessing the */ - /* environment, which might be in a chip on that bus. For details */ - /* about this problem see doc/I2C_Edge_Conditions. */ + /* + * Call board specific i2c bus reset routine before accessing the + * environment, which might be in a chip on that bus. For details + * about this problem see doc/I2C_Edge_Conditions. + */ i2c_init_board(); #endif @@ -109,54 +114,52 @@ void i2c_init(int speed, int slaveadd) _i2c_bus_reset(); /* clear lo master address */ - out_8((u8 *)IIC_LMADR, 0); + out_8(&i2c->lmadr, 0); /* clear hi master address */ - out_8((u8 *)IIC_HMADR, 0); + out_8(&i2c->hmadr, 0); /* clear lo slave address */ - out_8((u8 *)IIC_LSADR, 0); + out_8(&i2c->lsadr, 0); /* clear hi slave address */ - out_8((u8 *)IIC_HSADR, 0); + out_8(&i2c->hsadr, 0); /* Clock divide Register */ - /* get OPB frequency */ - freqOPB = get_OPB_freq(); - /* set divisor according to freqOPB */ - divisor = (freqOPB - 1) / 10000000; + /* set divisor according to freq_opb */ + divisor = (get_OPB_freq() - 1) / 10000000; if (divisor == 0) divisor = 1; - out_8((u8 *)IIC_CLKDIV, divisor); + out_8(&i2c->clkdiv, divisor); /* no interrupts */ - out_8((u8 *)IIC_INTRMSK, 0); + out_8(&i2c->intrmsk, 0); /* clear transfer count */ - out_8((u8 *)IIC_XFRCNT, 0); + out_8(&i2c->xfrcnt, 0); /* clear extended control & stat */ /* write 1 in SRC SRS SWC SWS to clear these fields */ - out_8((u8 *)IIC_XTCNTLSS, 0xF0); + out_8(&i2c->xtcntlss, 0xF0); /* Mode Control Register Flush Slave/Master data buffer */ - out_8((u8 *)IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB); + out_8(&i2c->mdcntl, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB); - val = in_8((u8 *)IIC_MDCNTL); + val = in_8(&i2c->mdcntl); /* Ignore General Call, slave transfers are ignored, * disable interrupts, exit unknown bus state, enable hold * SCL 100kHz normaly or FastMode for 400kHz and above */ - val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL; + val |= IIC_MDCNTL_EUBS | IIC_MDCNTL_HSCL; if (speed >= 400000) val |= IIC_MDCNTL_FSM; - out_8((u8 *)IIC_MDCNTL, val); + out_8(&i2c->mdcntl, val); /* clear control reg */ - out_8((u8 *)IIC_CNTL, 0x00); + out_8(&i2c->cntl, 0x00); } /* set to SPD bus as default bus upon powerup */ @@ -195,13 +198,14 @@ static int i2c_transfer(unsigned char cmd_type, unsigned char data[], unsigned short data_len) { - unsigned char* ptr; + struct ppc4xx_i2c *i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR; + u8 *ptr; int reading; - int tran,cnt; + int tran, cnt; int result; int status; int i; - uchar creg; + u8 creg; if (data == 0 || data_len == 0) { /* Don't support data transfer of no length or to address 0 */ @@ -219,12 +223,13 @@ static int i2c_transfer(unsigned char cmd_type, } /* Clear Stop Complete Bit */ - out_8((u8 *)IIC_STS, IIC_STS_SCMP); + out_8(&i2c->sts, IIC_STS_SCMP); + /* Check init */ i = 10; do { /* Get status */ - status = in_8((u8 *)IIC_STS); + status = in_8(&i2c->sts); i--; } while ((status & IIC_STS_PT) && (i > 0)); @@ -232,13 +237,16 @@ static int i2c_transfer(unsigned char cmd_type, result = IIC_NOK_TOUT; return(result); } + /* flush the Master/Slave Databuffers */ - out_8((u8 *)IIC_MDCNTL, ((in_8((u8 *)IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB)); + out_8(&i2c->mdcntl, in_8(&i2c->mdcntl) | + IIC_MDCNTL_FMDB | IIC_MDCNTL_FSDB); + /* need to wait 4 OPB clocks? code below should take that long */ /* 7-bit adressing */ - out_8((u8 *)IIC_HMADR, 0); - out_8((u8 *)IIC_LMADR, chip); + out_8(&i2c->hmadr, 0); + out_8(&i2c->lmadr, chip); tran = 0; result = IIC_OK; @@ -247,9 +255,10 @@ static int i2c_transfer(unsigned char cmd_type, while (tran != cnt && (result == IIC_OK)) { int bc,j; - /* Control register = - * Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start, - * Transfer is a sequence of transfers + /* + * Control register = + * Normal transfer, 7-bits adressing, Transfer up to + * bc bytes, Normal start, Transfer is a sequence of transfers */ creg |= IIC_CNTL_PT; @@ -259,32 +268,36 @@ static int i2c_transfer(unsigned char cmd_type, if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt)) creg |= IIC_CNTL_CHT; - if (reading) + if (reading) { creg |= IIC_CNTL_READ; - else - for(j=0; j < bc; j++) + } else { + for(j = 0; j < bc; j++) { /* Set buffer */ - out_8((u8 *)IIC_MDBUF, ptr[tran+j]); - out_8((u8 *)IIC_CNTL, creg); + out_8(&i2c->mdbuf, ptr[tran + j]); + } + } + out_8(&i2c->cntl, creg); - /* Transfer is in progress + /* + * Transfer is in progress * we have to wait for upto 5 bytes of data * 1 byte chip address+r/w bit then bc bytes * of data. * udelay(10) is 1 bit time at 100khz * Doubled for slop. 20 is too small. */ - i = 2*5*8; + i = 2 * 5 * 8; do { /* Get status */ - status = in_8((u8 *)IIC_STS); + status = in_8(&i2c->sts); udelay(10); i--; - } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) && (i > 0)); + } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) && + (i > 0)); if (status & IIC_STS_ERR) { result = IIC_NOK; - status = in_8((u8 *)IIC_EXTSTS); + status = in_8(&i2c->extsts); /* Lost arbitration? */ if (status & IIC_EXTSTS_LA) result = IIC_NOK_LA; @@ -297,19 +310,21 @@ static int i2c_transfer(unsigned char cmd_type, } else if ( status & IIC_STS_PT) { result = IIC_NOK_TOUT; } + /* Command is reading => get buffer */ if ((reading) && (result == IIC_OK)) { /* Are there data in buffer */ if (status & IIC_STS_MDBS) { /* - * even if we have data we have to wait 4OPB clocks - * for it to hit the front of the FIFO, after that - * we can just read. We should check XFCNT here and - * if the FIFO is full there is no need to wait. + * even if we have data we have to wait 4OPB + * clocks for it to hit the front of the FIFO, + * after that we can just read. We should check + * XFCNT here and if the FIFO is full there is + * no need to wait. */ udelay(1); - for (j=0; j<bc; j++) - ptr[tran+j] = in_8((u8 *)IIC_MDBUF); + for (j = 0; j < bc; j++) + ptr[tran + j] = in_8(&i2c->mdbuf); } else result = IIC_NOK_DATA; } @@ -324,7 +339,7 @@ static int i2c_transfer(unsigned char cmd_type, creg = IIC_CNTL_RPST; } } - return (result); + return result; } int i2c_probe(uchar chip) @@ -338,17 +353,17 @@ 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(1, chip << 1, 0,0, buf, 1) != 0); + return (i2c_transfer(1, chip << 1, 0, 0, buf, 1) != 0); } - -int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len) +static int ppc4xx_i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer, + int len, int read) { uchar xaddr[4]; int ret; if (alen > 4) { - printf ("I2C read: addr len %d not supported\n", alen); + printf("I2C: addr len %d not supported\n", alen); return 1; } @@ -373,50 +388,30 @@ 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(1, chip<<1, &xaddr[4-alen], alen, buffer, len)) != 0) { - if (gd->have_console) - printf( "I2c read: failed %d\n", ret); + if ((ret = i2c_transfer(read, chip << 1, &xaddr[4 - alen], alen, + buffer, len)) != 0) { + if (gd->have_console) { + printf("I2C %s: failed %d\n", + read ? "read" : "write", ret); + } + return 1; } + return 0; } -int i2c_write(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]; - - if (alen > 4) { - printf ("I2C write: addr len %d not supported\n", alen); - return 1; - - } - - if (alen > 0) { - xaddr[0] = (addr >> 24) & 0xFF; - xaddr[1] = (addr >> 16) & 0xFF; - xaddr[2] = (addr >> 8) & 0xFF; - xaddr[3] = addr & 0xFF; - } - -#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW - /* - * EEPROM chips that implement "address overflow" are ones - * like Catalyst 24WC04/08/16 which has 9/10/11 bits of - * address and the extra bits end up in the "chip address" - * bit slots. This makes a 24WC08 (1Kbyte) chip look like - * four 256 byte chips. - * - * Note that we consider the length of the address field to - * still be one byte because the extra address bits are - * hidden in the chip address. - */ - if (alen > 0) - chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); -#endif + return ppc4xx_i2c_transfer(chip, addr, alen, buffer, len, 1); +} - return (i2c_transfer(0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0); +int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len) +{ + return ppc4xx_i2c_transfer(chip, addr, alen, buffer, len, 0); } #if defined(CONFIG_I2C_MULTI_BUS) diff --git a/cpu/ppc4xx/u-boot.lds b/cpu/ppc4xx/u-boot.lds new file mode 100644 index 0000000000..2b47934a2e --- /dev/null +++ b/cpu/ppc4xx/u-boot.lds @@ -0,0 +1,169 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. + * + * 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 "config.h" /* CONFIG_BOARDDIR */ + +#ifndef RESET_VECTOR_ADDRESS +#define RESET_VECTOR_ADDRESS 0xfffffffc +#endif + +OUTPUT_ARCH(powerpc) +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +PHDRS +{ + text PT_LOAD; + bss PT_LOAD; +} + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + *(.text) + *(.got1) + } :text + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.eh_frame) + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + } :text + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x00FF) & 0xFFFFFF00; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + +#ifdef CONFIG_440 + .bootpg RESET_VECTOR_ADDRESS - 0xffc : + { + cpu/ppc4xx/start.o (.bootpg) + + /* + * PPC440 board need a board specific object with the + * TLB definitions. This needs to get included right after + * start.o, since the first shadow TLB only covers 4k + * of address space. + */ + CONFIG_BOARDDIR/init.o (.bootpg) + } :text = 0xffff +#endif + + .resetvec RESET_VECTOR_ADDRESS : + { + *(.resetvec) + } :text = 0xffff + + . = RESET_VECTOR_ADDRESS + 0x4; + + /* + * Make sure that the bss segment isn't linked at 0x0, otherwise its + * address won't be updated during relocation fixups. Note that + * this is a temporary fix. Code to dynamically the fixup the bss + * location will be added in the future. When the bss relocation + * fixup code is present this workaround should be removed. + */ +#if (RESET_VECTOR_ADDRESS == 0xfffffffc) + . |= 0x10; +#endif + + __bss_start = .; + .bss (NOLOAD) : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } :bss + + . = ALIGN(4); + _end = . ; + PROVIDE (end = .); +} |