cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

setup_tx4938.c (13868B)


      1/*
      2 * TX4938/4937 setup routines
      3 * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
      4 *	    and RBTX49xx patch from CELF patch archive.
      5 *
      6 * 2003-2005 (c) MontaVista Software, Inc.
      7 * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
      8 *
      9 * This file is subject to the terms and conditions of the GNU General Public
     10 * License.  See the file "COPYING" in the main directory of this archive
     11 * for more details.
     12 */
     13#include <linux/init.h>
     14#include <linux/ioport.h>
     15#include <linux/delay.h>
     16#include <linux/param.h>
     17#include <linux/ptrace.h>
     18#include <linux/mtd/physmap.h>
     19#include <linux/platform_device.h>
     20#include <linux/platform_data/txx9/ndfmc.h>
     21#include <asm/reboot.h>
     22#include <asm/traps.h>
     23#include <asm/txx9irq.h>
     24#include <asm/txx9tmr.h>
     25#include <asm/txx9pio.h>
     26#include <asm/txx9/generic.h>
     27#include <asm/txx9/dmac.h>
     28#include <asm/txx9/tx4938.h>
     29
     30static void __init tx4938_wdr_init(void)
     31{
     32	/* report watchdog reset status */
     33	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST)
     34		pr_warn("Watchdog reset detected at 0x%lx\n",
     35			read_c0_errorepc());
     36	/* clear WatchDogReset (W1C) */
     37	tx4938_ccfg_set(TX4938_CCFG_WDRST);
     38	/* do reset on watchdog */
     39	tx4938_ccfg_set(TX4938_CCFG_WR);
     40}
     41
     42void __init tx4938_wdt_init(void)
     43{
     44	txx9_wdt_init(TX4938_TMR_REG(2) & 0xfffffffffULL);
     45}
     46
     47static void tx4938_machine_restart(char *command)
     48{
     49	local_irq_disable();
     50	pr_emerg("Rebooting (with %s watchdog reset)...\n",
     51		 (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) ?
     52		 "external" : "internal");
     53	/* clear watchdog status */
     54	tx4938_ccfg_set(TX4938_CCFG_WDRST);	/* W1C */
     55	txx9_wdt_now(TX4938_TMR_REG(2) & 0xfffffffffULL);
     56	while (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST))
     57		;
     58	mdelay(10);
     59	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) {
     60		pr_emerg("Rebooting (with internal watchdog reset)...\n");
     61		/* External WDRST failed.  Do internal watchdog reset */
     62		tx4938_ccfg_clear(TX4938_CCFG_WDREXEN);
     63	}
     64	/* fallback */
     65	(*_machine_halt)();
     66}
     67
     68void show_registers(struct pt_regs *regs);
     69static int tx4938_be_handler(struct pt_regs *regs, int is_fixup)
     70{
     71	int data = regs->cp0_cause & 4;
     72	console_verbose();
     73	pr_err("%cBE exception at %#lx\n", data ? 'D' : 'I', regs->cp0_epc);
     74	pr_err("ccfg:%llx, toea:%llx\n",
     75	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg),
     76	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->toea));
     77#ifdef CONFIG_PCI
     78	tx4927_report_pcic_status();
     79#endif
     80	show_registers(regs);
     81	panic("BusError!");
     82}
     83static void __init tx4938_be_init(void)
     84{
     85	mips_set_be_handler(tx4938_be_handler);
     86}
     87
     88static struct resource tx4938_sdram_resource[4];
     89static struct resource tx4938_sram_resource;
     90
     91#define TX4938_SRAM_SIZE 0x800
     92
     93void __init tx4938_setup(void)
     94{
     95	int i;
     96	__u32 divmode;
     97	unsigned int cpuclk = 0;
     98	u64 ccfg;
     99
    100	txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE,
    101			  TX4938_REG_SIZE);
    102	set_c0_config(TX49_CONF_CWFON);
    103
    104	/* SDRAMC,EBUSC are configured by PROM */
    105	for (i = 0; i < 8; i++) {
    106		if (!(TX4938_EBUSC_CR(i) & 0x8))
    107			continue;	/* disabled */
    108		txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i);
    109		txx9_ce_res[i].end =
    110			txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1;
    111		request_resource(&iomem_resource, &txx9_ce_res[i]);
    112	}
    113
    114	/* clocks */
    115	ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg);
    116	if (txx9_master_clock) {
    117		/* calculate gbus_clock and cpu_clock from master_clock */
    118		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
    119		switch (divmode) {
    120		case TX4938_CCFG_DIVMODE_8:
    121		case TX4938_CCFG_DIVMODE_10:
    122		case TX4938_CCFG_DIVMODE_12:
    123		case TX4938_CCFG_DIVMODE_16:
    124		case TX4938_CCFG_DIVMODE_18:
    125			txx9_gbus_clock = txx9_master_clock * 4; break;
    126		default:
    127			txx9_gbus_clock = txx9_master_clock;
    128		}
    129		switch (divmode) {
    130		case TX4938_CCFG_DIVMODE_2:
    131		case TX4938_CCFG_DIVMODE_8:
    132			cpuclk = txx9_gbus_clock * 2; break;
    133		case TX4938_CCFG_DIVMODE_2_5:
    134		case TX4938_CCFG_DIVMODE_10:
    135			cpuclk = txx9_gbus_clock * 5 / 2; break;
    136		case TX4938_CCFG_DIVMODE_3:
    137		case TX4938_CCFG_DIVMODE_12:
    138			cpuclk = txx9_gbus_clock * 3; break;
    139		case TX4938_CCFG_DIVMODE_4:
    140		case TX4938_CCFG_DIVMODE_16:
    141			cpuclk = txx9_gbus_clock * 4; break;
    142		case TX4938_CCFG_DIVMODE_4_5:
    143		case TX4938_CCFG_DIVMODE_18:
    144			cpuclk = txx9_gbus_clock * 9 / 2; break;
    145		}
    146		txx9_cpu_clock = cpuclk;
    147	} else {
    148		if (txx9_cpu_clock == 0)
    149			txx9_cpu_clock = 300000000;	/* 300MHz */
    150		/* calculate gbus_clock and master_clock from cpu_clock */
    151		cpuclk = txx9_cpu_clock;
    152		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
    153		switch (divmode) {
    154		case TX4938_CCFG_DIVMODE_2:
    155		case TX4938_CCFG_DIVMODE_8:
    156			txx9_gbus_clock = cpuclk / 2; break;
    157		case TX4938_CCFG_DIVMODE_2_5:
    158		case TX4938_CCFG_DIVMODE_10:
    159			txx9_gbus_clock = cpuclk * 2 / 5; break;
    160		case TX4938_CCFG_DIVMODE_3:
    161		case TX4938_CCFG_DIVMODE_12:
    162			txx9_gbus_clock = cpuclk / 3; break;
    163		case TX4938_CCFG_DIVMODE_4:
    164		case TX4938_CCFG_DIVMODE_16:
    165			txx9_gbus_clock = cpuclk / 4; break;
    166		case TX4938_CCFG_DIVMODE_4_5:
    167		case TX4938_CCFG_DIVMODE_18:
    168			txx9_gbus_clock = cpuclk * 2 / 9; break;
    169		}
    170		switch (divmode) {
    171		case TX4938_CCFG_DIVMODE_8:
    172		case TX4938_CCFG_DIVMODE_10:
    173		case TX4938_CCFG_DIVMODE_12:
    174		case TX4938_CCFG_DIVMODE_16:
    175		case TX4938_CCFG_DIVMODE_18:
    176			txx9_master_clock = txx9_gbus_clock / 4; break;
    177		default:
    178			txx9_master_clock = txx9_gbus_clock;
    179		}
    180	}
    181	/* change default value to udelay/mdelay take reasonable time */
    182	loops_per_jiffy = txx9_cpu_clock / HZ / 2;
    183
    184	/* CCFG */
    185	tx4938_wdr_init();
    186	/* clear BusErrorOnWrite flag (W1C) */
    187	tx4938_ccfg_set(TX4938_CCFG_BEOW);
    188	/* enable Timeout BusError */
    189	if (txx9_ccfg_toeon)
    190		tx4938_ccfg_set(TX4938_CCFG_TOE);
    191
    192	/* DMA selection */
    193	txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL);
    194
    195	/* Use external clock for external arbiter */
    196	if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB))
    197		txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL);
    198
    199	pr_info("%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
    200		txx9_pcode_str, (cpuclk + 500000) / 1000000,
    201		(txx9_master_clock + 500000) / 1000000,
    202		(__u32)____raw_readq(&tx4938_ccfgptr->crir),
    203		____raw_readq(&tx4938_ccfgptr->ccfg),
    204		____raw_readq(&tx4938_ccfgptr->pcfg));
    205
    206	pr_info("%s SDRAMC --", txx9_pcode_str);
    207	for (i = 0; i < 4; i++) {
    208		__u64 cr = TX4938_SDRAMC_CR(i);
    209		unsigned long base, size;
    210		if (!((__u32)cr & 0x00000400))
    211			continue;	/* disabled */
    212		base = (unsigned long)(cr >> 49) << 21;
    213		size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21;
    214		pr_cont(" CR%d:%016llx", i, cr);
    215		tx4938_sdram_resource[i].name = "SDRAM";
    216		tx4938_sdram_resource[i].start = base;
    217		tx4938_sdram_resource[i].end = base + size - 1;
    218		tx4938_sdram_resource[i].flags = IORESOURCE_MEM;
    219		request_resource(&iomem_resource, &tx4938_sdram_resource[i]);
    220	}
    221	pr_cont(" TR:%09llx\n", ____raw_readq(&tx4938_sdramcptr->tr));
    222
    223	/* SRAM */
    224	if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) {
    225		unsigned int size = TX4938_SRAM_SIZE;
    226		tx4938_sram_resource.name = "SRAM";
    227		tx4938_sram_resource.start =
    228			(____raw_readq(&tx4938_sramcptr->cr) >> (39-11))
    229			& ~(size - 1);
    230		tx4938_sram_resource.end =
    231			tx4938_sram_resource.start + TX4938_SRAM_SIZE - 1;
    232		tx4938_sram_resource.flags = IORESOURCE_MEM;
    233		request_resource(&iomem_resource, &tx4938_sram_resource);
    234	}
    235
    236	/* TMR */
    237	/* disable all timers */
    238	for (i = 0; i < TX4938_NR_TMR; i++)
    239		txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL);
    240
    241	/* PIO */
    242	__raw_writel(0, &tx4938_pioptr->maskcpu);
    243	__raw_writel(0, &tx4938_pioptr->maskext);
    244
    245	if (txx9_pcode == 0x4938) {
    246		__u64 pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);
    247		/* set PCIC1 reset */
    248		txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST);
    249		if (pcfg & (TX4938_PCFG_ETH0_SEL | TX4938_PCFG_ETH1_SEL)) {
    250			mdelay(1);	/* at least 128 cpu clock */
    251			/* clear PCIC1 reset */
    252			txx9_clear64(&tx4938_ccfgptr->clkctr,
    253				     TX4938_CLKCTR_PCIC1RST);
    254		} else {
    255			pr_info("%s: stop PCIC1\n", txx9_pcode_str);
    256			/* stop PCIC1 */
    257			txx9_set64(&tx4938_ccfgptr->clkctr,
    258				   TX4938_CLKCTR_PCIC1CKD);
    259		}
    260		if (!(pcfg & TX4938_PCFG_ETH0_SEL)) {
    261			pr_info("%s: stop ETH0\n", txx9_pcode_str);
    262			txx9_set64(&tx4938_ccfgptr->clkctr,
    263				   TX4938_CLKCTR_ETH0RST);
    264			txx9_set64(&tx4938_ccfgptr->clkctr,
    265				   TX4938_CLKCTR_ETH0CKD);
    266		}
    267		if (!(pcfg & TX4938_PCFG_ETH1_SEL)) {
    268			pr_info("%s: stop ETH1\n", txx9_pcode_str);
    269			txx9_set64(&tx4938_ccfgptr->clkctr,
    270				   TX4938_CLKCTR_ETH1RST);
    271			txx9_set64(&tx4938_ccfgptr->clkctr,
    272				   TX4938_CLKCTR_ETH1CKD);
    273		}
    274	}
    275
    276	_machine_restart = tx4938_machine_restart;
    277	board_be_init = tx4938_be_init;
    278}
    279
    280void __init tx4938_time_init(unsigned int tmrnr)
    281{
    282	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS)
    283		txx9_clockevent_init(TX4938_TMR_REG(tmrnr) & 0xfffffffffULL,
    284				     TXX9_IRQ_BASE + TX4938_IR_TMR(tmrnr),
    285				     TXX9_IMCLK);
    286}
    287
    288void __init tx4938_sio_init(unsigned int sclk, unsigned int cts_mask)
    289{
    290	int i;
    291	unsigned int ch_mask = 0;
    292
    293	if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL)
    294		ch_mask |= 1 << 1; /* disable SIO1 by PCFG setting */
    295	for (i = 0; i < 2; i++) {
    296		if ((1 << i) & ch_mask)
    297			continue;
    298		txx9_sio_init(TX4938_SIO_REG(i) & 0xfffffffffULL,
    299			      TXX9_IRQ_BASE + TX4938_IR_SIO(i),
    300			      i, sclk, (1 << i) & cts_mask);
    301	}
    302}
    303
    304void __init tx4938_spi_init(int busid)
    305{
    306	txx9_spi_init(busid, TX4938_SPI_REG & 0xfffffffffULL,
    307		      TXX9_IRQ_BASE + TX4938_IR_SPI);
    308}
    309
    310void __init tx4938_ethaddr_init(unsigned char *addr0, unsigned char *addr1)
    311{
    312	u64 pcfg = __raw_readq(&tx4938_ccfgptr->pcfg);
    313
    314	if (addr0 && (pcfg & TX4938_PCFG_ETH0_SEL))
    315		txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH0, addr0);
    316	if (addr1 && (pcfg & TX4938_PCFG_ETH1_SEL))
    317		txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH1, addr1);
    318}
    319
    320void __init tx4938_mtd_init(int ch)
    321{
    322	struct physmap_flash_data pdata = {
    323		.width = TX4938_EBUSC_WIDTH(ch) / 8,
    324	};
    325	unsigned long start = txx9_ce_res[ch].start;
    326	unsigned long size = txx9_ce_res[ch].end - start + 1;
    327
    328	if (!(TX4938_EBUSC_CR(ch) & 0x8))
    329		return; /* disabled */
    330	txx9_physmap_flash_init(ch, start, size, &pdata);
    331}
    332
    333void __init tx4938_ata_init(unsigned int irq, unsigned int shift, int tune)
    334{
    335	struct platform_device *pdev;
    336	struct resource res[] = {
    337		{
    338			/* .start and .end are filled in later */
    339			.flags = IORESOURCE_MEM,
    340		}, {
    341			.start = irq,
    342			.flags = IORESOURCE_IRQ,
    343		},
    344	};
    345	struct tx4938ide_platform_info pdata = {
    346		.ioport_shift = shift,
    347		/*
    348		 * The IDE driver should not change bus timings if other ISA
    349		 * devices existed.
    350		 */
    351		.gbus_clock = tune ? txx9_gbus_clock : 0,
    352	};
    353	u64 ebccr;
    354	int i;
    355
    356	if ((__raw_readq(&tx4938_ccfgptr->pcfg) &
    357	     (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL))
    358	    != TX4938_PCFG_ATA_SEL)
    359		return;
    360	for (i = 0; i < 8; i++) {
    361		/* check EBCCRn.ISA, EBCCRn.BSZ, EBCCRn.ME */
    362		ebccr = __raw_readq(&tx4938_ebuscptr->cr[i]);
    363		if ((ebccr & 0x00f00008) == 0x00e00008)
    364			break;
    365	}
    366	if (i == 8)
    367		return;
    368	pdata.ebus_ch = i;
    369	res[0].start = ((ebccr >> 48) << 20) + 0x10000;
    370	res[0].end = res[0].start + 0x20000 - 1;
    371	pdev = platform_device_alloc("tx4938ide", -1);
    372	if (!pdev ||
    373	    platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
    374	    platform_device_add_data(pdev, &pdata, sizeof(pdata)) ||
    375	    platform_device_add(pdev))
    376		platform_device_put(pdev);
    377}
    378
    379void __init tx4938_ndfmc_init(unsigned int hold, unsigned int spw)
    380{
    381	struct txx9ndfmc_platform_data plat_data = {
    382		.shift = 1,
    383		.gbus_clock = txx9_gbus_clock,
    384		.hold = hold,
    385		.spw = spw,
    386		.ch_mask = 1,
    387	};
    388	unsigned long baseaddr = TX4938_NDFMC_REG & 0xfffffffffULL;
    389
    390#ifdef __BIG_ENDIAN
    391	baseaddr += 4;
    392#endif
    393	if ((__raw_readq(&tx4938_ccfgptr->pcfg) &
    394	     (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL)) ==
    395	    TX4938_PCFG_NDF_SEL)
    396		txx9_ndfmc_init(baseaddr, &plat_data);
    397}
    398
    399void __init tx4938_dmac_init(int memcpy_chan0, int memcpy_chan1)
    400{
    401	struct txx9dmac_platform_data plat_data = {
    402		.have_64bit_regs = true,
    403	};
    404	int i;
    405
    406	for (i = 0; i < 2; i++) {
    407		plat_data.memcpy_chan = i ? memcpy_chan1 : memcpy_chan0;
    408		txx9_dmac_init(i, TX4938_DMA_REG(i) & 0xfffffffffULL,
    409			       TXX9_IRQ_BASE + TX4938_IR_DMA(i, 0),
    410			       &plat_data);
    411	}
    412}
    413
    414void __init tx4938_aclc_init(void)
    415{
    416	u64 pcfg = __raw_readq(&tx4938_ccfgptr->pcfg);
    417
    418	if ((pcfg & TX4938_PCFG_SEL2) &&
    419	    !(pcfg & TX4938_PCFG_ETH0_SEL))
    420		txx9_aclc_init(TX4938_ACLC_REG & 0xfffffffffULL,
    421			       TXX9_IRQ_BASE + TX4938_IR_ACLC,
    422			       1, 0, 1);
    423}
    424
    425void __init tx4938_sramc_init(void)
    426{
    427	if (tx4938_sram_resource.start)
    428		txx9_sramc_init(&tx4938_sram_resource);
    429}
    430
    431static void __init tx4938_stop_unused_modules(void)
    432{
    433	__u64 pcfg, rst = 0, ckd = 0;
    434	char buf[128];
    435
    436	buf[0] = '\0';
    437	local_irq_disable();
    438	pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);
    439	switch (txx9_pcode) {
    440	case 0x4937:
    441		if (!(pcfg & TX4938_PCFG_SEL2)) {
    442			rst |= TX4938_CLKCTR_ACLRST;
    443			ckd |= TX4938_CLKCTR_ACLCKD;
    444			strcat(buf, " ACLC");
    445		}
    446		break;
    447	case 0x4938:
    448		if (!(pcfg & TX4938_PCFG_SEL2) ||
    449		    (pcfg & TX4938_PCFG_ETH0_SEL)) {
    450			rst |= TX4938_CLKCTR_ACLRST;
    451			ckd |= TX4938_CLKCTR_ACLCKD;
    452			strcat(buf, " ACLC");
    453		}
    454		if ((pcfg &
    455		     (TX4938_PCFG_ATA_SEL | TX4938_PCFG_ISA_SEL |
    456		      TX4938_PCFG_NDF_SEL))
    457		    != TX4938_PCFG_NDF_SEL) {
    458			rst |= TX4938_CLKCTR_NDFRST;
    459			ckd |= TX4938_CLKCTR_NDFCKD;
    460			strcat(buf, " NDFMC");
    461		}
    462		if (!(pcfg & TX4938_PCFG_SPI_SEL)) {
    463			rst |= TX4938_CLKCTR_SPIRST;
    464			ckd |= TX4938_CLKCTR_SPICKD;
    465			strcat(buf, " SPI");
    466		}
    467		break;
    468	}
    469	if (rst | ckd) {
    470		txx9_set64(&tx4938_ccfgptr->clkctr, rst);
    471		txx9_set64(&tx4938_ccfgptr->clkctr, ckd);
    472	}
    473	local_irq_enable();
    474	if (buf[0])
    475		pr_info("%s: stop%s\n", txx9_pcode_str, buf);
    476}
    477
    478static int __init tx4938_late_init(void)
    479{
    480	if (txx9_pcode != 0x4937 && txx9_pcode != 0x4938)
    481		return -ENODEV;
    482	tx4938_stop_unused_modules();
    483	return 0;
    484}
    485late_initcall(tx4938_late_init);