diff options
Diffstat (limited to 'arch/mips/txx9/generic')
-rw-r--r-- | arch/mips/txx9/generic/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/txx9/generic/irq_tx4927.c | 11 | ||||
-rw-r--r-- | arch/mips/txx9/generic/irq_tx4938.c | 11 | ||||
-rw-r--r-- | arch/mips/txx9/generic/irq_tx4939.c | 215 | ||||
-rw-r--r-- | arch/mips/txx9/generic/setup.c | 432 | ||||
-rw-r--r-- | arch/mips/txx9/generic/setup_tx3927.c | 37 | ||||
-rw-r--r-- | arch/mips/txx9/generic/setup_tx4927.c | 97 | ||||
-rw-r--r-- | arch/mips/txx9/generic/setup_tx4938.c | 122 | ||||
-rw-r--r-- | arch/mips/txx9/generic/setup_tx4939.c | 506 | ||||
-rw-r--r-- | arch/mips/txx9/generic/spi_eeprom.c | 103 |
10 files changed, 1505 insertions, 31 deletions
diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile index 9bb34af26b73..0030d23bef5b 100644 --- a/arch/mips/txx9/generic/Makefile +++ b/arch/mips/txx9/generic/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_SOC_TX3927) += setup_tx3927.o irq_tx3927.o obj-$(CONFIG_SOC_TX4927) += mem_tx4927.o setup_tx4927.o irq_tx4927.o obj-$(CONFIG_SOC_TX4938) += mem_tx4927.o setup_tx4938.o irq_tx4938.o +obj-$(CONFIG_SOC_TX4939) += setup_tx4939.o irq_tx4939.o obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o +obj-$(CONFIG_SPI) += spi_eeprom.o EXTRA_CFLAGS += -Werror diff --git a/arch/mips/txx9/generic/irq_tx4927.c b/arch/mips/txx9/generic/irq_tx4927.c index cbea1fdde82b..ad2870def8f1 100644 --- a/arch/mips/txx9/generic/irq_tx4927.c +++ b/arch/mips/txx9/generic/irq_tx4927.c @@ -30,8 +30,19 @@ void __init tx4927_irq_init(void) { + int i; + mips_cpu_irq_init(); txx9_irq_init(TX4927_IRC_REG & 0xfffffffffULL); set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4927_IRC_INT, handle_simple_irq); + /* raise priority for errors, timers, SIO */ + txx9_irq_set_pri(TX4927_IR_ECCERR, 7); + txx9_irq_set_pri(TX4927_IR_WTOERR, 7); + txx9_irq_set_pri(TX4927_IR_PCIERR, 7); + txx9_irq_set_pri(TX4927_IR_PCIPME, 7); + for (i = 0; i < TX4927_NUM_IR_TMR; i++) + txx9_irq_set_pri(TX4927_IR_TMR(i), 6); + for (i = 0; i < TX4927_NUM_IR_SIO; i++) + txx9_irq_set_pri(TX4927_IR_SIO(i), 5); } diff --git a/arch/mips/txx9/generic/irq_tx4938.c b/arch/mips/txx9/generic/irq_tx4938.c index 6eac684bf190..025ae11359a8 100644 --- a/arch/mips/txx9/generic/irq_tx4938.c +++ b/arch/mips/txx9/generic/irq_tx4938.c @@ -18,8 +18,19 @@ void __init tx4938_irq_init(void) { + int i; + mips_cpu_irq_init(); txx9_irq_init(TX4938_IRC_REG & 0xfffffffffULL); set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4938_IRC_INT, handle_simple_irq); + /* raise priority for errors, timers, SIO */ + txx9_irq_set_pri(TX4938_IR_ECCERR, 7); + txx9_irq_set_pri(TX4938_IR_WTOERR, 7); + txx9_irq_set_pri(TX4938_IR_PCIERR, 7); + txx9_irq_set_pri(TX4938_IR_PCIPME, 7); + for (i = 0; i < TX4938_NUM_IR_TMR; i++) + txx9_irq_set_pri(TX4938_IR_TMR(i), 6); + for (i = 0; i < TX4938_NUM_IR_SIO; i++) + txx9_irq_set_pri(TX4938_IR_SIO(i), 5); } diff --git a/arch/mips/txx9/generic/irq_tx4939.c b/arch/mips/txx9/generic/irq_tx4939.c new file mode 100644 index 000000000000..013213a8706b --- /dev/null +++ b/arch/mips/txx9/generic/irq_tx4939.c @@ -0,0 +1,215 @@ +/* + * TX4939 irq routines + * Based on linux/arch/mips/kernel/irq_txx9.c, + * and RBTX49xx patch from CELF patch archive. + * + * Copyright 2001, 2003-2005 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * source@mvista.com + * Copyright (C) 2000-2001,2005-2007 Toshiba Corporation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +/* + * TX4939 defines 64 IRQs. + * Similer to irq_txx9.c but different register layouts. + */ +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/types.h> +#include <asm/irq_cpu.h> +#include <asm/txx9irq.h> +#include <asm/txx9/tx4939.h> + +/* IRCER : Int. Control Enable */ +#define TXx9_IRCER_ICE 0x00000001 + +/* IRCR : Int. Control */ +#define TXx9_IRCR_LOW 0x00000000 +#define TXx9_IRCR_HIGH 0x00000001 +#define TXx9_IRCR_DOWN 0x00000002 +#define TXx9_IRCR_UP 0x00000003 +#define TXx9_IRCR_EDGE(cr) ((cr) & 0x00000002) + +/* IRSCR : Int. Status Control */ +#define TXx9_IRSCR_EIClrE 0x00000100 +#define TXx9_IRSCR_EIClr_MASK 0x0000000f + +/* IRCSR : Int. Current Status */ +#define TXx9_IRCSR_IF 0x00010000 + +#define irc_dlevel 0 +#define irc_elevel 1 + +static struct { + unsigned char level; + unsigned char mode; +} tx4939irq[TX4939_NUM_IR] __read_mostly; + +static void tx4939_irq_unmask(unsigned int irq) +{ + unsigned int irq_nr = irq - TXX9_IRQ_BASE; + u32 __iomem *lvlp; + int ofs; + if (irq_nr < 32) { + irq_nr--; + lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r; + } else { + irq_nr -= 32; + lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r; + } + ofs = (irq_nr & 16) + (irq_nr & 1) * 8; + __raw_writel((__raw_readl(lvlp) & ~(0xff << ofs)) + | (tx4939irq[irq_nr].level << ofs), + lvlp); +} + +static inline void tx4939_irq_mask(unsigned int irq) +{ + unsigned int irq_nr = irq - TXX9_IRQ_BASE; + u32 __iomem *lvlp; + int ofs; + if (irq_nr < 32) { + irq_nr--; + lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r; + } else { + irq_nr -= 32; + lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r; + } + ofs = (irq_nr & 16) + (irq_nr & 1) * 8; + __raw_writel((__raw_readl(lvlp) & ~(0xff << ofs)) + | (irc_dlevel << ofs), + lvlp); + mmiowb(); +} + +static void tx4939_irq_mask_ack(unsigned int irq) +{ + unsigned int irq_nr = irq - TXX9_IRQ_BASE; + + tx4939_irq_mask(irq); + if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) { + irq_nr--; + /* clear edge detection */ + __raw_writel((TXx9_IRSCR_EIClrE | (irq_nr & 0xf)) + << (irq_nr & 0x10), + &tx4939_ircptr->edc.r); + } +} + +static int tx4939_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + unsigned int irq_nr = irq - TXX9_IRQ_BASE; + u32 cr; + u32 __iomem *crp; + int ofs; + int mode; + + if (flow_type & IRQF_TRIGGER_PROBE) + return 0; + switch (flow_type & IRQF_TRIGGER_MASK) { + case IRQF_TRIGGER_RISING: + mode = TXx9_IRCR_UP; + break; + case IRQF_TRIGGER_FALLING: + mode = TXx9_IRCR_DOWN; + break; + case IRQF_TRIGGER_HIGH: + mode = TXx9_IRCR_HIGH; + break; + case IRQF_TRIGGER_LOW: + mode = TXx9_IRCR_LOW; + break; + default: + return -EINVAL; + } + if (irq_nr < 32) { + irq_nr--; + crp = &tx4939_ircptr->dm[(irq_nr & 8) >> 3].r; + } else { + irq_nr -= 32; + crp = &tx4939_ircptr->dm2[((irq_nr & 8) >> 3)].r; + } + ofs = (((irq_nr & 16) >> 1) | (irq_nr & (8 - 1))) * 2; + cr = __raw_readl(crp); + cr &= ~(0x3 << ofs); + cr |= (mode & 0x3) << ofs; + __raw_writel(cr, crp); + tx4939irq[irq_nr].mode = mode; + return 0; +} + +static struct irq_chip tx4939_irq_chip = { + .name = "TX4939", + .ack = tx4939_irq_mask_ack, + .mask = tx4939_irq_mask, + .mask_ack = tx4939_irq_mask_ack, + .unmask = tx4939_irq_unmask, + .set_type = tx4939_irq_set_type, +}; + +static int tx4939_irq_set_pri(int irc_irq, int new_pri) +{ + int old_pri; + + if ((unsigned int)irc_irq >= TX4939_NUM_IR) + return 0; + old_pri = tx4939irq[irc_irq].level; + tx4939irq[irc_irq].level = new_pri; + return old_pri; +} + +void __init tx4939_irq_init(void) +{ + int i; + + mips_cpu_irq_init(); + /* disable interrupt control */ + __raw_writel(0, &tx4939_ircptr->den.r); + __raw_writel(0, &tx4939_ircptr->maskint.r); + __raw_writel(0, &tx4939_ircptr->maskext.r); + /* irq_base + 0 is not used */ + for (i = 1; i < TX4939_NUM_IR; i++) { + tx4939irq[i].level = 4; /* middle level */ + tx4939irq[i].mode = TXx9_IRCR_LOW; + set_irq_chip_and_handler(TXX9_IRQ_BASE + i, + &tx4939_irq_chip, handle_level_irq); + } + + /* mask all IRC interrupts */ + __raw_writel(0, &tx4939_ircptr->msk.r); + for (i = 0; i < 16; i++) + __raw_writel(0, &tx4939_ircptr->lvl[i].r); + /* setup IRC interrupt mode (Low Active) */ + for (i = 0; i < 2; i++) + __raw_writel(0, &tx4939_ircptr->dm[i].r); + for (i = 0; i < 2; i++) + __raw_writel(0, &tx4939_ircptr->dm2[i].r); + /* enable interrupt control */ + __raw_writel(TXx9_IRCER_ICE, &tx4939_ircptr->den.r); + __raw_writel(irc_elevel, &tx4939_ircptr->msk.r); + + set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4939_IRC_INT, + handle_simple_irq); + + /* raise priority for errors, timers, sio */ + tx4939_irq_set_pri(TX4939_IR_WTOERR, 7); + tx4939_irq_set_pri(TX4939_IR_PCIERR, 7); + tx4939_irq_set_pri(TX4939_IR_PCIPME, 7); + for (i = 0; i < TX4939_NUM_IR_TMR; i++) + tx4939_irq_set_pri(TX4939_IR_TMR(i), 6); + for (i = 0; i < TX4939_NUM_IR_SIO; i++) + tx4939_irq_set_pri(TX4939_IR_SIO(i), 5); +} + +int tx4939_irq(void) +{ + u32 csr = __raw_readl(&tx4939_ircptr->cs.r); + + if (likely(!(csr & TXx9_IRCSR_IF))) + return TXX9_IRQ_BASE + (csr & (TX4939_NUM_IR - 1)); + return -1; +} diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 0afe94c48fb6..5526375010f8 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -22,11 +22,16 @@ #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/serial_core.h> +#include <linux/mtd/physmap.h> +#include <linux/leds.h> #include <asm/bootinfo.h> #include <asm/time.h> #include <asm/reboot.h> +#include <asm/r4kcache.h> +#include <asm/sections.h> #include <asm/txx9/generic.h> #include <asm/txx9/pci.h> +#include <asm/txx9tmr.h> #ifdef CONFIG_CPU_TX49XX #include <asm/txx9/tx4938.h> #endif @@ -53,6 +58,7 @@ txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size) txx9_ce_res[i].name = txx9_ce_res_name[i]; } + txx9_pcode = pcode; sprintf(txx9_pcode_str, "TX%x", pcode); if (base) { txx9_reg_res.start = base & 0xfffffffffULL; @@ -66,7 +72,12 @@ unsigned int txx9_master_clock; unsigned int txx9_cpu_clock; unsigned int txx9_gbus_clock; +#ifdef CONFIG_CPU_TX39XX +/* don't enable by default - see errata */ +int txx9_ccfg_toeon __initdata; +#else int txx9_ccfg_toeon __initdata = 1; +#endif /* Minimum CLK support */ @@ -118,39 +129,232 @@ int irq_to_gpio(unsigned irq) EXPORT_SYMBOL(irq_to_gpio); #endif -extern struct txx9_board_vec jmr3927_vec; -extern struct txx9_board_vec rbtx4927_vec; -extern struct txx9_board_vec rbtx4937_vec; -extern struct txx9_board_vec rbtx4938_vec; +#define BOARD_VEC(board) extern struct txx9_board_vec board; +#include <asm/txx9/boards.h> +#undef BOARD_VEC struct txx9_board_vec *txx9_board_vec __initdata; static char txx9_system_type[32]; -void __init prom_init_cmdline(void) +static struct txx9_board_vec *board_vecs[] __initdata = { +#define BOARD_VEC(board) &board, +#include <asm/txx9/boards.h> +#undef BOARD_VEC +}; + +static struct txx9_board_vec *__init find_board_byname(const char *name) +{ + int i; + + /* search board_vecs table */ + for (i = 0; i < ARRAY_SIZE(board_vecs); i++) { + if (strstr(board_vecs[i]->system, name)) + return board_vecs[i]; + } + return NULL; +} + +static void __init prom_init_cmdline(void) { int argc = (int)fw_arg0; - char **argv = (char **)fw_arg1; + int *argv32 = (int *)fw_arg1; int i; /* Always ignore the "-c" at argv[0] */ -#ifdef CONFIG_64BIT - char *fixed_argv[32]; - for (i = 0; i < argc; i++) - fixed_argv[i] = (char *)(long)(*((__s32 *)argv + i)); - argv = fixed_argv; -#endif + char builtin[CL_SIZE]; /* ignore all built-in args if any f/w args given */ - if (argc > 1) - *arcs_cmdline = '\0'; + /* + * But if built-in strings was started with '+', append them + * to command line args. If built-in was started with '-', + * ignore all f/w args. + */ + builtin[0] = '\0'; + if (arcs_cmdline[0] == '+') + strcpy(builtin, arcs_cmdline + 1); + else if (arcs_cmdline[0] == '-') { + strcpy(builtin, arcs_cmdline + 1); + argc = 0; + } else if (argc <= 1) + strcpy(builtin, arcs_cmdline); + arcs_cmdline[0] = '\0'; for (i = 1; i < argc; i++) { + char *str = (char *)(long)argv32[i]; if (i != 1) strcat(arcs_cmdline, " "); - strcat(arcs_cmdline, argv[i]); + if (strchr(str, ' ')) { + strcat(arcs_cmdline, "\""); + strcat(arcs_cmdline, str); + strcat(arcs_cmdline, "\""); + } else + strcat(arcs_cmdline, str); + } + /* append saved builtin args */ + if (builtin[0]) { + if (arcs_cmdline[0]) + strcat(arcs_cmdline, " "); + strcat(arcs_cmdline, builtin); } } -void __init prom_init(void) +static int txx9_ic_disable __initdata; +static int txx9_dc_disable __initdata; + +#if defined(CONFIG_CPU_TX49XX) +/* flush all cache on very early stage (before 4k_cache_init) */ +static void __init early_flush_dcache(void) { + unsigned int conf = read_c0_config(); + unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6)); + unsigned int linesz = 32; + unsigned long addr, end; + + end = INDEX_BASE + dc_size / 4; + /* 4way, waybit=0 */ + for (addr = INDEX_BASE; addr < end; addr += linesz) { + cache_op(Index_Writeback_Inv_D, addr | 0); + cache_op(Index_Writeback_Inv_D, addr | 1); + cache_op(Index_Writeback_Inv_D, addr | 2); + cache_op(Index_Writeback_Inv_D, addr | 3); + } +} + +static void __init txx9_cache_fixup(void) +{ + unsigned int conf; + + conf = read_c0_config(); + /* flush and disable */ + if (txx9_ic_disable) { + conf |= TX49_CONF_IC; + write_c0_config(conf); + } + if (txx9_dc_disable) { + early_flush_dcache(); + conf |= TX49_CONF_DC; + write_c0_config(conf); + } + + /* enable cache */ + conf = read_c0_config(); + if (!txx9_ic_disable) + conf &= ~TX49_CONF_IC; + if (!txx9_dc_disable) + conf &= ~TX49_CONF_DC; + write_c0_config(conf); + + if (conf & TX49_CONF_IC) + pr_info("TX49XX I-Cache disabled.\n"); + if (conf & TX49_CONF_DC) + pr_info("TX49XX D-Cache disabled.\n"); +} +#elif defined(CONFIG_CPU_TX39XX) +/* flush all cache on very early stage (before tx39_cache_init) */ +static void __init early_flush_dcache(void) +{ + unsigned int conf = read_c0_config(); + unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >> + TX39_CONF_DCS_SHIFT)); + unsigned int linesz = 16; + unsigned long addr, end; + + end = INDEX_BASE + dc_size / 2; + /* 2way, waybit=0 */ + for (addr = INDEX_BASE; addr < end; addr += linesz) { + cache_op(Index_Writeback_Inv_D, addr | 0); + cache_op(Index_Writeback_Inv_D, addr | 1); + } +} + +static void __init txx9_cache_fixup(void) +{ + unsigned int conf; + + conf = read_c0_config(); + /* flush and disable */ + if (txx9_ic_disable) { + conf &= ~TX39_CONF_ICE; + write_c0_config(conf); + } + if (txx9_dc_disable) { + early_flush_dcache(); + conf &= ~TX39_CONF_DCE; + write_c0_config(conf); + } + + /* enable cache */ + conf = read_c0_config(); + if (!txx9_ic_disable) + conf |= TX39_CONF_ICE; + if (!txx9_dc_disable) + conf |= TX39_CONF_DCE; + write_c0_config(conf); + + if (!(conf & TX39_CONF_ICE)) + pr_info("TX39XX I-Cache disabled.\n"); + if (!(conf & TX39_CONF_DCE)) + pr_info("TX39XX D-Cache disabled.\n"); +} +#else +static inline void txx9_cache_fixup(void) +{ +} +#endif + +static void __init preprocess_cmdline(void) +{ + char cmdline[CL_SIZE]; + char *s; + + strcpy(cmdline, arcs_cmdline); + s = cmdline; + arcs_cmdline[0] = '\0'; + while (s && *s) { + char *str = strsep(&s, " "); + if (strncmp(str, "board=", 6) == 0) { + txx9_board_vec = find_board_byname(str + 6); + continue; + } else if (strncmp(str, "masterclk=", 10) == 0) { + unsigned long val; + if (strict_strtoul(str + 10, 10, &val) == 0) + txx9_master_clock = val; + continue; + } else if (strcmp(str, "icdisable") == 0) { + txx9_ic_disable = 1; + continue; + } else if (strcmp(str, "dcdisable") == 0) { + txx9_dc_disable = 1; + continue; + } else if (strcmp(str, "toeoff") == 0) { + txx9_ccfg_toeon = 0; + continue; + } else if (strcmp(str, "toeon") == 0) { + txx9_ccfg_toeon = 1; + continue; + } + if (arcs_cmdline[0]) + strcat(arcs_cmdline, " "); + strcat(arcs_cmdline, str); + } + + txx9_cache_fixup(); +} + +static void __init select_board(void) +{ + const char *envstr; + + /* first, determine by "board=" argument in preprocess_cmdline() */ + if (txx9_board_vec) + return; + /* next, determine by "board" envvar */ + envstr = prom_getenv("board"); + if (envstr) { + txx9_board_vec = find_board_byname(envstr); + if (txx9_board_vec) + return; + } + + /* select "default" board */ #ifdef CONFIG_CPU_TX39XX txx9_board_vec = &jmr3927_vec; #endif @@ -169,8 +373,20 @@ void __init prom_init(void) txx9_board_vec = &rbtx4938_vec; break; #endif +#ifdef CONFIG_TOSHIBA_RBTX4939 + case 0x4939: + txx9_board_vec = &rbtx4939_vec; + break; +#endif } #endif +} + +void __init prom_init(void) +{ + prom_init_cmdline(); + preprocess_cmdline(); + select_board(); strcpy(txx9_system_type, txx9_board_vec->system); @@ -179,6 +395,11 @@ void __init prom_init(void) void __init prom_free_prom_memory(void) { + unsigned long saddr = PAGE_SIZE; + unsigned long eaddr = __pa_symbol(&_text); + + if (saddr < eaddr) + free_init_pages("prom memory", saddr, eaddr); } const char *get_system_type(void) @@ -191,6 +412,21 @@ char * __init prom_getcmdline(void) return &(arcs_cmdline[0]); } +const char *__init prom_getenv(const char *name) +{ + const s32 *str = (const s32 *)fw_arg2; + + if (!str) + return NULL; + /* YAMON style ("name", "value" pairs) */ + while (str[0] && str[1]) { + if (!strcmp((const char *)(unsigned long)str[0], name)) + return (const char *)(unsigned long)str[1]; + str += 2; + } + return NULL; +} + static void __noreturn txx9_machine_halt(void) { local_irq_disable(); @@ -221,6 +457,20 @@ void __init txx9_wdt_init(unsigned long base) platform_device_register_simple("txx9wdt", -1, &res, 1); } +void txx9_wdt_now(unsigned long base) +{ + struct txx9_tmr_reg __iomem *tmrptr = + ioremap(base, sizeof(struct txx9_tmr_reg)); + /* disable watch dog timer */ + __raw_writel(TXx9_TMWTMR_WDIS | TXx9_TMWTMR_TWC, &tmrptr->wtmr); + __raw_writel(0, &tmrptr->tcr); + /* kick watchdog */ + __raw_writel(TXx9_TMWTMR_TWIE, &tmrptr->wtmr); + __raw_writel(1, &tmrptr->cpra); /* immediate */ + __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, + &tmrptr->tcr); +} + /* SPI support */ void __init txx9_spi_init(int busid, unsigned long base, int irq) { @@ -371,3 +621,153 @@ static unsigned long __swizzle_addr_none(unsigned long port) unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none; EXPORT_SYMBOL(__swizzle_addr_b); #endif + +void __init txx9_physmap_flash_init(int no, unsigned long addr, + unsigned long size, + const struct physmap_flash_data *pdata) +{ +#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE) + struct resource res = { + .start = addr, + .end = addr + size - 1, + .flags = IORESOURCE_MEM, + }; + struct platform_device *pdev; +#ifdef CONFIG_MTD_PARTITIONS + static struct mtd_partition parts[2]; + struct physmap_flash_data pdata_part; + + /* If this area contained boot area, make separate partition */ + if (pdata->nr_parts == 0 && !pdata->parts && + addr < 0x1fc00000 && addr + size > 0x1fc00000 && + !parts[0].name) { + parts[0].name = "boot"; + parts[0].offset = 0x1fc00000 - addr; + parts[0].size = addr + size - 0x1fc00000; + parts[1].name = "user"; + parts[1].offset = 0; + parts[1].size = 0x1fc00000 - addr; + pdata_part = *pdata; + pdata_part.nr_parts = ARRAY_SIZE(parts); + pdata_part.parts = parts; + pdata = &pdata_part; + } +#endif + pdev = platform_device_alloc("physmap-flash", no); + if (!pdev || + platform_device_add_resources(pdev, &res, 1) || + platform_device_add_data(pdev, pdata, sizeof(*pdata)) || + platform_device_add(pdev)) + platform_device_put(pdev); +#endif +} + +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +static DEFINE_SPINLOCK(txx9_iocled_lock); + +#define TXX9_IOCLED_MAXLEDS 8 + +struct txx9_iocled_data { + struct gpio_chip chip; + u8 cur_val; + void __iomem *mmioaddr; + struct gpio_led_platform_data pdata; + struct gpio_led leds[TXX9_IOCLED_MAXLEDS]; + char names[TXX9_IOCLED_MAXLEDS][32]; +}; + +static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset) +{ + struct txx9_iocled_data *data = + container_of(chip, struct txx9_iocled_data, chip); + return data->cur_val & (1 << offset); +} + +static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct txx9_iocled_data *data = + container_of(chip, struct txx9_iocled_data, chip); + unsigned long flags; + spin_lock_irqsave(&txx9_iocled_lock, flags); + if (value) + data->cur_val |= 1 << offset; + else + data->cur_val &= ~(1 << offset); + writeb(data->cur_val, data->mmioaddr); + mmiowb(); + spin_unlock_irqrestore(&txx9_iocled_lock, flags); +} + +static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset) +{ + return 0; +} + +static int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset, + int value) +{ + txx9_iocled_set(chip, offset, value); + return 0; +} + +void __init txx9_iocled_init(unsigned long baseaddr, + int basenum, unsigned int num, int lowactive, + const char *color, char **deftriggers) +{ + struct txx9_iocled_data *iocled; + struct platform_device *pdev; + int i; + static char *default_triggers[] __initdata = { + "heartbeat", + "ide-disk", + "nand-disk", + NULL, + }; + + if (!deftriggers) + deftriggers = default_triggers; + iocled = kzalloc(sizeof(*iocled), GFP_KERNEL); + if (!iocled) + return; + iocled->mmioaddr = ioremap(baseaddr, 1); + if (!iocled->mmioaddr) + return; + iocled->chip.get = txx9_iocled_get; + iocled->chip.set = txx9_iocled_set; + iocled->chip.direction_input = txx9_iocled_dir_in; + iocled->chip.direction_output = txx9_iocled_dir_out; + iocled->chip.label = "iocled"; + iocled->chip.base = basenum; + iocled->chip.ngpio = num; + if (gpiochip_add(&iocled->chip)) + return; + if (basenum < 0) + basenum = iocled->chip.base; + + pdev = platform_device_alloc("leds-gpio", basenum); + if (!pdev) + return; + iocled->pdata.num_leds = num; + iocled->pdata.leds = iocled->leds; + for (i = 0; i < num; i++) { + struct gpio_led *led = &iocled->leds[i]; + snprintf(iocled->names[i], sizeof(iocled->names[i]), + "iocled:%s:%u", color, i); + led->name = iocled->names[i]; + led->gpio = basenum + i; + led->active_low = lowactive; + if (deftriggers && *deftriggers) + led->default_trigger = *deftriggers++; + } + pdev->dev.platform_data = &iocled->pdata; + if (platform_device_add(pdev)) + platform_device_put(pdev); +} +#else /* CONFIG_LEDS_GPIO */ +void __init txx9_iocled_init(unsigned long baseaddr, + int basenum, unsigned int num, int lowactive, + const char *color, char **deftriggers) +{ +} +#endif /* CONFIG_LEDS_GPIO */ diff --git a/arch/mips/txx9/generic/setup_tx3927.c b/arch/mips/txx9/generic/setup_tx3927.c index 7bd963d37fc3..9505d58454c8 100644 --- a/arch/mips/txx9/generic/setup_tx3927.c +++ b/arch/mips/txx9/generic/setup_tx3927.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <linux/param.h> #include <linux/io.h> +#include <linux/mtd/physmap.h> #include <asm/mipsregs.h> #include <asm/txx9irq.h> #include <asm/txx9tmr.h> @@ -32,11 +33,6 @@ void __init tx3927_setup(void) int i; unsigned int conf; - /* don't enable - see errata */ - txx9_ccfg_toeon = 0; - if (strstr(prom_getcmdline(), "toeon") != NULL) - txx9_ccfg_toeon = 1; - txx9_reg_res_init(TX3927_REV_PCODE(), TX3927_REG_BASE, TX3927_REG_SIZE); @@ -99,16 +95,14 @@ void __init tx3927_setup(void) txx9_gpio_init(TX3927_PIO_REG, 0, 16); conf = read_c0_conf(); - if (!(conf & TX39_CONF_ICE)) - printk(KERN_INFO "TX3927 I-Cache disabled.\n"); - if (!(conf & TX39_CONF_DCE)) - printk(KERN_INFO "TX3927 D-Cache disabled.\n"); - else if (!(conf & TX39_CONF_WBON)) - printk(KERN_INFO "TX3927 D-Cache WriteThrough.\n"); - else if (!(conf & TX39_CONF_CWFON)) - printk(KERN_INFO "TX3927 D-Cache WriteBack.\n"); - else - printk(KERN_INFO "TX3927 D-Cache WriteBack (CWF) .\n"); + if (conf & TX39_CONF_DCE) { + if (!(conf & TX39_CONF_WBON)) + pr_info("TX3927 D-Cache WriteThrough.\n"); + else if (!(conf & TX39_CONF_CWFON)) + pr_info("TX3927 D-Cache WriteBack.\n"); + else + pr_info("TX3927 D-Cache WriteBack (CWF) .\n"); + } } void __init tx3927_time_init(unsigned int evt_tmrnr, unsigned int src_tmrnr) @@ -128,3 +122,16 @@ void __init tx3927_sio_init(unsigned int sclk, unsigned int cts_mask) TXX9_IRQ_BASE + TX3927_IR_SIO(i), i, sclk, (1 << i) & cts_mask); } + +void __init tx3927_mtd_init(int ch) +{ + struct physmap_flash_data pdata = { + .width = TX3927_ROMC_WIDTH(ch) / 8, + }; + unsigned long start = txx9_ce_res[ch].start; + unsigned long size = txx9_ce_res[ch].end - start + 1; + + if (!(tx3927_romcptr->cr[ch] & 0x8)) + return; /* disabled */ + txx9_physmap_flash_init(ch, start, size, &pdata); +} diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c index f80d4b7a694d..914e93c62639 100644 --- a/arch/mips/txx9/generic/setup_tx4927.c +++ b/arch/mips/txx9/generic/setup_tx4927.c @@ -14,6 +14,10 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/param.h> +#include <linux/ptrace.h> +#include <linux/mtd/physmap.h> +#include <asm/reboot.h> +#include <asm/traps.h> #include <asm/txx9irq.h> #include <asm/txx9tmr.h> #include <asm/txx9pio.h> @@ -22,6 +26,10 @@ static void __init tx4927_wdr_init(void) { + /* report watchdog reset status */ + if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDRST) + pr_warning("Watchdog reset detected at 0x%lx\n", + read_c0_errorepc()); /* clear WatchDogReset (W1C) */ tx4927_ccfg_set(TX4927_CCFG_WDRST); /* do reset on watchdog */ @@ -33,6 +41,47 @@ void __init tx4927_wdt_init(void) txx9_wdt_init(TX4927_TMR_REG(2) & 0xfffffffffULL); } +static void tx4927_machine_restart(char *command) +{ + local_irq_disable(); + pr_emerg("Rebooting (with %s watchdog reset)...\n", + (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDREXEN) ? + "external" : "internal"); + /* clear watchdog status */ + tx4927_ccfg_set(TX4927_CCFG_WDRST); /* W1C */ + txx9_wdt_now(TX4927_TMR_REG(2) & 0xfffffffffULL); + while (!(____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDRST)) + ; + mdelay(10); + if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDREXEN) { + pr_emerg("Rebooting (with internal watchdog reset)...\n"); + /* External WDRST failed. Do internal watchdog reset */ + tx4927_ccfg_clear(TX4927_CCFG_WDREXEN); + } + /* fallback */ + (*_machine_halt)(); +} + +void show_registers(struct pt_regs *regs); +static int tx4927_be_handler(struct pt_regs *regs, int is_fixup) +{ + int data = regs->cp0_cause & 4; + console_verbose(); + pr_err("%cBE exception at %#lx\n", data ? 'D' : 'I', regs->cp0_epc); + pr_err("ccfg:%llx, toea:%llx\n", + (unsigned long long)____raw_readq(&tx4927_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4927_ccfgptr->toea)); +#ifdef CONFIG_PCI + tx4927_report_pcic_status(); +#endif + show_registers(regs); + panic("BusError!"); +} +static void __init tx4927_be_init(void) +{ + board_be_handler = tx4927_be_handler; +} + static struct resource tx4927_sdram_resource[4]; void __init tx4927_setup(void) @@ -44,6 +93,7 @@ void __init tx4927_setup(void) txx9_reg_res_init(TX4927_REV_PCODE(), TX4927_REG_BASE, TX4927_REG_SIZE); + set_c0_config(TX49_CONF_CWFON); /* SDRAMC,EBUSC are configured by PROM */ for (i = 0; i < 8; i++) { @@ -167,6 +217,9 @@ void __init tx4927_setup(void) txx9_gpio_init(TX4927_PIO_REG & 0xfffffffffULL, 0, TX4927_NUM_PIO); __raw_writel(0, &tx4927_pioptr->maskcpu); __raw_writel(0, &tx4927_pioptr->maskext); + + _machine_restart = tx4927_machine_restart; + board_be_init = tx4927_be_init; } void __init tx4927_time_init(unsigned int tmrnr) @@ -186,3 +239,47 @@ void __init tx4927_sio_init(unsigned int sclk, unsigned int cts_mask) TXX9_IRQ_BASE + TX4927_IR_SIO(i), i, sclk, (1 << i) & cts_mask); } + +void __init tx4927_mtd_init(int ch) +{ + struct physmap_flash_data pdata = { + .width = TX4927_EBUSC_WIDTH(ch) / 8, + }; + unsigned long start = txx9_ce_res[ch].start; + unsigned long size = txx9_ce_res[ch].end - start + 1; + + if (!(TX4927_EBUSC_CR(ch) & 0x8)) + return; /* disabled */ + txx9_physmap_flash_init(ch, start, size, &pdata); +} + +static void __init tx4927_stop_unused_modules(void) +{ + __u64 pcfg, rst = 0, ckd = 0; + char buf[128]; + + buf[0] = '\0'; + local_irq_disable(); + pcfg = ____raw_readq(&tx4927_ccfgptr->pcfg); + if (!(pcfg & TX4927_PCFG_SEL2)) { + rst |= TX4927_CLKCTR_ACLRST; + ckd |= TX4927_CLKCTR_ACLCKD; + strcat(buf, " ACLC"); + } + if (rst | ckd) { + txx9_set64(&tx4927_ccfgptr->clkctr, rst); + txx9_set64(&tx4927_ccfgptr->clkctr, ckd); + } + local_irq_enable(); + if (buf[0]) + pr_info("%s: stop%s\n", txx9_pcode_str, buf); +} + +static int __init tx4927_late_init(void) +{ + if (txx9_pcode != 0x4927) + return -ENODEV; + tx4927_stop_unused_modules(); + return 0; +} +late_initcall(tx4927_late_init); diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c index f3040b9ba059..af724e53ef91 100644 --- a/arch/mips/txx9/generic/setup_tx4938.c +++ b/arch/mips/txx9/generic/setup_tx4938.c @@ -14,6 +14,10 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/param.h> +#include <linux/ptrace.h> +#include <linux/mtd/physmap.h> +#include <asm/reboot.h> +#include <asm/traps.h> #include <asm/txx9irq.h> #include <asm/txx9tmr.h> #include <asm/txx9pio.h> @@ -22,6 +26,10 @@ static void __init tx4938_wdr_init(void) { + /* report watchdog reset status */ + if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST) + pr_warning("Watchdog reset detected at 0x%lx\n", + read_c0_errorepc()); /* clear WatchDogReset (W1C) */ tx4938_ccfg_set(TX4938_CCFG_WDRST); /* do reset on watchdog */ @@ -33,6 +41,47 @@ void __init tx4938_wdt_init(void) txx9_wdt_init(TX4938_TMR_REG(2) & 0xfffffffffULL); } +static void tx4938_machine_restart(char *command) +{ + local_irq_disable(); + pr_emerg("Rebooting (with %s watchdog reset)...\n", + (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) ? + "external" : "internal"); + /* clear watchdog status */ + tx4938_ccfg_set(TX4938_CCFG_WDRST); /* W1C */ + txx9_wdt_now(TX4938_TMR_REG(2) & 0xfffffffffULL); + while (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST)) + ; + mdelay(10); + if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) { + pr_emerg("Rebooting (with internal watchdog reset)...\n"); + /* External WDRST failed. Do internal watchdog reset */ + tx4938_ccfg_clear(TX4938_CCFG_WDREXEN); + } + /* fallback */ + (*_machine_halt)(); +} + +void show_registers(struct pt_regs *regs); +static int tx4938_be_handler(struct pt_regs *regs, int is_fixup) +{ + int data = regs->cp0_cause & 4; + console_verbose(); + pr_err("%cBE exception at %#lx\n", data ? 'D' : 'I', regs->cp0_epc); + pr_err("ccfg:%llx, toea:%llx\n", + (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4938_ccfgptr->toea)); +#ifdef CONFIG_PCI + tx4927_report_pcic_status(); +#endif + show_registers(regs); + panic("BusError!"); +} +static void __init tx4938_be_init(void) +{ + board_be_handler = tx4938_be_handler; +} + static struct resource tx4938_sdram_resource[4]; static struct resource tx4938_sram_resource; @@ -47,6 +96,7 @@ void __init tx4938_setup(void) txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE, TX4938_REG_SIZE); + set_c0_config(TX49_CONF_CWFON); /* SDRAMC,EBUSC are configured by PROM */ for (i = 0; i < 8; i++) { @@ -227,6 +277,9 @@ void __init tx4938_setup(void) TX4938_CLKCTR_ETH1CKD); } } + + _machine_restart = tx4938_machine_restart; + board_be_init = tx4938_be_init; } void __init tx4938_time_init(unsigned int tmrnr) @@ -268,3 +321,72 @@ void __init tx4938_ethaddr_init(unsigned char *addr0, unsigned char *addr1) if (addr1 && (pcfg & TX4938_PCFG_ETH1_SEL)) txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH1, addr1); } + +void __init tx4938_mtd_init(int ch) +{ + struct physmap_flash_data pdata = { + .width = TX4938_EBUSC_WIDTH(ch) / 8, + }; + unsigned long start = txx9_ce_res[ch].start; + unsigned long size = txx9_ce_res[ch].end - start + 1; + + if (!(TX4938_EBUSC_CR(ch) & 0x8)) + return; /* disabled */ + txx9_physmap_flash_init(ch, start, size, &pdata); +} + +static void __init tx4938_stop_unused_modules(void) +{ + __u64 pcfg, rst = 0, ckd = 0; + char buf[128]; + + buf[0] = '\0'; + local_irq_disable(); + pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg); + switch (txx9_pcode) { + case 0x4937: + if (!(pcfg & TX4938_PCFG_SEL2)) { + rst |= TX4938_CLKCTR_ACLRST; + ckd |= TX4938_CLKCTR_ACLCKD; + strcat(buf, " ACLC"); + } + break; + case 0x4938: + if (!(pcfg & TX4938_PCFG_SEL2) || + (pcfg & TX4938_PCFG_ETH0_SEL)) { + rst |= TX4938_CLKCTR_ACLRST; + ckd |= TX4938_CLKCTR_ACLCKD; + strcat(buf, " ACLC"); + } + if ((pcfg & + (TX4938_PCFG_ATA_SEL | TX4938_PCFG_ISA_SEL | + TX4938_PCFG_NDF_SEL)) + != TX4938_PCFG_NDF_SEL) { + rst |= TX4938_CLKCTR_NDFRST; + ckd |= TX4938_CLKCTR_NDFCKD; + strcat(buf, " NDFMC"); + } + if (!(pcfg & TX4938_PCFG_SPI_SEL)) { + rst |= TX4938_CLKCTR_SPIRST; + ckd |= TX4938_CLKCTR_SPICKD; + strcat(buf, " SPI"); + } + break; + } + if (rst | ckd) { + txx9_set64(&tx4938_ccfgptr->clkctr, rst); + txx9_set64(&tx4938_ccfgptr->clkctr, ckd); + } + local_irq_enable(); + if (buf[0]) + pr_info("%s: stop%s\n", txx9_pcode_str, buf); +} + +static int __init tx4938_late_init(void) +{ + if (txx9_pcode != 0x4937 && txx9_pcode != 0x4938) + return -ENODEV; + tx4938_stop_unused_modules(); + return 0; +} +late_initcall(tx4938_late_init); diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c new file mode 100644 index 000000000000..6c0049a5bbc1 --- /dev/null +++ b/arch/mips/txx9/generic/setup_tx4939.c @@ -0,0 +1,506 @@ +/* + * TX4939 setup routines + * Based on linux/arch/mips/txx9/generic/setup_tx4938.c, + * and RBTX49xx patch from CELF patch archive. + * + * 2003-2005 (c) MontaVista Software, Inc. + * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/notifier.h> +#include <linux/sysdev.h> +#include <linux/ethtool.h> +#include <linux/param.h> +#include <linux/ptrace.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <asm/bootinfo.h> +#include <asm/reboot.h> +#include <asm/traps.h> +#include <asm/txx9irq.h> +#include <asm/txx9tmr.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/tx4939.h> + +static void __init tx4939_wdr_init(void) +{ + /* report watchdog reset status */ + if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDRST) + pr_warning("Watchdog reset detected at 0x%lx\n", + read_c0_errorepc()); + /* clear WatchDogReset (W1C) */ + tx4939_ccfg_set(TX4939_CCFG_WDRST); + /* do reset on watchdog */ + tx4939_ccfg_set(TX4939_CCFG_WR); +} + +void __init tx4939_wdt_init(void) +{ + txx9_wdt_init(TX4939_TMR_REG(2) & 0xfffffffffULL); +} + +static void tx4939_machine_restart(char *command) +{ + local_irq_disable(); + pr_emerg("Rebooting (with %s watchdog reset)...\n", + (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDREXEN) ? + "external" : "internal"); + /* clear watchdog status */ + tx4939_ccfg_set(TX4939_CCFG_WDRST); /* W1C */ + txx9_wdt_now(TX4939_TMR_REG(2) & 0xfffffffffULL); + while (!(____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDRST)) + ; + mdelay(10); + if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDREXEN) { + pr_emerg("Rebooting (with internal watchdog reset)...\n"); + /* External WDRST failed. Do internal watchdog reset */ + tx4939_ccfg_clear(TX4939_CCFG_WDREXEN); + } + /* fallback */ + (*_machine_halt)(); +} + +void show_registers(struct pt_regs *regs); +static int tx4939_be_handler(struct pt_regs *regs, int is_fixup) +{ + int data = regs->cp0_cause & 4; + console_verbose(); + pr_err("%cBE exception at %#lx\n", + data ? 'D' : 'I', regs->cp0_epc); + pr_err("ccfg:%llx, toea:%llx\n", + (unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4939_ccfgptr->toea)); +#ifdef CONFIG_PCI + tx4927_report_pcic_status(); +#endif + show_registers(regs); + panic("BusError!"); +} +static void __init tx4939_be_init(void) +{ + board_be_handler = tx4939_be_handler; +} + +static struct resource tx4939_sdram_resource[4]; +static struct resource tx4939_sram_resource; +#define TX4939_SRAM_SIZE 0x800 + +void __init tx4939_add_memory_regions(void) +{ + int i; + unsigned long start, size; + u64 win; + + for (i = 0; i < 4; i++) { + if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i))) + continue; + win = ____raw_readq(&tx4939_ddrcptr->win[i]); + start = (unsigned long)(win >> 48); + size = (((unsigned long)(win >> 32) & 0xffff) + 1) - start; + add_memory_region(start << 20, size << 20, BOOT_MEM_RAM); + } +} + +void __init tx4939_setup(void) +{ + int i; + __u32 divmode; + __u64 pcfg; + int cpuclk = 0; + + txx9_reg_res_init(TX4939_REV_PCODE(), TX4939_REG_BASE, + TX4939_REG_SIZE); + set_c0_config(TX49_CONF_CWFON); + + /* SDRAMC,EBUSC are configured by PROM */ + for (i = 0; i < 4; i++) { + if (!(TX4939_EBUSC_CR(i) & 0x8)) + continue; /* disabled */ + txx9_ce_res[i].start = (unsigned long)TX4939_EBUSC_BA(i); + txx9_ce_res[i].end = + txx9_ce_res[i].start + TX4939_EBUSC_SIZE(i) - 1; + request_resource(&iomem_resource, &txx9_ce_res[i]); + } + + /* clocks */ + if (txx9_master_clock) { + /* calculate cpu_clock from master_clock */ + divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) & + TX4939_CCFG_MULCLK_MASK; + cpuclk = txx9_master_clock * 20 / 2; + switch (divmode) { + case TX4939_CCFG_MULCLK_8: + cpuclk = cpuclk / 3 * 4 /* / 6 * 8 */; break; + case TX4939_CCFG_MULCLK_9: + cpuclk = cpuclk / 2 * 3 /* / 6 * 9 */; break; + case TX4939_CCFG_MULCLK_10: + cpuclk = cpuclk / 3 * 5 /* / 6 * 10 */; break; + case TX4939_CCFG_MULCLK_11: + cpuclk = cpuclk / 6 * 11; break; + case TX4939_CCFG_MULCLK_12: + cpuclk = cpuclk * 2 /* / 6 * 12 */; break; + case TX4939_CCFG_MULCLK_13: + cpuclk = cpuclk / 6 * 13; break; + case TX4939_CCFG_MULCLK_14: + cpuclk = cpuclk / 3 * 7 /* / 6 * 14 */; break; + case TX4939_CCFG_MULCLK_15: + cpuclk = cpuclk / 2 * 5 /* / 6 * 15 */; break; + } + txx9_cpu_clock = cpuclk; + } else { + if (txx9_cpu_clock == 0) + txx9_cpu_clock = 400000000; /* 400MHz */ + /* calculate master_clock from cpu_clock */ + cpuclk = txx9_cpu_clock; + divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) & + TX4939_CCFG_MULCLK_MASK; + switch (divmode) { + case TX4939_CCFG_MULCLK_8: + txx9_master_clock = cpuclk * 6 / 8; break; + case TX4939_CCFG_MULCLK_9: + txx9_master_clock = cpuclk * 6 / 9; break; + case TX4939_CCFG_MULCLK_10: + txx9_master_clock = cpuclk * 6 / 10; break; + case TX4939_CCFG_MULCLK_11: + txx9_master_clock = cpuclk * 6 / 11; break; + case TX4939_CCFG_MULCLK_12: + txx9_master_clock = cpuclk * 6 / 12; break; + case TX4939_CCFG_MULCLK_13: + txx9_master_clock = cpuclk * 6 / 13; break; + case TX4939_CCFG_MULCLK_14: + txx9_master_clock = cpuclk * 6 / 14; break; + case TX4939_CCFG_MULCLK_15: + txx9_master_clock = cpuclk * 6 / 15; break; + } + txx9_master_clock /= 10; /* * 2 / 20 */ + } + /* calculate gbus_clock from cpu_clock */ + divmode = (__u32)____raw_readq(&tx4939_ccfgptr->ccfg) & + TX4939_CCFG_YDIVMODE_MASK; + txx9_gbus_clock = txx9_cpu_clock; + switch (divmode) { + case TX4939_CCFG_YDIVMODE_2: + txx9_gbus_clock /= 2; break; + case TX4939_CCFG_YDIVMODE_3: + txx9_gbus_clock /= 3; break; + case TX4939_CCFG_YDIVMODE_5: + txx9_gbus_clock /= 5; break; + case TX4939_CCFG_YDIVMODE_6: + txx9_gbus_clock /= 6; break; + } + /* change default value to udelay/mdelay take reasonable time */ + loops_per_jiffy = txx9_cpu_clock / HZ / 2; + + /* CCFG */ + tx4939_wdr_init(); + /* clear BusErrorOnWrite flag (W1C) */ + tx4939_ccfg_set(TX4939_CCFG_WDRST | TX4939_CCFG_BEOW); + /* enable Timeout BusError */ + if (txx9_ccfg_toeon) + tx4939_ccfg_set(TX4939_CCFG_TOE); + + /* DMA selection */ + txx9_clear64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_DMASEL_ALL); + + /* Use external clock for external arbiter */ + if (!(____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCIARB)) + txx9_clear64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_PCICLKEN_ALL); + + pr_info("%s -- %dMHz(M%dMHz,G%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", + txx9_pcode_str, + (cpuclk + 500000) / 1000000, + (txx9_master_clock + 500000) / 1000000, + (txx9_gbus_clock + 500000) / 1000000, + (__u32)____raw_readq(&tx4939_ccfgptr->crir), + (unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4939_ccfgptr->pcfg)); + + pr_info("%s DDRC -- EN:%08x", txx9_pcode_str, + (__u32)____raw_readq(&tx4939_ddrcptr->winen)); + for (i = 0; i < 4; i++) { + __u64 win = ____raw_readq(&tx4939_ddrcptr->win[i]); + if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i))) + continue; /* disabled */ + printk(KERN_CONT " #%d:%016llx", i, (unsigned long long)win); + tx4939_sdram_resource[i].name = "DDR SDRAM"; + tx4939_sdram_resource[i].start = + (unsigned long)(win >> 48) << 20; + tx4939_sdram_resource[i].end = + ((((unsigned long)(win >> 32) & 0xffff) + 1) << + 20) - 1; + tx4939_sdram_resource[i].flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4939_sdram_resource[i]); + } + printk(KERN_CONT "\n"); + + /* SRAM */ + if (____raw_readq(&tx4939_sramcptr->cr) & 1) { + unsigned int size = TX4939_SRAM_SIZE; + tx4939_sram_resource.name = "SRAM"; + tx4939_sram_resource.start = + (____raw_readq(&tx4939_sramcptr->cr) >> (39-11)) + & ~(size - 1); + tx4939_sram_resource.end = + tx4939_sram_resource.start + TX4939_SRAM_SIZE - 1; + tx4939_sram_resource.flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4939_sram_resource); + } + + /* TMR */ + /* disable all timers */ + for (i = 0; i < TX4939_NR_TMR; i++) + txx9_tmr_init(TX4939_TMR_REG(i) & 0xfffffffffULL); + + /* DMA */ + for (i = 0; i < 2; i++) + ____raw_writeq(TX4938_DMA_MCR_MSTEN, + (void __iomem *)(TX4939_DMA_REG(i) + 0x50)); + + /* set PCIC1 reset (required to prevent hangup on BIST) */ + txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1RST); + pcfg = ____raw_readq(&tx4939_ccfgptr->pcfg); + if (pcfg & (TX4939_PCFG_ET0MODE | TX4939_PCFG_ET1MODE)) { + mdelay(1); /* at least 128 cpu clock */ + /* clear PCIC1 reset */ + txx9_clear64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1RST); + } else { + pr_info("%s: stop PCIC1\n", txx9_pcode_str); + /* stop PCIC1 */ + txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_PCI1CKD); + } + if (!(pcfg & TX4939_PCFG_ET0MODE)) { + pr_info("%s: stop ETH0\n", txx9_pcode_str); + txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH0RST); + txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH0CKD); + } + if (!(pcfg & TX4939_PCFG_ET1MODE)) { + pr_info("%s: stop ETH1\n", txx9_pcode_str); + txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH1RST); + txx9_set64(&tx4939_ccfgptr->clkctr, TX4939_CLKCTR_ETH1CKD); + } + + _machine_restart = tx4939_machine_restart; + board_be_init = tx4939_be_init; +} + +void __init tx4939_time_init(unsigned int tmrnr) +{ + if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_TINTDIS) + txx9_clockevent_init(TX4939_TMR_REG(tmrnr) & 0xfffffffffULL, + TXX9_IRQ_BASE + TX4939_IR_TMR(tmrnr), + TXX9_IMCLK); +} + +void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask) +{ + int i; + unsigned int ch_mask = 0; + __u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg); + + cts_mask |= ~1; /* only SIO0 have RTS/CTS */ + if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO0) + cts_mask |= 1 << 0; /* disable SIO0 RTS/CTS by PCFG setting */ + if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO2) + ch_mask |= 1 << 2; /* disable SIO2 by PCFG setting */ + if (pcfg & TX4939_PCFG_SIO3MODE) + ch_mask |= 1 << 3; /* disable SIO3 by PCFG setting */ + for (i = 0; i < 4; i++) { + if ((1 << i) & ch_mask) + continue; + txx9_sio_init(TX4939_SIO_REG(i) & 0xfffffffffULL, + TXX9_IRQ_BASE + TX4939_IR_SIO(i), + i, sclk, (1 << i) & cts_mask); + } +} + +#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) +static int tx4939_get_eth_speed(struct net_device *dev) +{ + struct ethtool_cmd cmd = { ETHTOOL_GSET }; + int speed = 100; /* default 100Mbps */ + int err; + if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) + return speed; + err = dev->ethtool_ops->get_settings(dev, &cmd); + if (err < 0) + return speed; + speed = cmd.speed == SPEED_100 ? 100 : 10; + return speed; +} +static int tx4939_netdev_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + if (event == NETDEV_CHANGE && netif_carrier_ok(dev)) { + __u64 bit = 0; + if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(0)) + bit = TX4939_PCFG_SPEED0; + else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1)) + bit = TX4939_PCFG_SPEED1; + if (bit) { + int speed = tx4939_get_eth_speed(dev); + if (speed == 100) + txx9_set64(&tx4939_ccfgptr->pcfg, bit); + else + txx9_clear64(&tx4939_ccfgptr->pcfg, bit); + } + } + return NOTIFY_DONE; +} + +static struct notifier_block tx4939_netdev_notifier = { + .notifier_call = tx4939_netdev_event, + .priority = 1, +}; + +void __init tx4939_ethaddr_init(unsigned char *addr0, unsigned char *addr1) +{ + u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg); + + if (addr0 && (pcfg & TX4939_PCFG_ET0MODE)) + txx9_ethaddr_init(TXX9_IRQ_BASE + TX4939_IR_ETH(0), addr0); + if (addr1 && (pcfg & TX4939_PCFG_ET1MODE)) + txx9_ethaddr_init(TXX9_IRQ_BASE + TX4939_IR_ETH(1), addr1); + register_netdevice_notifier(&tx4939_netdev_notifier); +} +#else +void __init tx4939_ethaddr_init(unsigned char *addr0, unsigned char *addr1) +{ +} +#endif + +void __init tx4939_mtd_init(int ch) +{ + struct physmap_flash_data pdata = { + .width = TX4939_EBUSC_WIDTH(ch) / 8, + }; + unsigned long start = txx9_ce_res[ch].start; + unsigned long size = txx9_ce_res[ch].end - start + 1; + + if (!(TX4939_EBUSC_CR(ch) & 0x8)) + return; /* disabled */ + txx9_physmap_flash_init(ch, start, size, &pdata); +} + +#define TX4939_ATA_REG_PHYS(ch) (TX4939_ATA_REG(ch) & 0xfffffffffULL) +void __init tx4939_ata_init(void) +{ + static struct resource ata0_res[] = { + { + .start = TX4939_ATA_REG_PHYS(0), + .end = TX4939_ATA_REG_PHYS(0) + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, { + .start = TXX9_IRQ_BASE + TX4939_IR_ATA(0), + .flags = IORESOURCE_IRQ, + }, + }; + static struct resource ata1_res[] = { + { + .start = TX4939_ATA_REG_PHYS(1), + .end = TX4939_ATA_REG_PHYS(1) + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, { + .start = TXX9_IRQ_BASE + TX4939_IR_ATA(1), + .flags = IORESOURCE_IRQ, + }, + }; + static struct platform_device ata0_dev = { + .name = "tx4939ide", + .id = 0, + .num_resources = ARRAY_SIZE(ata0_res), + .resource = ata0_res, + }; + static struct platform_device ata1_dev = { + .name = "tx4939ide", + .id = 1, + .num_resources = ARRAY_SIZE(ata1_res), + .resource = ata1_res, + }; + __u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg); + + if (pcfg & TX4939_PCFG_ATA0MODE) + platform_device_register(&ata0_dev); + if ((pcfg & (TX4939_PCFG_ATA1MODE | + TX4939_PCFG_ET1MODE | + TX4939_PCFG_ET0MODE)) == TX4939_PCFG_ATA1MODE) + platform_device_register(&ata1_dev); +} + +static void __init tx4939_stop_unused_modules(void) +{ + __u64 pcfg, rst = 0, ckd = 0; + char buf[128]; + + buf[0] = '\0'; + local_irq_disable(); + pcfg = ____raw_readq(&tx4939_ccfgptr->pcfg); + if ((pcfg & TX4939_PCFG_I2SMODE_MASK) != + TX4939_PCFG_I2SMODE_ACLC) { + rst |= TX4939_CLKCTR_ACLRST; + ckd |= TX4939_CLKCTR_ACLCKD; + strcat(buf, " ACLC"); + } + if ((pcfg & TX4939_PCFG_I2SMODE_MASK) != + TX4939_PCFG_I2SMODE_I2S && + (pcfg & TX4939_PCFG_I2SMODE_MASK) != + TX4939_PCFG_I2SMODE_I2S_ALT) { + rst |= TX4939_CLKCTR_I2SRST; + ckd |= TX4939_CLKCTR_I2SCKD; + strcat(buf, " I2S"); + } + if (!(pcfg & TX4939_PCFG_ATA0MODE)) { + rst |= TX4939_CLKCTR_ATA0RST; + ckd |= TX4939_CLKCTR_ATA0CKD; + strcat(buf, " ATA0"); + } + if (!(pcfg & TX4939_PCFG_ATA1MODE)) { + rst |= TX4939_CLKCTR_ATA1RST; + ckd |= TX4939_CLKCTR_ATA1CKD; + strcat(buf, " ATA1"); + } + if (pcfg & TX4939_PCFG_SPIMODE) { + rst |= TX4939_CLKCTR_SPIRST; + ckd |= TX4939_CLKCTR_SPICKD; + strcat(buf, " SPI"); + } + if (!(pcfg & (TX4939_PCFG_VSSMODE | TX4939_PCFG_VPSMODE))) { + rst |= TX4939_CLKCTR_VPCRST; + ckd |= TX4939_CLKCTR_VPCCKD; + strcat(buf, " VPC"); + } + if ((pcfg & TX4939_PCFG_SIO2MODE_MASK) != TX4939_PCFG_SIO2MODE_SIO2) { + rst |= TX4939_CLKCTR_SIO2RST; + ckd |= TX4939_CLKCTR_SIO2CKD; + strcat(buf, " SIO2"); + } + if (pcfg & TX4939_PCFG_SIO3MODE) { + rst |= TX4939_CLKCTR_SIO3RST; + ckd |= TX4939_CLKCTR_SIO3CKD; + strcat(buf, " SIO3"); + } + if (rst | ckd) { + txx9_set64(&tx4939_ccfgptr->clkctr, rst); + txx9_set64(&tx4939_ccfgptr->clkctr, ckd); + } + local_irq_enable(); + if (buf[0]) + pr_info("%s: stop%s\n", txx9_pcode_str, buf); +} + +static int __init tx4939_late_init(void) +{ + if (txx9_pcode != 0x4939) + return -ENODEV; + tx4939_stop_unused_modules(); + return 0; +} +late_initcall(tx4939_late_init); diff --git a/arch/mips/txx9/generic/spi_eeprom.c b/arch/mips/txx9/generic/spi_eeprom.c new file mode 100644 index 000000000000..75c347238f47 --- /dev/null +++ b/arch/mips/txx9/generic/spi_eeprom.c @@ -0,0 +1,103 @@ +/* + * spi_eeprom.c + * Copyright (C) 2000-2001 Toshiba Corporation + * + * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is + * licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) + */ +#include <linux/init.h> +#include <linux/device.h> +#include <linux/spi/spi.h> +#include <linux/spi/eeprom.h> +#include <asm/txx9/spi.h> + +#define AT250X0_PAGE_SIZE 8 + +/* register board information for at25 driver */ +int __init spi_eeprom_register(int busid, int chipid, int size) +{ + struct spi_board_info info = { + .modalias = "at25", + .max_speed_hz = 1500000, /* 1.5Mbps */ + .bus_num = busid, + .chip_select = chipid, + /* Mode 0: High-Active, Sample-Then-Shift */ + }; + struct spi_eeprom *eeprom; + eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL); + if (!eeprom) + return -ENOMEM; + strcpy(eeprom->name, "at250x0"); + eeprom->byte_len = size; + eeprom->page_size = AT250X0_PAGE_SIZE; + eeprom->flags = EE_ADDR1; + info.platform_data = eeprom; + return spi_register_board_info(&info, 1); +} + +/* simple temporary spi driver to provide early access to seeprom. */ + +static struct read_param { + int busid; + int chipid; + int address; + unsigned char *buf; + int len; +} *read_param; + +static int __init early_seeprom_probe(struct spi_device *spi) +{ + int stat = 0; + u8 cmd[2]; + int len = read_param->len; + char *buf = read_param->buf; + int address = read_param->address; + + dev_info(&spi->dev, "spiclk %u KHz.\n", + (spi->max_speed_hz + 500) / 1000); + if (read_param->busid != spi->master->bus_num || + read_param->chipid != spi->chip_select) + return -ENODEV; + while (len > 0) { + /* spi_write_then_read can only work with small chunk */ + int c = len < AT250X0_PAGE_SIZE ? len : AT250X0_PAGE_SIZE; + cmd[0] = 0x03; /* AT25_READ */ + cmd[1] = address; + stat = spi_write_then_read(spi, cmd, sizeof(cmd), buf, c); + buf += c; + len -= c; + address += c; + } + return stat; +} + +static struct spi_driver early_seeprom_driver __initdata = { + .driver = { + .name = "at25", + .owner = THIS_MODULE, + }, + .probe = early_seeprom_probe, +}; + +int __init spi_eeprom_read(int busid, int chipid, int address, + unsigned char *buf, int len) +{ + int ret; + struct read_param param = { + .busid = busid, + .chipid = chipid, + .address = address, + .buf = buf, + .len = len + }; + + read_param = ¶m; + ret = spi_register_driver(&early_seeprom_driver); + if (!ret) + spi_unregister_driver(&early_seeprom_driver); + return ret; +} |