Path: blob/master/arch/mips/txx9/generic/setup_tx4939.c
10818 views
/*1* TX4939 setup routines2* Based on linux/arch/mips/txx9/generic/setup_tx4938.c,3* and RBTX49xx patch from CELF patch archive.4*5* 2003-2005 (c) MontaVista Software, Inc.6* (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-20077*8* This file is subject to the terms and conditions of the GNU General Public9* License. See the file "COPYING" in the main directory of this archive10* for more details.11*/12#include <linux/init.h>13#include <linux/ioport.h>14#include <linux/delay.h>15#include <linux/netdevice.h>16#include <linux/notifier.h>17#include <linux/sysdev.h>18#include <linux/ethtool.h>19#include <linux/param.h>20#include <linux/ptrace.h>21#include <linux/mtd/physmap.h>22#include <linux/platform_device.h>23#include <asm/bootinfo.h>24#include <asm/reboot.h>25#include <asm/traps.h>26#include <asm/txx9irq.h>27#include <asm/txx9tmr.h>28#include <asm/txx9/generic.h>29#include <asm/txx9/ndfmc.h>30#include <asm/txx9/dmac.h>31#include <asm/txx9/tx4939.h>3233static void __init tx4939_wdr_init(void)34{35/* report watchdog reset status */36if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDRST)37pr_warning("Watchdog reset detected at 0x%lx\n",38read_c0_errorepc());39/* clear WatchDogReset (W1C) */40tx4939_ccfg_set(TX4939_CCFG_WDRST);41/* do reset on watchdog */42tx4939_ccfg_set(TX4939_CCFG_WR);43}4445void __init tx4939_wdt_init(void)46{47txx9_wdt_init(TX4939_TMR_REG(2) & 0xfffffffffULL);48}4950static void tx4939_machine_restart(char *command)51{52local_irq_disable();53pr_emerg("Rebooting (with %s watchdog reset)...\n",54(____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDREXEN) ?55"external" : "internal");56/* clear watchdog status */57tx4939_ccfg_set(TX4939_CCFG_WDRST); /* W1C */58txx9_wdt_now(TX4939_TMR_REG(2) & 0xfffffffffULL);59while (!(____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDRST))60;61mdelay(10);62if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDREXEN) {63pr_emerg("Rebooting (with internal watchdog reset)...\n");64/* External WDRST failed. Do internal watchdog reset */65tx4939_ccfg_clear(TX4939_CCFG_WDREXEN);66}67/* fallback */68(*_machine_halt)();69}7071void show_registers(struct pt_regs *regs);72static int tx4939_be_handler(struct pt_regs *regs, int is_fixup)73{74int data = regs->cp0_cause & 4;75console_verbose();76pr_err("%cBE exception at %#lx\n",77data ? 'D' : 'I', regs->cp0_epc);78pr_err("ccfg:%llx, toea:%llx\n",79(unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg),80(unsigned long long)____raw_readq(&tx4939_ccfgptr->toea));81#ifdef CONFIG_PCI82tx4927_report_pcic_status();83#endif84show_registers(regs);85panic("BusError!");86}87static void __init tx4939_be_init(void)88{89board_be_handler = tx4939_be_handler;90}9192static struct resource tx4939_sdram_resource[4];93static struct resource tx4939_sram_resource;94#define TX4939_SRAM_SIZE 0x8009596void __init tx4939_add_memory_regions(void)97{98int i;99unsigned long start, size;100u64 win;101102for (i = 0; i < 4; i++) {103if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i)))104continue;105win = ____raw_readq(&tx4939_ddrcptr->win[i]);106start = (unsigned long)(win >> 48);107size = (((unsigned long)(win >> 32) & 0xffff) + 1) - start;108add_memory_region(start << 20, size << 20, BOOT_MEM_RAM);109}110}111112void __init tx4939_setup(void)113{114int i;115__u32 divmode;116__u64 pcfg;117unsigned int cpuclk = 0;118119txx9_reg_res_init(TX4939_REV_PCODE(), TX4939_REG_BASE,120TX4939_REG_SIZE);121set_c0_config(TX49_CONF_CWFON);122123/* SDRAMC,EBUSC are configured by PROM */124for (i = 0; i < 4; i++) {125if (!(TX4939_EBUSC_CR(i) & 0x8))126continue; /* disabled */127txx9_ce_res[i].start = (unsigned long)TX4939_EBUSC_BA(i);128txx9_ce_res[i].end =129txx9_ce_res[i].start + TX4939_EBUSC_SIZE(i) - 1;130request_resource(&iomem_resource, &txx9_ce_res[i]);131}132133/* clocks */134if (txx9_master_clock) {135/* calculate cpu_clock from master_clock */136divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) &137TX4939_CCFG_MULCLK_MASK;138cpuclk = txx9_master_clock * 20 / 2;139switch (divmode) {140case TX4939_CCFG_MULCLK_8:141cpuclk = cpuclk / 3 * 4 /* / 6 * 8 */; break;142case TX4939_CCFG_MULCLK_9:143cpuclk = cpuclk / 2 * 3 /* / 6 * 9 */; break;144case TX4939_CCFG_MULCLK_10:145cpuclk = cpuclk / 3 * 5 /* / 6 * 10 */; break;146case TX4939_CCFG_MULCLK_11:147cpuclk = cpuclk / 6 * 11; break;148case TX4939_CCFG_MULCLK_12:149cpuclk = cpuclk * 2 /* / 6 * 12 */; break;150case TX4939_CCFG_MULCLK_13:151cpuclk = cpuclk / 6 * 13; break;152case TX4939_CCFG_MULCLK_14:153cpuclk = cpuclk / 3 * 7 /* / 6 * 14 */; break;154case TX4939_CCFG_MULCLK_15:155cpuclk = cpuclk / 2 * 5 /* / 6 * 15 */; break;156}157txx9_cpu_clock = cpuclk;158} else {159if (txx9_cpu_clock == 0)160txx9_cpu_clock = 400000000; /* 400MHz */161/* calculate master_clock from cpu_clock */162cpuclk = txx9_cpu_clock;163divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) &164TX4939_CCFG_MULCLK_MASK;165switch (divmode) {166case TX4939_CCFG_MULCLK_8:167txx9_master_clock = cpuclk * 6 / 8; break;168case TX4939_CCFG_MULCLK_9:169txx9_master_clock = cpuclk * 6 / 9; break;170case TX4939_CCFG_MULCLK_10:171txx9_master_clock = cpuclk * 6 / 10; break;172case TX4939_CCFG_MULCLK_11:173txx9_master_clock = cpuclk * 6 / 11; break;174case TX4939_CCFG_MULCLK_12:175txx9_master_clock = cpuclk * 6 / 12; break;176case TX4939_CCFG_MULCLK_13:177txx9_master_clock = cpuclk * 6 / 13; break;178case TX4939_CCFG_MULCLK_14:179txx9_master_clock = cpuclk * 6 / 14; break;180case TX4939_CCFG_MULCLK_15:181txx9_master_clock = cpuclk * 6 / 15; break;182}183txx9_master_clock /= 10; /* * 2 / 20 */184}185/* calculate gbus_clock from cpu_clock */186divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) &187TX4939_CCFG_YDIVMODE_MASK;188txx9_gbus_clock = txx9_cpu_clock;189switch (divmode) {190case TX4939_CCFG_YDIVMODE_2:191txx9_gbus_clock /= 2; break;192case TX4939_CCFG_YDIVMODE_3:193txx9_gbus_clock /= 3; break;194case TX4939_CCFG_YDIVMODE_5:195txx9_gbus_clock /= 5; break;196case TX4939_CCFG_YDIVMODE_6:197txx9_gbus_clock /= 6; break;198}199/* change default value to udelay/mdelay take reasonable time */200loops_per_jiffy = txx9_cpu_clock / HZ / 2;201202/* CCFG */203tx4939_wdr_init();204/* clear BusErrorOnWrite flag (W1C) */205tx4939_ccfg_set(TX4939_CCFG_WDRST | TX4939_CCFG_BEOW);206/* enable Timeout BusError */207if (txx9_ccfg_toeon)208tx4939_ccfg_set(TX4939_CCFG_TOE);209210/* DMA selection */211txx9_clear64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_DMASEL_ALL);212213/* Use external clock for external arbiter */214if (!(____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCIARB))215txx9_clear64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_PCICLKEN_ALL);216217pr_info("%s -- %dMHz(M%dMHz,G%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",218txx9_pcode_str,219(cpuclk + 500000) / 1000000,220(txx9_master_clock + 500000) / 1000000,221(txx9_gbus_clock + 500000) / 1000000,222(__u32)____raw_readq(&tx4939_ccfgptr->crir),223(unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg),224(unsigned long long)____raw_readq(&tx4939_ccfgptr->pcfg));225226pr_info("%s DDRC -- EN:%08x", txx9_pcode_str,227(__u32)____raw_readq(&tx4939_ddrcptr->winen));228for (i = 0; i < 4; i++) {229__u64 win = ____raw_readq(&tx4939_ddrcptr->win[i]);230if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i)))231continue; /* disabled */232printk(KERN_CONT " #%d:%016llx", i, (unsigned long long)win);233tx4939_sdram_resource[i].name = "DDR SDRAM";234tx4939_sdram_resource[i].start =235(unsigned long)(win >> 48) << 20;236tx4939_sdram_resource[i].end =237((((unsigned long)(win >> 32) & 0xffff) + 1) <<23820) - 1;239tx4939_sdram_resource[i].flags = IORESOURCE_MEM;240request_resource(&iomem_resource, &tx4939_sdram_resource[i]);241}242printk(KERN_CONT "\n");243244/* SRAM */245if (____raw_readq(&tx4939_sramcptr->cr) & 1) {246unsigned int size = TX4939_SRAM_SIZE;247tx4939_sram_resource.name = "SRAM";248tx4939_sram_resource.start =249(____raw_readq(&tx4939_sramcptr->cr) >> (39-11))250& ~(size - 1);251tx4939_sram_resource.end =252tx4939_sram_resource.start + TX4939_SRAM_SIZE - 1;253tx4939_sram_resource.flags = IORESOURCE_MEM;254request_resource(&iomem_resource, &tx4939_sram_resource);255}256257/* TMR */258/* disable all timers */259for (i = 0; i < TX4939_NR_TMR; i++)260txx9_tmr_init(TX4939_TMR_REG(i) & 0xfffffffffULL);261262/* set PCIC1 reset (required to prevent hangup on BIST) */263txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1RST);264pcfg = ____raw_readq(&tx4939_ccfgptr->pcfg);265if (pcfg & (TX4939_PCFG_ET0MODE | TX4939_PCFG_ET1MODE)) {266mdelay(1); /* at least 128 cpu clock */267/* clear PCIC1 reset */268txx9_clear64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1RST);269} else {270pr_info("%s: stop PCIC1\n", txx9_pcode_str);271/* stop PCIC1 */272txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1CKD);273}274if (!(pcfg & TX4939_PCFG_ET0MODE)) {275pr_info("%s: stop ETH0\n", txx9_pcode_str);276txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH0RST);277txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH0CKD);278}279if (!(pcfg & TX4939_PCFG_ET1MODE)) {280pr_info("%s: stop ETH1\n", txx9_pcode_str);281txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH1RST);282txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH1CKD);283}284285_machine_restart = tx4939_machine_restart;286board_be_init = tx4939_be_init;287}288289void __init tx4939_time_init(unsigned int tmrnr)290{291if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_TINTDIS)292txx9_clockevent_init(TX4939_TMR_REG(tmrnr) & 0xfffffffffULL,293TXX9_IRQ_BASE + TX4939_IR_TMR(tmrnr),294TXX9_IMCLK);295}296297void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)298{299int i;300unsigned int ch_mask = 0;301__u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);302303cts_mask |= ~1; /* only SIO0 have RTS/CTS */304if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO0)305cts_mask |= 1 << 0; /* disable SIO0 RTS/CTS by PCFG setting */306if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO2)307ch_mask |= 1 << 2; /* disable SIO2 by PCFG setting */308if (pcfg & TX4939_PCFG_SIO3MODE)309ch_mask |= 1 << 3; /* disable SIO3 by PCFG setting */310for (i = 0; i < 4; i++) {311if ((1 << i) & ch_mask)312continue;313txx9_sio_init(TX4939_SIO_REG(i) & 0xfffffffffULL,314TXX9_IRQ_BASE + TX4939_IR_SIO(i),315i, sclk, (1 << i) & cts_mask);316}317}318319#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)320static u32 tx4939_get_eth_speed(struct net_device *dev)321{322struct ethtool_cmd cmd;323if (dev_ethtool_get_settings(dev, &cmd))324return 100; /* default 100Mbps */325326return ethtool_cmd_speed(&cmd);327}328329static int tx4939_netdev_event(struct notifier_block *this,330unsigned long event,331void *ptr)332{333struct net_device *dev = ptr;334if (event == NETDEV_CHANGE && netif_carrier_ok(dev)) {335__u64 bit = 0;336if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(0))337bit = TX4939_PCFG_SPEED0;338else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1))339bit = TX4939_PCFG_SPEED1;340if (bit) {341if (tx4939_get_eth_speed(dev) == 100)342txx9_set64(&tx4939_ccfgptr->pcfg, bit);343else344txx9_clear64(&tx4939_ccfgptr->pcfg, bit);345}346}347return NOTIFY_DONE;348}349350static struct notifier_block tx4939_netdev_notifier = {351.notifier_call = tx4939_netdev_event,352.priority = 1,353};354355void __init tx4939_ethaddr_init(unsigned char *addr0, unsigned char *addr1)356{357u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);358359if (addr0 && (pcfg & TX4939_PCFG_ET0MODE))360txx9_ethaddr_init(TXX9_IRQ_BASE + TX4939_IR_ETH(0), addr0);361if (addr1 && (pcfg & TX4939_PCFG_ET1MODE))362txx9_ethaddr_init(TXX9_IRQ_BASE + TX4939_IR_ETH(1), addr1);363register_netdevice_notifier(&tx4939_netdev_notifier);364}365#else366void __init tx4939_ethaddr_init(unsigned char *addr0, unsigned char *addr1)367{368}369#endif370371void __init tx4939_mtd_init(int ch)372{373struct physmap_flash_data pdata = {374.width = TX4939_EBUSC_WIDTH(ch) / 8,375};376unsigned long start = txx9_ce_res[ch].start;377unsigned long size = txx9_ce_res[ch].end - start + 1;378379if (!(TX4939_EBUSC_CR(ch) & 0x8))380return; /* disabled */381txx9_physmap_flash_init(ch, start, size, &pdata);382}383384#define TX4939_ATA_REG_PHYS(ch) (TX4939_ATA_REG(ch) & 0xfffffffffULL)385void __init tx4939_ata_init(void)386{387static struct resource ata0_res[] = {388{389.start = TX4939_ATA_REG_PHYS(0),390.end = TX4939_ATA_REG_PHYS(0) + 0x1000 - 1,391.flags = IORESOURCE_MEM,392}, {393.start = TXX9_IRQ_BASE + TX4939_IR_ATA(0),394.flags = IORESOURCE_IRQ,395},396};397static struct resource ata1_res[] = {398{399.start = TX4939_ATA_REG_PHYS(1),400.end = TX4939_ATA_REG_PHYS(1) + 0x1000 - 1,401.flags = IORESOURCE_MEM,402}, {403.start = TXX9_IRQ_BASE + TX4939_IR_ATA(1),404.flags = IORESOURCE_IRQ,405},406};407static struct platform_device ata0_dev = {408.name = "tx4939ide",409.id = 0,410.num_resources = ARRAY_SIZE(ata0_res),411.resource = ata0_res,412};413static struct platform_device ata1_dev = {414.name = "tx4939ide",415.id = 1,416.num_resources = ARRAY_SIZE(ata1_res),417.resource = ata1_res,418};419__u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);420421if (pcfg & TX4939_PCFG_ATA0MODE)422platform_device_register(&ata0_dev);423if ((pcfg & (TX4939_PCFG_ATA1MODE |424TX4939_PCFG_ET1MODE |425TX4939_PCFG_ET0MODE)) == TX4939_PCFG_ATA1MODE)426platform_device_register(&ata1_dev);427}428429void __init tx4939_rtc_init(void)430{431static struct resource res[] = {432{433.start = TX4939_RTC_REG & 0xfffffffffULL,434.end = (TX4939_RTC_REG & 0xfffffffffULL) + 0x100 - 1,435.flags = IORESOURCE_MEM,436}, {437.start = TXX9_IRQ_BASE + TX4939_IR_RTC,438.flags = IORESOURCE_IRQ,439},440};441static struct platform_device rtc_dev = {442.name = "tx4939rtc",443.id = -1,444.num_resources = ARRAY_SIZE(res),445.resource = res,446};447448platform_device_register(&rtc_dev);449}450451void __init tx4939_ndfmc_init(unsigned int hold, unsigned int spw,452unsigned char ch_mask, unsigned char wide_mask)453{454struct txx9ndfmc_platform_data plat_data = {455.shift = 1,456.gbus_clock = txx9_gbus_clock,457.hold = hold,458.spw = spw,459.flags = NDFMC_PLAT_FLAG_NO_RSTR | NDFMC_PLAT_FLAG_HOLDADD |460NDFMC_PLAT_FLAG_DUMMYWRITE,461.ch_mask = ch_mask,462.wide_mask = wide_mask,463};464txx9_ndfmc_init(TX4939_NDFMC_REG & 0xfffffffffULL, &plat_data);465}466467void __init tx4939_dmac_init(int memcpy_chan0, int memcpy_chan1)468{469struct txx9dmac_platform_data plat_data = {470.have_64bit_regs = true,471};472int i;473474for (i = 0; i < 2; i++) {475plat_data.memcpy_chan = i ? memcpy_chan1 : memcpy_chan0;476txx9_dmac_init(i, TX4939_DMA_REG(i) & 0xfffffffffULL,477TXX9_IRQ_BASE + TX4939_IR_DMA(i, 0),478&plat_data);479}480}481482void __init tx4939_aclc_init(void)483{484u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);485486if ((pcfg & TX4939_PCFG_I2SMODE_MASK) == TX4939_PCFG_I2SMODE_ACLC)487txx9_aclc_init(TX4939_ACLC_REG & 0xfffffffffULL,488TXX9_IRQ_BASE + TX4939_IR_ACLC, 1, 0, 1);489}490491void __init tx4939_sramc_init(void)492{493if (tx4939_sram_resource.start)494txx9_sramc_init(&tx4939_sram_resource);495}496497void __init tx4939_rng_init(void)498{499static struct resource res = {500.start = TX4939_RNG_REG & 0xfffffffffULL,501.end = (TX4939_RNG_REG & 0xfffffffffULL) + 0x30 - 1,502.flags = IORESOURCE_MEM,503};504static struct platform_device pdev = {505.name = "tx4939-rng",506.id = -1,507.num_resources = 1,508.resource = &res,509};510511platform_device_register(&pdev);512}513514static void __init tx4939_stop_unused_modules(void)515{516__u64 pcfg, rst = 0, ckd = 0;517char buf[128];518519buf[0] = '\0';520local_irq_disable();521pcfg = ____raw_readq(&tx4939_ccfgptr->pcfg);522if ((pcfg & TX4939_PCFG_I2SMODE_MASK) !=523TX4939_PCFG_I2SMODE_ACLC) {524rst |= TX4939_CLKCTR_ACLRST;525ckd |= TX4939_CLKCTR_ACLCKD;526strcat(buf, " ACLC");527}528if ((pcfg & TX4939_PCFG_I2SMODE_MASK) !=529TX4939_PCFG_I2SMODE_I2S &&530(pcfg & TX4939_PCFG_I2SMODE_MASK) !=531TX4939_PCFG_I2SMODE_I2S_ALT) {532rst |= TX4939_CLKCTR_I2SRST;533ckd |= TX4939_CLKCTR_I2SCKD;534strcat(buf, " I2S");535}536if (!(pcfg & TX4939_PCFG_ATA0MODE)) {537rst |= TX4939_CLKCTR_ATA0RST;538ckd |= TX4939_CLKCTR_ATA0CKD;539strcat(buf, " ATA0");540}541if (!(pcfg & TX4939_PCFG_ATA1MODE)) {542rst |= TX4939_CLKCTR_ATA1RST;543ckd |= TX4939_CLKCTR_ATA1CKD;544strcat(buf, " ATA1");545}546if (pcfg & TX4939_PCFG_SPIMODE) {547rst |= TX4939_CLKCTR_SPIRST;548ckd |= TX4939_CLKCTR_SPICKD;549strcat(buf, " SPI");550}551if (!(pcfg & (TX4939_PCFG_VSSMODE | TX4939_PCFG_VPSMODE))) {552rst |= TX4939_CLKCTR_VPCRST;553ckd |= TX4939_CLKCTR_VPCCKD;554strcat(buf, " VPC");555}556if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO2) {557rst |= TX4939_CLKCTR_SIO2RST;558ckd |= TX4939_CLKCTR_SIO2CKD;559strcat(buf, " SIO2");560}561if (pcfg & TX4939_PCFG_SIO3MODE) {562rst |= TX4939_CLKCTR_SIO3RST;563ckd |= TX4939_CLKCTR_SIO3CKD;564strcat(buf, " SIO3");565}566if (rst | ckd) {567txx9_set64(&tx4939_ccfgptr->clkctr, rst);568txx9_set64(&tx4939_ccfgptr->clkctr, ckd);569}570local_irq_enable();571if (buf[0])572pr_info("%s: stop%s\n", txx9_pcode_str, buf);573}574575static int __init tx4939_late_init(void)576{577if (txx9_pcode != 0x4939)578return -ENODEV;579tx4939_stop_unused_modules();580return 0;581}582late_initcall(tx4939_late_init);583584585