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

p1022_ds.c (15051B)


      1/*
      2 * P1022DS board specific routines
      3 *
      4 * Authors: Travis Wheatley <travis.wheatley@freescale.com>
      5 *          Dave Liu <daveliu@freescale.com>
      6 *          Timur Tabi <timur@freescale.com>
      7 *
      8 * Copyright 2010 Freescale Semiconductor, Inc.
      9 *
     10 * This file is taken from the Freescale P1022DS BSP, with modifications:
     11 * 2) No AMP support
     12 * 3) No PCI endpoint support
     13 *
     14 * This file is licensed under the terms of the GNU General Public License
     15 * version 2.  This program is licensed "as is" without any warranty of any
     16 * kind, whether express or implied.
     17 */
     18
     19#include <linux/fsl/guts.h>
     20#include <linux/pci.h>
     21#include <linux/of_address.h>
     22#include <linux/of_platform.h>
     23#include <asm/div64.h>
     24#include <asm/mpic.h>
     25#include <asm/swiotlb.h>
     26
     27#include <sysdev/fsl_soc.h>
     28#include <sysdev/fsl_pci.h>
     29#include <asm/udbg.h>
     30#include <asm/fsl_lbc.h>
     31#include "smp.h"
     32
     33#include "mpc85xx.h"
     34
     35#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
     36
     37#define PMUXCR_ELBCDIU_MASK	0xc0000000
     38#define PMUXCR_ELBCDIU_NOR16	0x80000000
     39#define PMUXCR_ELBCDIU_DIU	0x40000000
     40
     41/*
     42 * Board-specific initialization of the DIU.  This code should probably be
     43 * executed when the DIU is opened, rather than in arch code, but the DIU
     44 * driver does not have a mechanism for this (yet).
     45 *
     46 * This is especially problematic on the P1022DS because the local bus (eLBC)
     47 * and the DIU video signals share the same pins, which means that enabling the
     48 * DIU will disable access to NOR flash.
     49 */
     50
     51/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
     52#define CLKDVDR_PXCKEN		0x80000000
     53#define CLKDVDR_PXCKINV		0x10000000
     54#define CLKDVDR_PXCKDLY		0x06000000
     55#define CLKDVDR_PXCLK_MASK	0x00FF0000
     56
     57/* Some ngPIXIS register definitions */
     58#define PX_CTL		3
     59#define PX_BRDCFG0	8
     60#define PX_BRDCFG1	9
     61
     62#define PX_BRDCFG0_ELBC_SPI_MASK	0xc0
     63#define PX_BRDCFG0_ELBC_SPI_ELBC	0x00
     64#define PX_BRDCFG0_ELBC_SPI_NULL	0xc0
     65#define PX_BRDCFG0_ELBC_DIU		0x02
     66
     67#define PX_BRDCFG1_DVIEN	0x80
     68#define PX_BRDCFG1_DFPEN	0x40
     69#define PX_BRDCFG1_BACKLIGHT	0x20
     70#define PX_BRDCFG1_DDCEN	0x10
     71
     72#define PX_CTL_ALTACC		0x80
     73
     74/*
     75 * DIU Area Descriptor
     76 *
     77 * Note that we need to byte-swap the value before it's written to the AD
     78 * register.  So even though the registers don't look like they're in the same
     79 * bit positions as they are on the MPC8610, the same value is written to the
     80 * AD register on the MPC8610 and on the P1022.
     81 */
     82#define AD_BYTE_F		0x10000000
     83#define AD_ALPHA_C_MASK		0x0E000000
     84#define AD_ALPHA_C_SHIFT	25
     85#define AD_BLUE_C_MASK		0x01800000
     86#define AD_BLUE_C_SHIFT		23
     87#define AD_GREEN_C_MASK		0x00600000
     88#define AD_GREEN_C_SHIFT	21
     89#define AD_RED_C_MASK		0x00180000
     90#define AD_RED_C_SHIFT		19
     91#define AD_PALETTE		0x00040000
     92#define AD_PIXEL_S_MASK		0x00030000
     93#define AD_PIXEL_S_SHIFT	16
     94#define AD_COMP_3_MASK		0x0000F000
     95#define AD_COMP_3_SHIFT		12
     96#define AD_COMP_2_MASK		0x00000F00
     97#define AD_COMP_2_SHIFT		8
     98#define AD_COMP_1_MASK		0x000000F0
     99#define AD_COMP_1_SHIFT		4
    100#define AD_COMP_0_MASK		0x0000000F
    101#define AD_COMP_0_SHIFT		0
    102
    103#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
    104	cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
    105	(blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
    106	(red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
    107	(c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
    108	(c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
    109
    110struct fsl_law {
    111	u32	lawbar;
    112	u32	reserved1;
    113	u32	lawar;
    114	u32	reserved[5];
    115};
    116
    117#define LAWBAR_MASK	0x00F00000
    118#define LAWBAR_SHIFT	12
    119
    120#define LAWAR_EN	0x80000000
    121#define LAWAR_TGT_MASK	0x01F00000
    122#define LAW_TRGT_IF_LBC	(0x04 << 20)
    123
    124#define LAWAR_MASK	(LAWAR_EN | LAWAR_TGT_MASK)
    125#define LAWAR_MATCH	(LAWAR_EN | LAW_TRGT_IF_LBC)
    126
    127#define BR_BA		0xFFFF8000
    128
    129/*
    130 * Map a BRx value to a physical address
    131 *
    132 * The localbus BRx registers only store the lower 32 bits of the address.  To
    133 * obtain the upper four bits, we need to scan the LAW table.  The entry which
    134 * maps to the localbus will contain the upper four bits.
    135 */
    136static phys_addr_t lbc_br_to_phys(const void *ecm, unsigned int count, u32 br)
    137{
    138#ifndef CONFIG_PHYS_64BIT
    139	/*
    140	 * If we only have 32-bit addressing, then the BRx address *is* the
    141	 * physical address.
    142	 */
    143	return br & BR_BA;
    144#else
    145	const struct fsl_law *law = ecm + 0xc08;
    146	unsigned int i;
    147
    148	for (i = 0; i < count; i++) {
    149		u64 lawbar = in_be32(&law[i].lawbar);
    150		u32 lawar = in_be32(&law[i].lawar);
    151
    152		if ((lawar & LAWAR_MASK) == LAWAR_MATCH)
    153			/* Extract the upper four bits */
    154			return (br & BR_BA) | ((lawbar & LAWBAR_MASK) << 12);
    155	}
    156
    157	return 0;
    158#endif
    159}
    160
    161/**
    162 * p1022ds_set_monitor_port: switch the output to a different monitor port
    163 */
    164static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
    165{
    166	struct device_node *guts_node;
    167	struct device_node *lbc_node = NULL;
    168	struct device_node *law_node = NULL;
    169	struct ccsr_guts __iomem *guts;
    170	struct fsl_lbc_regs *lbc = NULL;
    171	void *ecm = NULL;
    172	u8 __iomem *lbc_lcs0_ba = NULL;
    173	u8 __iomem *lbc_lcs1_ba = NULL;
    174	phys_addr_t cs0_addr, cs1_addr;
    175	u32 br0, or0, br1, or1;
    176	const __be32 *iprop;
    177	unsigned int num_laws;
    178	u8 b;
    179
    180	/* Map the global utilities registers. */
    181	guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
    182	if (!guts_node) {
    183		pr_err("p1022ds: missing global utilities device node\n");
    184		return;
    185	}
    186
    187	guts = of_iomap(guts_node, 0);
    188	if (!guts) {
    189		pr_err("p1022ds: could not map global utilities device\n");
    190		goto exit;
    191	}
    192
    193	lbc_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc");
    194	if (!lbc_node) {
    195		pr_err("p1022ds: missing localbus node\n");
    196		goto exit;
    197	}
    198
    199	lbc = of_iomap(lbc_node, 0);
    200	if (!lbc) {
    201		pr_err("p1022ds: could not map localbus node\n");
    202		goto exit;
    203	}
    204
    205	law_node = of_find_compatible_node(NULL, NULL, "fsl,ecm-law");
    206	if (!law_node) {
    207		pr_err("p1022ds: missing local access window node\n");
    208		goto exit;
    209	}
    210
    211	ecm = of_iomap(law_node, 0);
    212	if (!ecm) {
    213		pr_err("p1022ds: could not map local access window node\n");
    214		goto exit;
    215	}
    216
    217	iprop = of_get_property(law_node, "fsl,num-laws", NULL);
    218	if (!iprop) {
    219		pr_err("p1022ds: LAW node is missing fsl,num-laws property\n");
    220		goto exit;
    221	}
    222	num_laws = be32_to_cpup(iprop);
    223
    224	/*
    225	 * Indirect mode requires both BR0 and BR1 to be set to "GPCM",
    226	 * otherwise writes to these addresses won't actually appear on the
    227	 * local bus, and so the PIXIS won't see them.
    228	 *
    229	 * In FCM mode, writes go to the NAND controller, which does not pass
    230	 * them to the localbus directly.  So we force BR0 and BR1 into GPCM
    231	 * mode, since we don't care about what's behind the localbus any
    232	 * more.
    233	 */
    234	br0 = in_be32(&lbc->bank[0].br);
    235	br1 = in_be32(&lbc->bank[1].br);
    236	or0 = in_be32(&lbc->bank[0].or);
    237	or1 = in_be32(&lbc->bank[1].or);
    238
    239	/* Make sure CS0 and CS1 are programmed */
    240	if (!(br0 & BR_V) || !(br1 & BR_V)) {
    241		pr_err("p1022ds: CS0 and/or CS1 is not programmed\n");
    242		goto exit;
    243	}
    244
    245	/*
    246	 * Use the existing BRx/ORx values if it's already GPCM. Otherwise,
    247	 * force the values to simple 32KB GPCM windows with the most
    248	 * conservative timing.
    249	 */
    250	if ((br0 & BR_MSEL) != BR_MS_GPCM) {
    251		br0 = (br0 & BR_BA) | BR_V;
    252		or0 = 0xFFFF8000 | 0xFF7;
    253		out_be32(&lbc->bank[0].br, br0);
    254		out_be32(&lbc->bank[0].or, or0);
    255	}
    256	if ((br1 & BR_MSEL) != BR_MS_GPCM) {
    257		br1 = (br1 & BR_BA) | BR_V;
    258		or1 = 0xFFFF8000 | 0xFF7;
    259		out_be32(&lbc->bank[1].br, br1);
    260		out_be32(&lbc->bank[1].or, or1);
    261	}
    262
    263	cs0_addr = lbc_br_to_phys(ecm, num_laws, br0);
    264	if (!cs0_addr) {
    265		pr_err("p1022ds: could not determine physical address for CS0"
    266		       " (BR0=%08x)\n", br0);
    267		goto exit;
    268	}
    269	cs1_addr = lbc_br_to_phys(ecm, num_laws, br1);
    270	if (!cs1_addr) {
    271		pr_err("p1022ds: could not determine physical address for CS1"
    272		       " (BR1=%08x)\n", br1);
    273		goto exit;
    274	}
    275
    276	lbc_lcs0_ba = ioremap(cs0_addr, 1);
    277	if (!lbc_lcs0_ba) {
    278		pr_err("p1022ds: could not ioremap CS0 address %llx\n",
    279		       (unsigned long long)cs0_addr);
    280		goto exit;
    281	}
    282	lbc_lcs1_ba = ioremap(cs1_addr, 1);
    283	if (!lbc_lcs1_ba) {
    284		pr_err("p1022ds: could not ioremap CS1 address %llx\n",
    285		       (unsigned long long)cs1_addr);
    286		goto exit;
    287	}
    288
    289	/* Make sure we're in indirect mode first. */
    290	if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
    291	    PMUXCR_ELBCDIU_DIU) {
    292		struct device_node *pixis_node;
    293		void __iomem *pixis;
    294
    295		pixis_node =
    296			of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga");
    297		if (!pixis_node) {
    298			pr_err("p1022ds: missing pixis node\n");
    299			goto exit;
    300		}
    301
    302		pixis = of_iomap(pixis_node, 0);
    303		of_node_put(pixis_node);
    304		if (!pixis) {
    305			pr_err("p1022ds: could not map pixis registers\n");
    306			goto exit;
    307		}
    308
    309		/* Enable indirect PIXIS mode.  */
    310		setbits8(pixis + PX_CTL, PX_CTL_ALTACC);
    311		iounmap(pixis);
    312
    313		/* Switch the board mux to the DIU */
    314		out_8(lbc_lcs0_ba, PX_BRDCFG0);	/* BRDCFG0 */
    315		b = in_8(lbc_lcs1_ba);
    316		b |= PX_BRDCFG0_ELBC_DIU;
    317		out_8(lbc_lcs1_ba, b);
    318
    319		/* Set the chip mux to DIU mode. */
    320		clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK,
    321				PMUXCR_ELBCDIU_DIU);
    322		in_be32(&guts->pmuxcr);
    323	}
    324
    325
    326	switch (port) {
    327	case FSL_DIU_PORT_DVI:
    328		/* Enable the DVI port, disable the DFP and the backlight */
    329		out_8(lbc_lcs0_ba, PX_BRDCFG1);
    330		b = in_8(lbc_lcs1_ba);
    331		b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
    332		b |= PX_BRDCFG1_DVIEN;
    333		out_8(lbc_lcs1_ba, b);
    334		break;
    335	case FSL_DIU_PORT_LVDS:
    336		/*
    337		 * LVDS also needs backlight enabled, otherwise the display
    338		 * will be blank.
    339		 */
    340		/* Enable the DFP port, disable the DVI and the backlight */
    341		out_8(lbc_lcs0_ba, PX_BRDCFG1);
    342		b = in_8(lbc_lcs1_ba);
    343		b &= ~PX_BRDCFG1_DVIEN;
    344		b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT;
    345		out_8(lbc_lcs1_ba, b);
    346		break;
    347	default:
    348		pr_err("p1022ds: unsupported monitor port %i\n", port);
    349	}
    350
    351exit:
    352	if (lbc_lcs1_ba)
    353		iounmap(lbc_lcs1_ba);
    354	if (lbc_lcs0_ba)
    355		iounmap(lbc_lcs0_ba);
    356	if (lbc)
    357		iounmap(lbc);
    358	if (ecm)
    359		iounmap(ecm);
    360	if (guts)
    361		iounmap(guts);
    362
    363	of_node_put(law_node);
    364	of_node_put(lbc_node);
    365	of_node_put(guts_node);
    366}
    367
    368/**
    369 * p1022ds_set_pixel_clock: program the DIU's clock
    370 *
    371 * @pixclock: the wavelength, in picoseconds, of the clock
    372 */
    373void p1022ds_set_pixel_clock(unsigned int pixclock)
    374{
    375	struct device_node *guts_np = NULL;
    376	struct ccsr_guts __iomem *guts;
    377	unsigned long freq;
    378	u64 temp;
    379	u32 pxclk;
    380
    381	/* Map the global utilities registers. */
    382	guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
    383	if (!guts_np) {
    384		pr_err("p1022ds: missing global utilities device node\n");
    385		return;
    386	}
    387
    388	guts = of_iomap(guts_np, 0);
    389	of_node_put(guts_np);
    390	if (!guts) {
    391		pr_err("p1022ds: could not map global utilities device\n");
    392		return;
    393	}
    394
    395	/* Convert pixclock from a wavelength to a frequency */
    396	temp = 1000000000000ULL;
    397	do_div(temp, pixclock);
    398	freq = temp;
    399
    400	/*
    401	 * 'pxclk' is the ratio of the platform clock to the pixel clock.
    402	 * This number is programmed into the CLKDVDR register, and the valid
    403	 * range of values is 2-255.
    404	 */
    405	pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
    406	pxclk = clamp_t(u32, pxclk, 2, 255);
    407
    408	/* Disable the pixel clock, and set it to non-inverted and no delay */
    409	clrbits32(&guts->clkdvdr,
    410		  CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
    411
    412	/* Enable the clock and set the pxclk */
    413	setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
    414
    415	iounmap(guts);
    416}
    417
    418/**
    419 * p1022ds_valid_monitor_port: set the monitor port for sysfs
    420 */
    421enum fsl_diu_monitor_port
    422p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port)
    423{
    424	switch (port) {
    425	case FSL_DIU_PORT_DVI:
    426	case FSL_DIU_PORT_LVDS:
    427		return port;
    428	default:
    429		return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */
    430	}
    431}
    432
    433#endif
    434
    435void __init p1022_ds_pic_init(void)
    436{
    437	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
    438		MPIC_SINGLE_DEST_CPU,
    439		0, 256, " OpenPIC  ");
    440	BUG_ON(mpic == NULL);
    441	mpic_init(mpic);
    442}
    443
    444#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
    445
    446/* TRUE if there is a "video=fslfb" command-line parameter. */
    447static bool fslfb;
    448
    449/*
    450 * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to
    451 * true if we find it.
    452 *
    453 * We need to use early_param() instead of __setup() because the normal
    454 * __setup() gets called to late.  However, early_param() gets called very
    455 * early, before the device tree is unflattened, so all we can do now is set a
    456 * global variable.  Later on, p1022_ds_setup_arch() will use that variable
    457 * to determine if we need to update the device tree.
    458 */
    459static int __init early_video_setup(char *options)
    460{
    461	fslfb = (strncmp(options, "fslfb:", 6) == 0);
    462
    463	return 0;
    464}
    465early_param("video", early_video_setup);
    466
    467#endif
    468
    469/*
    470 * Setup the architecture
    471 */
    472static void __init p1022_ds_setup_arch(void)
    473{
    474	if (ppc_md.progress)
    475		ppc_md.progress("p1022_ds_setup_arch()", 0);
    476
    477#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
    478	diu_ops.set_monitor_port	= p1022ds_set_monitor_port;
    479	diu_ops.set_pixel_clock		= p1022ds_set_pixel_clock;
    480	diu_ops.valid_monitor_port	= p1022ds_valid_monitor_port;
    481
    482	/*
    483	 * Disable the NOR and NAND flash nodes if there is video=fslfb...
    484	 * command-line parameter.  When the DIU is active, the localbus is
    485	 * unavailable, so we have to disable these nodes before the MTD
    486	 * driver loads.
    487	 */
    488	if (fslfb) {
    489		struct device_node *np =
    490			of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc");
    491
    492		if (np) {
    493			struct device_node *np2;
    494
    495			of_node_get(np);
    496			np2 = of_find_compatible_node(np, NULL, "cfi-flash");
    497			if (np2) {
    498				static struct property nor_status = {
    499					.name = "status",
    500					.value = "disabled",
    501					.length = sizeof("disabled"),
    502				};
    503
    504				/*
    505				 * of_update_property() is called before
    506				 * kmalloc() is available, so the 'new' object
    507				 * should be allocated in the global area.
    508				 * The easiest way is to do that is to
    509				 * allocate one static local variable for each
    510				 * call to this function.
    511				 */
    512				pr_info("p1022ds: disabling %pOF node",
    513					np2);
    514				of_update_property(np2, &nor_status);
    515				of_node_put(np2);
    516			}
    517
    518			of_node_get(np);
    519			np2 = of_find_compatible_node(np, NULL,
    520						      "fsl,elbc-fcm-nand");
    521			if (np2) {
    522				static struct property nand_status = {
    523					.name = "status",
    524					.value = "disabled",
    525					.length = sizeof("disabled"),
    526				};
    527
    528				pr_info("p1022ds: disabling %pOF node",
    529					np2);
    530				of_update_property(np2, &nand_status);
    531				of_node_put(np2);
    532			}
    533
    534			of_node_put(np);
    535		}
    536
    537	}
    538
    539#endif
    540
    541	mpc85xx_smp_init();
    542
    543	fsl_pci_assign_primary();
    544
    545	swiotlb_detect_4g();
    546
    547	pr_info("Freescale P1022 DS reference board\n");
    548}
    549
    550machine_arch_initcall(p1022_ds, mpc85xx_common_publish_devices);
    551
    552/*
    553 * Called very early, device-tree isn't unflattened
    554 */
    555static int __init p1022_ds_probe(void)
    556{
    557	return of_machine_is_compatible("fsl,p1022ds");
    558}
    559
    560define_machine(p1022_ds) {
    561	.name			= "P1022 DS",
    562	.probe			= p1022_ds_probe,
    563	.setup_arch		= p1022_ds_setup_arch,
    564	.init_IRQ		= p1022_ds_pic_init,
    565#ifdef CONFIG_PCI
    566	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
    567	.pcibios_fixup_phb	= fsl_pcibios_fixup_phb,
    568#endif
    569	.get_irq		= mpic_get_irq,
    570	.calibrate_decr		= generic_calibrate_decr,
    571	.progress		= udbg_progress,
    572};