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

4xx.c (20430B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2007 David Gibson, IBM Corporation.
      4 *
      5 * Based on earlier code:
      6 *   Matt Porter <mporter@kernel.crashing.org>
      7 *   Copyright 2002-2005 MontaVista Software Inc.
      8 *
      9 *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
     10 *   Copyright (c) 2003, 2004 Zultys Technologies
     11 *
     12 * Copyright (C) 2009 Wind River Systems, Inc.
     13 *   Updated for supporting PPC405EX on Kilauea.
     14 *   Tiejun Chen <tiejun.chen@windriver.com>
     15 */
     16#include <stddef.h>
     17#include "types.h"
     18#include "string.h"
     19#include "stdio.h"
     20#include "ops.h"
     21#include "reg.h"
     22#include "dcr.h"
     23
     24static unsigned long chip_11_errata(unsigned long memsize)
     25{
     26	unsigned long pvr;
     27
     28	pvr = mfpvr();
     29
     30	switch (pvr & 0xf0000ff0) {
     31		case 0x40000850:
     32		case 0x400008d0:
     33		case 0x200008d0:
     34			memsize -= 4096;
     35			break;
     36		default:
     37			break;
     38	}
     39
     40	return memsize;
     41}
     42
     43/* Read the 4xx SDRAM controller to get size of system memory. */
     44void ibm4xx_sdram_fixup_memsize(void)
     45{
     46	int i;
     47	unsigned long memsize, bank_config;
     48
     49	memsize = 0;
     50	for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
     51		bank_config = SDRAM0_READ(sdram_bxcr[i]);
     52		if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
     53			memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
     54	}
     55
     56	memsize = chip_11_errata(memsize);
     57	dt_fixup_memory(0, memsize);
     58}
     59
     60/* Read the 440SPe MQ controller to get size of system memory. */
     61#define DCRN_MQ0_B0BAS		0x40
     62#define DCRN_MQ0_B1BAS		0x41
     63#define DCRN_MQ0_B2BAS		0x42
     64#define DCRN_MQ0_B3BAS		0x43
     65
     66static u64 ibm440spe_decode_bas(u32 bas)
     67{
     68	u64 base = ((u64)(bas & 0xFFE00000u)) << 2;
     69
     70	/* open coded because I'm paranoid about invalid values */
     71	switch ((bas >> 4) & 0xFFF) {
     72	case 0:
     73		return 0;
     74	case 0xffc:
     75		return base + 0x000800000ull;
     76	case 0xff8:
     77		return base + 0x001000000ull;
     78	case 0xff0:
     79		return base + 0x002000000ull;
     80	case 0xfe0:
     81		return base + 0x004000000ull;
     82	case 0xfc0:
     83		return base + 0x008000000ull;
     84	case 0xf80:
     85		return base + 0x010000000ull;
     86	case 0xf00:
     87		return base + 0x020000000ull;
     88	case 0xe00:
     89		return base + 0x040000000ull;
     90	case 0xc00:
     91		return base + 0x080000000ull;
     92	case 0x800:
     93		return base + 0x100000000ull;
     94	}
     95	printf("Memory BAS value 0x%08x unsupported !\n", bas);
     96	return 0;
     97}
     98
     99void ibm440spe_fixup_memsize(void)
    100{
    101	u64 banktop, memsize = 0;
    102
    103	/* Ultimately, we should directly construct the memory node
    104	 * so we are able to handle holes in the memory address space
    105	 */
    106	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B0BAS));
    107	if (banktop > memsize)
    108		memsize = banktop;
    109	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B1BAS));
    110	if (banktop > memsize)
    111		memsize = banktop;
    112	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B2BAS));
    113	if (banktop > memsize)
    114		memsize = banktop;
    115	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B3BAS));
    116	if (banktop > memsize)
    117		memsize = banktop;
    118
    119	dt_fixup_memory(0, memsize);
    120}
    121
    122
    123/* 4xx DDR1/2 Denali memory controller support */
    124/* DDR0 registers */
    125#define DDR0_02			2
    126#define DDR0_08			8
    127#define DDR0_10			10
    128#define DDR0_14			14
    129#define DDR0_42			42
    130#define DDR0_43			43
    131
    132/* DDR0_02 */
    133#define DDR_START		0x1
    134#define DDR_START_SHIFT		0
    135#define DDR_MAX_CS_REG		0x3
    136#define DDR_MAX_CS_REG_SHIFT	24
    137#define DDR_MAX_COL_REG		0xf
    138#define DDR_MAX_COL_REG_SHIFT	16
    139#define DDR_MAX_ROW_REG		0xf
    140#define DDR_MAX_ROW_REG_SHIFT	8
    141/* DDR0_08 */
    142#define DDR_DDR2_MODE		0x1
    143#define DDR_DDR2_MODE_SHIFT	0
    144/* DDR0_10 */
    145#define DDR_CS_MAP		0x3
    146#define DDR_CS_MAP_SHIFT	8
    147/* DDR0_14 */
    148#define DDR_REDUC		0x1
    149#define DDR_REDUC_SHIFT		16
    150/* DDR0_42 */
    151#define DDR_APIN		0x7
    152#define DDR_APIN_SHIFT		24
    153/* DDR0_43 */
    154#define DDR_COL_SZ		0x7
    155#define DDR_COL_SZ_SHIFT	8
    156#define DDR_BANK8		0x1
    157#define DDR_BANK8_SHIFT		0
    158
    159#define DDR_GET_VAL(val, mask, shift)	(((val) >> (shift)) & (mask))
    160
    161/*
    162 * Some U-Boot versions set the number of chipselects to two
    163 * for Sequoia/Rainier boards while they only have one chipselect
    164 * hardwired. Hardcode the number of chipselects to one
    165 * for sequioa/rainer board models or read the actual value
    166 * from the memory controller register DDR0_10 otherwise.
    167 */
    168static inline u32 ibm4xx_denali_get_cs(void)
    169{
    170	void *devp;
    171	char model[64];
    172	u32 val, cs;
    173
    174	devp = finddevice("/");
    175	if (!devp)
    176		goto read_cs;
    177
    178	if (getprop(devp, "model", model, sizeof(model)) <= 0)
    179		goto read_cs;
    180
    181	model[sizeof(model)-1] = 0;
    182
    183	if (!strcmp(model, "amcc,sequoia") ||
    184	    !strcmp(model, "amcc,rainier"))
    185		return 1;
    186
    187read_cs:
    188	/* get CS value */
    189	val = SDRAM0_READ(DDR0_10);
    190
    191	val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT);
    192	cs = 0;
    193	while (val) {
    194		if (val & 0x1)
    195			cs++;
    196		val = val >> 1;
    197	}
    198	return cs;
    199}
    200
    201void ibm4xx_denali_fixup_memsize(void)
    202{
    203	u32 val, max_cs, max_col, max_row;
    204	u32 cs, col, row, bank, dpath;
    205	unsigned long memsize;
    206
    207	val = SDRAM0_READ(DDR0_02);
    208	if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
    209		fatal("DDR controller is not initialized\n");
    210
    211	/* get maximum cs col and row values */
    212	max_cs  = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
    213	max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
    214	max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
    215
    216	cs = ibm4xx_denali_get_cs();
    217	if (!cs)
    218		fatal("No memory installed\n");
    219	if (cs > max_cs)
    220		fatal("DDR wrong CS configuration\n");
    221
    222	/* get data path bytes */
    223	val = SDRAM0_READ(DDR0_14);
    224
    225	if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT))
    226		dpath = 4; /* 32 bits */
    227	else
    228		dpath = 8; /* 64 bits */
    229
    230	/* get address pins (rows) */
    231	val = SDRAM0_READ(DDR0_42);
    232
    233	row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT);
    234	if (row > max_row)
    235		fatal("DDR wrong APIN configuration\n");
    236	row = max_row - row;
    237
    238	/* get collomn size and banks */
    239	val = SDRAM0_READ(DDR0_43);
    240
    241	col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT);
    242	if (col > max_col)
    243		fatal("DDR wrong COL configuration\n");
    244	col = max_col - col;
    245
    246	if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT))
    247		bank = 8; /* 8 banks */
    248	else
    249		bank = 4; /* 4 banks */
    250
    251	memsize = cs * (1 << (col+row)) * bank * dpath;
    252	memsize = chip_11_errata(memsize);
    253	dt_fixup_memory(0, memsize);
    254}
    255
    256#define SPRN_DBCR0_40X 0x3F2
    257#define SPRN_DBCR0_44X 0x134
    258#define DBCR0_RST_SYSTEM 0x30000000
    259
    260void ibm44x_dbcr_reset(void)
    261{
    262	unsigned long tmp;
    263
    264	asm volatile (
    265		"mfspr	%0,%1\n"
    266		"oris	%0,%0,%2@h\n"
    267		"mtspr	%1,%0"
    268		: "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM)
    269		);
    270
    271}
    272
    273void ibm40x_dbcr_reset(void)
    274{
    275	unsigned long tmp;
    276
    277	asm volatile (
    278		"mfspr	%0,%1\n"
    279		"oris	%0,%0,%2@h\n"
    280		"mtspr	%1,%0"
    281		: "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM)
    282		);
    283}
    284
    285#define EMAC_RESET 0x20000000
    286void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
    287{
    288	/* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
    289	 * do this for us
    290	 */
    291	if (emac0)
    292		*emac0 = EMAC_RESET;
    293	if (emac1)
    294		*emac1 = EMAC_RESET;
    295
    296	mtdcr(DCRN_MAL0_CFG, MAL_RESET);
    297	while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET)
    298		; /* loop until reset takes effect */
    299}
    300
    301/* Read 4xx EBC bus bridge registers to get mappings of the peripheral
    302 * banks into the OPB address space */
    303void ibm4xx_fixup_ebc_ranges(const char *ebc)
    304{
    305	void *devp;
    306	u32 bxcr;
    307	u32 ranges[EBC_NUM_BANKS*4];
    308	u32 *p = ranges;
    309	int i;
    310
    311	for (i = 0; i < EBC_NUM_BANKS; i++) {
    312		mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
    313		bxcr = mfdcr(DCRN_EBC0_CFGDATA);
    314
    315		if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
    316			*p++ = i;
    317			*p++ = 0;
    318			*p++ = bxcr & EBC_BXCR_BAS;
    319			*p++ = EBC_BXCR_BANK_SIZE(bxcr);
    320		}
    321	}
    322
    323	devp = finddevice(ebc);
    324	if (! devp)
    325		fatal("Couldn't locate EBC node %s\n\r", ebc);
    326
    327	setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
    328}
    329
    330/* Calculate 440GP clocks */
    331void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
    332{
    333	u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
    334	u32 cr0 = mfdcr(DCRN_CPC0_CR0);
    335	u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
    336	u32 opdv = CPC0_SYS0_OPDV(sys0);
    337	u32 epdv = CPC0_SYS0_EPDV(sys0);
    338
    339	if (sys0 & CPC0_SYS0_BYPASS) {
    340		/* Bypass system PLL */
    341		cpu = plb = sys_clk;
    342	} else {
    343		if (sys0 & CPC0_SYS0_EXTSL)
    344			/* PerClk */
    345			m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
    346		else
    347			/* CPU clock */
    348			m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
    349		cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0);
    350		plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0);
    351	}
    352
    353	opb = plb / opdv;
    354	ebc = opb / epdv;
    355
    356	/* FIXME: Check if this is for all 440GP, or just Ebony */
    357	if ((mfpvr() & 0xf0000fff) == 0x40000440)
    358		/* Rev. B 440GP, use external system clock */
    359		tb = sys_clk;
    360	else
    361		/* Rev. C 440GP, errata force us to use internal clock */
    362		tb = cpu;
    363
    364	if (cr0 & CPC0_CR0_U0EC)
    365		/* External UART clock */
    366		uart0 = ser_clk;
    367	else
    368		/* Internal UART clock */
    369		uart0 = plb / CPC0_CR0_UDIV(cr0);
    370
    371	if (cr0 & CPC0_CR0_U1EC)
    372		/* External UART clock */
    373		uart1 = ser_clk;
    374	else
    375		/* Internal UART clock */
    376		uart1 = plb / CPC0_CR0_UDIV(cr0);
    377
    378	printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
    379	       (sys_clk + 500000) / 1000000, sys_clk);
    380
    381	dt_fixup_cpu_clocks(cpu, tb, 0);
    382
    383	dt_fixup_clock("/plb", plb);
    384	dt_fixup_clock("/plb/opb", opb);
    385	dt_fixup_clock("/plb/opb/ebc", ebc);
    386	dt_fixup_clock("/plb/opb/serial@40000200", uart0);
    387	dt_fixup_clock("/plb/opb/serial@40000300", uart1);
    388}
    389
    390#define SPRN_CCR1 0x378
    391
    392static inline u32 __fix_zero(u32 v, u32 def)
    393{
    394	return v ? v : def;
    395}
    396
    397static unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk,
    398						unsigned int tmr_clk,
    399						int per_clk_from_opb)
    400{
    401	/* PLL config */
    402	u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
    403	u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
    404
    405	/* Dividers */
    406	u32 fbdv   = __fix_zero((plld >> 24) & 0x1f, 32);
    407	u32 fwdva  = __fix_zero((plld >> 16) & 0xf, 16);
    408	u32 fwdvb  = __fix_zero((plld >> 8) & 7, 8);
    409	u32 lfbdv  = __fix_zero(plld & 0x3f, 64);
    410	u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8);
    411	u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8);
    412	u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4);
    413	u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4);
    414
    415	/* Input clocks for primary dividers */
    416	u32 clk_a, clk_b;
    417
    418	/* Resulting clocks */
    419	u32 cpu, plb, opb, ebc, vco;
    420
    421	/* Timebase */
    422	u32 ccr1, tb = tmr_clk;
    423
    424	if (pllc & 0x40000000) {
    425		u32 m;
    426
    427		/* Feedback path */
    428		switch ((pllc >> 24) & 7) {
    429		case 0:
    430			/* PLLOUTx */
    431			m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
    432			break;
    433		case 1:
    434			/* CPU */
    435			m = fwdva * pradv0;
    436			break;
    437		case 5:
    438			/* PERClk */
    439			m = fwdvb * prbdv0 * opbdv0 * perdv0;
    440			break;
    441		default:
    442			printf("WARNING ! Invalid PLL feedback source !\n");
    443			goto bypass;
    444		}
    445		m *= fbdv;
    446		vco = sys_clk * m;
    447		clk_a = vco / fwdva;
    448		clk_b = vco / fwdvb;
    449	} else {
    450bypass:
    451		/* Bypass system PLL */
    452		vco = 0;
    453		clk_a = clk_b = sys_clk;
    454	}
    455
    456	cpu = clk_a / pradv0;
    457	plb = clk_b / prbdv0;
    458	opb = plb / opbdv0;
    459	ebc = (per_clk_from_opb ? opb : plb) / perdv0;
    460
    461	/* Figure out timebase.  Either CPU or default TmrClk */
    462	ccr1 = mfspr(SPRN_CCR1);
    463
    464	/* If passed a 0 tmr_clk, force CPU clock */
    465	if (tb == 0) {
    466		ccr1 &= ~0x80u;
    467		mtspr(SPRN_CCR1, ccr1);
    468	}
    469	if ((ccr1 & 0x0080) == 0)
    470		tb = cpu;
    471
    472	dt_fixup_cpu_clocks(cpu, tb, 0);
    473	dt_fixup_clock("/plb", plb);
    474	dt_fixup_clock("/plb/opb", opb);
    475	dt_fixup_clock("/plb/opb/ebc", ebc);
    476
    477	return plb;
    478}
    479
    480static void eplike_fixup_uart_clk(int index, const char *path,
    481				  unsigned int ser_clk,
    482				  unsigned int plb_clk)
    483{
    484	unsigned int sdr;
    485	unsigned int clock;
    486
    487	switch (index) {
    488	case 0:
    489		sdr = SDR0_READ(DCRN_SDR0_UART0);
    490		break;
    491	case 1:
    492		sdr = SDR0_READ(DCRN_SDR0_UART1);
    493		break;
    494	case 2:
    495		sdr = SDR0_READ(DCRN_SDR0_UART2);
    496		break;
    497	case 3:
    498		sdr = SDR0_READ(DCRN_SDR0_UART3);
    499		break;
    500	default:
    501		return;
    502	}
    503
    504	if (sdr & 0x00800000u)
    505		clock = ser_clk;
    506	else
    507		clock = plb_clk / __fix_zero(sdr & 0xff, 256);
    508
    509	dt_fixup_clock(path, clock);
    510}
    511
    512void ibm440ep_fixup_clocks(unsigned int sys_clk,
    513			   unsigned int ser_clk,
    514			   unsigned int tmr_clk)
    515{
    516	unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
    517
    518	/* serial clocks need fixup based on int/ext */
    519	eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
    520	eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
    521	eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
    522	eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk);
    523}
    524
    525void ibm440gx_fixup_clocks(unsigned int sys_clk,
    526			   unsigned int ser_clk,
    527			   unsigned int tmr_clk)
    528{
    529	unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
    530
    531	/* serial clocks need fixup based on int/ext */
    532	eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
    533	eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
    534}
    535
    536void ibm440spe_fixup_clocks(unsigned int sys_clk,
    537			    unsigned int ser_clk,
    538			    unsigned int tmr_clk)
    539{
    540	unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
    541
    542	/* serial clocks need fixup based on int/ext */
    543	eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk);
    544	eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk);
    545	eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk);
    546}
    547
    548void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
    549{
    550	u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
    551	u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
    552	u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
    553	u32 psr = mfdcr(DCRN_405_CPC0_PSR);
    554	u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
    555	u32 fwdv, fwdvb, fbdv, cbdv, opdv, epdv, ppdv, udiv;
    556
    557	fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
    558	fbdv = (pllmr & 0x1e000000) >> 25;
    559	if (fbdv == 0)
    560		fbdv = 16;
    561	cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */
    562	opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */
    563	ppdv = ((pllmr & 0x00006000) >> 13) + 1; /* PLB:PCI */
    564	epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */
    565	udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
    566
    567	/* check for 405GPr */
    568	if ((mfpvr() & 0xfffffff0) == (0x50910951 & 0xfffffff0)) {
    569		fwdvb = 8 - (pllmr & 0x00000007);
    570		if (!(psr & 0x00001000)) /* PCI async mode enable == 0 */
    571			if (psr & 0x00000020) /* New mode enable */
    572				m = fwdvb * 2 * ppdv;
    573			else
    574				m = fwdvb * cbdv * ppdv;
    575		else if (psr & 0x00000020) /* New mode enable */
    576			if (psr & 0x00000800) /* PerClk synch mode */
    577				m = fwdvb * 2 * epdv;
    578			else
    579				m = fbdv * fwdv;
    580		else if (epdv == fbdv)
    581			m = fbdv * cbdv * epdv;
    582		else
    583			m = fbdv * fwdvb * cbdv;
    584
    585		cpu = sys_clk * m / fwdv;
    586		plb = sys_clk * m / (fwdvb * cbdv);
    587	} else {
    588		m = fwdv * fbdv * cbdv;
    589		cpu = sys_clk * m / fwdv;
    590		plb = cpu / cbdv;
    591	}
    592	opb = plb / opdv;
    593	ebc = plb / epdv;
    594
    595	if (cpc0_cr0 & 0x80)
    596		/* uart0 uses the external clock */
    597		uart0 = ser_clk;
    598	else
    599		uart0 = cpu / udiv;
    600
    601	if (cpc0_cr0 & 0x40)
    602		/* uart1 uses the external clock */
    603		uart1 = ser_clk;
    604	else
    605		uart1 = cpu / udiv;
    606
    607	/* setup the timebase clock to tick at the cpu frequency */
    608	cpc0_cr1 = cpc0_cr1 & ~0x00800000;
    609	mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
    610	tb = cpu;
    611
    612	dt_fixup_cpu_clocks(cpu, tb, 0);
    613	dt_fixup_clock("/plb", plb);
    614	dt_fixup_clock("/plb/opb", opb);
    615	dt_fixup_clock("/plb/ebc", ebc);
    616	dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
    617	dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
    618}
    619
    620
    621void ibm405ep_fixup_clocks(unsigned int sys_clk)
    622{
    623	u32 pllmr0 = mfdcr(DCRN_CPC0_PLLMR0);
    624	u32 pllmr1 = mfdcr(DCRN_CPC0_PLLMR1);
    625	u32 cpc0_ucr = mfdcr(DCRN_CPC0_UCR);
    626	u32 cpu, plb, opb, ebc, uart0, uart1;
    627	u32 fwdva, fwdvb, fbdv, cbdv, opdv, epdv;
    628	u32 pllmr0_ccdv, tb, m;
    629
    630	fwdva = 8 - ((pllmr1 & 0x00070000) >> 16);
    631	fwdvb = 8 - ((pllmr1 & 0x00007000) >> 12);
    632	fbdv = (pllmr1 & 0x00f00000) >> 20;
    633	if (fbdv == 0)
    634		fbdv = 16;
    635
    636	cbdv = ((pllmr0 & 0x00030000) >> 16) + 1; /* CPU:PLB */
    637	epdv = ((pllmr0 & 0x00000300) >> 8) + 2;  /* PLB:EBC */
    638	opdv = ((pllmr0 & 0x00003000) >> 12) + 1; /* PLB:OPB */
    639
    640	m = fbdv * fwdvb;
    641
    642	pllmr0_ccdv = ((pllmr0 & 0x00300000) >> 20) + 1;
    643	if (pllmr1 & 0x80000000)
    644		cpu = sys_clk * m / (fwdva * pllmr0_ccdv);
    645	else
    646		cpu = sys_clk / pllmr0_ccdv;
    647
    648	plb = cpu / cbdv;
    649	opb = plb / opdv;
    650	ebc = plb / epdv;
    651	tb = cpu;
    652	uart0 = cpu / (cpc0_ucr & 0x0000007f);
    653	uart1 = cpu / ((cpc0_ucr & 0x00007f00) >> 8);
    654
    655	dt_fixup_cpu_clocks(cpu, tb, 0);
    656	dt_fixup_clock("/plb", plb);
    657	dt_fixup_clock("/plb/opb", opb);
    658	dt_fixup_clock("/plb/ebc", ebc);
    659	dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
    660	dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
    661}
    662
    663static u8 ibm405ex_fwdv_multi_bits[] = {
    664	/* values for:  1 - 16 */
    665	0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05,
    666	0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03
    667};
    668
    669u32 ibm405ex_get_fwdva(unsigned long cpr_fwdv)
    670{
    671	u32 index;
    672
    673	for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++)
    674		if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index])
    675			return index + 1;
    676
    677	return 0;
    678}
    679
    680static u8 ibm405ex_fbdv_multi_bits[] = {
    681	/* values for:  1 - 100 */
    682	0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
    683	0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
    684	0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
    685	0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
    686	0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
    687	0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
    688	0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
    689	0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
    690	0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
    691	0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
    692	/* values for:  101 - 200 */
    693	0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
    694	0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
    695	0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
    696	0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
    697	0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
    698	0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
    699	0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
    700	0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
    701	0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
    702	0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
    703	/* values for:  201 - 255 */
    704	0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
    705	0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
    706	0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
    707	0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
    708	0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
    709	0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
    710};
    711
    712u32 ibm405ex_get_fbdv(unsigned long cpr_fbdv)
    713{
    714	u32 index;
    715
    716	for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++)
    717		if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index])
    718			return index + 1;
    719
    720	return 0;
    721}
    722
    723void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk)
    724{
    725	/* PLL config */
    726	u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
    727	u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
    728	u32 cpud  = CPR0_READ(DCRN_CPR0_PRIMAD);
    729	u32 plbd  = CPR0_READ(DCRN_CPR0_PRIMBD);
    730	u32 opbd  = CPR0_READ(DCRN_CPR0_OPBD);
    731	u32 perd  = CPR0_READ(DCRN_CPR0_PERD);
    732
    733	/* Dividers */
    734	u32 fbdv   = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1));
    735
    736	u32 fwdva  = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1));
    737
    738	u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8);
    739
    740	/* PLBDV0 is hardwared to 010. */
    741	u32 plbdv0 = 2;
    742	u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8);
    743
    744	u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4);
    745
    746	u32 perdv0 = __fix_zero((perd >> 24) & 3, 4);
    747
    748	/* Resulting clocks */
    749	u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1;
    750
    751	/* PLL's VCO is the source for primary forward ? */
    752	if (pllc & 0x40000000) {
    753		u32 m;
    754
    755		/* Feedback path */
    756		switch ((pllc >> 24) & 7) {
    757		case 0:
    758			/* PLLOUTx */
    759			m = fbdv;
    760			break;
    761		case 1:
    762			/* CPU */
    763			m = fbdv * fwdva * cpudv0;
    764			break;
    765		case 5:
    766			/* PERClk */
    767			m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0;
    768			break;
    769		default:
    770			printf("WARNING ! Invalid PLL feedback source !\n");
    771			goto bypass;
    772		}
    773
    774		vco = (unsigned int)(sys_clk * m);
    775	} else {
    776bypass:
    777		/* Bypass system PLL */
    778		vco = 0;
    779	}
    780
    781	/* CPU = VCO / ( FWDVA x CPUDV0) */
    782	cpu = vco / (fwdva * cpudv0);
    783	/* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */
    784	plb = vco / (fwdva * plb2xdv0 * plbdv0);
    785	/* OPB = PLB / OPBDV0 */
    786	opb = plb / opbdv0;
    787	/* EBC = OPB / PERDV0 */
    788	ebc = opb / perdv0;
    789
    790	tb = cpu;
    791	uart0 = uart1 = uart_clk;
    792
    793	dt_fixup_cpu_clocks(cpu, tb, 0);
    794	dt_fixup_clock("/plb", plb);
    795	dt_fixup_clock("/plb/opb", opb);
    796	dt_fixup_clock("/plb/opb/ebc", ebc);
    797	dt_fixup_clock("/plb/opb/serial@ef600200", uart0);
    798	dt_fixup_clock("/plb/opb/serial@ef600300", uart1);
    799}