162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2007 David Gibson, IBM Corporation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on earlier code: 662306a36Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 762306a36Sopenharmony_ci * Copyright 2002-2005 MontaVista Software Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> 1062306a36Sopenharmony_ci * Copyright (c) 2003, 2004 Zultys Technologies 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Copyright (C) 2009 Wind River Systems, Inc. 1362306a36Sopenharmony_ci * Updated for supporting PPC405EX on Kilauea. 1462306a36Sopenharmony_ci * Tiejun Chen <tiejun.chen@windriver.com> 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci#include <stddef.h> 1762306a36Sopenharmony_ci#include "types.h" 1862306a36Sopenharmony_ci#include "string.h" 1962306a36Sopenharmony_ci#include "stdio.h" 2062306a36Sopenharmony_ci#include "ops.h" 2162306a36Sopenharmony_ci#include "reg.h" 2262306a36Sopenharmony_ci#include "dcr.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic unsigned long chip_11_errata(unsigned long memsize) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci unsigned long pvr; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci pvr = mfpvr(); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci switch (pvr & 0xf0000ff0) { 3162306a36Sopenharmony_ci case 0x40000850: 3262306a36Sopenharmony_ci case 0x400008d0: 3362306a36Sopenharmony_ci case 0x200008d0: 3462306a36Sopenharmony_ci memsize -= 4096; 3562306a36Sopenharmony_ci break; 3662306a36Sopenharmony_ci default: 3762306a36Sopenharmony_ci break; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci return memsize; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Read the 4xx SDRAM controller to get size of system memory. */ 4462306a36Sopenharmony_civoid ibm4xx_sdram_fixup_memsize(void) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci int i; 4762306a36Sopenharmony_ci unsigned long memsize, bank_config; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci memsize = 0; 5062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) { 5162306a36Sopenharmony_ci bank_config = SDRAM0_READ(sdram_bxcr[i]); 5262306a36Sopenharmony_ci if (bank_config & SDRAM_CONFIG_BANK_ENABLE) 5362306a36Sopenharmony_ci memsize += SDRAM_CONFIG_BANK_SIZE(bank_config); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci memsize = chip_11_errata(memsize); 5762306a36Sopenharmony_ci dt_fixup_memory(0, memsize); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Read the 440SPe MQ controller to get size of system memory. */ 6162306a36Sopenharmony_ci#define DCRN_MQ0_B0BAS 0x40 6262306a36Sopenharmony_ci#define DCRN_MQ0_B1BAS 0x41 6362306a36Sopenharmony_ci#define DCRN_MQ0_B2BAS 0x42 6462306a36Sopenharmony_ci#define DCRN_MQ0_B3BAS 0x43 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic u64 ibm440spe_decode_bas(u32 bas) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci u64 base = ((u64)(bas & 0xFFE00000u)) << 2; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* open coded because I'm paranoid about invalid values */ 7162306a36Sopenharmony_ci switch ((bas >> 4) & 0xFFF) { 7262306a36Sopenharmony_ci case 0: 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci case 0xffc: 7562306a36Sopenharmony_ci return base + 0x000800000ull; 7662306a36Sopenharmony_ci case 0xff8: 7762306a36Sopenharmony_ci return base + 0x001000000ull; 7862306a36Sopenharmony_ci case 0xff0: 7962306a36Sopenharmony_ci return base + 0x002000000ull; 8062306a36Sopenharmony_ci case 0xfe0: 8162306a36Sopenharmony_ci return base + 0x004000000ull; 8262306a36Sopenharmony_ci case 0xfc0: 8362306a36Sopenharmony_ci return base + 0x008000000ull; 8462306a36Sopenharmony_ci case 0xf80: 8562306a36Sopenharmony_ci return base + 0x010000000ull; 8662306a36Sopenharmony_ci case 0xf00: 8762306a36Sopenharmony_ci return base + 0x020000000ull; 8862306a36Sopenharmony_ci case 0xe00: 8962306a36Sopenharmony_ci return base + 0x040000000ull; 9062306a36Sopenharmony_ci case 0xc00: 9162306a36Sopenharmony_ci return base + 0x080000000ull; 9262306a36Sopenharmony_ci case 0x800: 9362306a36Sopenharmony_ci return base + 0x100000000ull; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci printf("Memory BAS value 0x%08x unsupported !\n", bas); 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_civoid ibm440spe_fixup_memsize(void) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci u64 banktop, memsize = 0; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Ultimately, we should directly construct the memory node 10462306a36Sopenharmony_ci * so we are able to handle holes in the memory address space 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B0BAS)); 10762306a36Sopenharmony_ci if (banktop > memsize) 10862306a36Sopenharmony_ci memsize = banktop; 10962306a36Sopenharmony_ci banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B1BAS)); 11062306a36Sopenharmony_ci if (banktop > memsize) 11162306a36Sopenharmony_ci memsize = banktop; 11262306a36Sopenharmony_ci banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B2BAS)); 11362306a36Sopenharmony_ci if (banktop > memsize) 11462306a36Sopenharmony_ci memsize = banktop; 11562306a36Sopenharmony_ci banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B3BAS)); 11662306a36Sopenharmony_ci if (banktop > memsize) 11762306a36Sopenharmony_ci memsize = banktop; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci dt_fixup_memory(0, memsize); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 4xx DDR1/2 Denali memory controller support */ 12462306a36Sopenharmony_ci/* DDR0 registers */ 12562306a36Sopenharmony_ci#define DDR0_02 2 12662306a36Sopenharmony_ci#define DDR0_08 8 12762306a36Sopenharmony_ci#define DDR0_10 10 12862306a36Sopenharmony_ci#define DDR0_14 14 12962306a36Sopenharmony_ci#define DDR0_42 42 13062306a36Sopenharmony_ci#define DDR0_43 43 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* DDR0_02 */ 13362306a36Sopenharmony_ci#define DDR_START 0x1 13462306a36Sopenharmony_ci#define DDR_START_SHIFT 0 13562306a36Sopenharmony_ci#define DDR_MAX_CS_REG 0x3 13662306a36Sopenharmony_ci#define DDR_MAX_CS_REG_SHIFT 24 13762306a36Sopenharmony_ci#define DDR_MAX_COL_REG 0xf 13862306a36Sopenharmony_ci#define DDR_MAX_COL_REG_SHIFT 16 13962306a36Sopenharmony_ci#define DDR_MAX_ROW_REG 0xf 14062306a36Sopenharmony_ci#define DDR_MAX_ROW_REG_SHIFT 8 14162306a36Sopenharmony_ci/* DDR0_08 */ 14262306a36Sopenharmony_ci#define DDR_DDR2_MODE 0x1 14362306a36Sopenharmony_ci#define DDR_DDR2_MODE_SHIFT 0 14462306a36Sopenharmony_ci/* DDR0_10 */ 14562306a36Sopenharmony_ci#define DDR_CS_MAP 0x3 14662306a36Sopenharmony_ci#define DDR_CS_MAP_SHIFT 8 14762306a36Sopenharmony_ci/* DDR0_14 */ 14862306a36Sopenharmony_ci#define DDR_REDUC 0x1 14962306a36Sopenharmony_ci#define DDR_REDUC_SHIFT 16 15062306a36Sopenharmony_ci/* DDR0_42 */ 15162306a36Sopenharmony_ci#define DDR_APIN 0x7 15262306a36Sopenharmony_ci#define DDR_APIN_SHIFT 24 15362306a36Sopenharmony_ci/* DDR0_43 */ 15462306a36Sopenharmony_ci#define DDR_COL_SZ 0x7 15562306a36Sopenharmony_ci#define DDR_COL_SZ_SHIFT 8 15662306a36Sopenharmony_ci#define DDR_BANK8 0x1 15762306a36Sopenharmony_ci#define DDR_BANK8_SHIFT 0 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#define DDR_GET_VAL(val, mask, shift) (((val) >> (shift)) & (mask)) 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * Some U-Boot versions set the number of chipselects to two 16362306a36Sopenharmony_ci * for Sequoia/Rainier boards while they only have one chipselect 16462306a36Sopenharmony_ci * hardwired. Hardcode the number of chipselects to one 16562306a36Sopenharmony_ci * for sequioa/rainer board models or read the actual value 16662306a36Sopenharmony_ci * from the memory controller register DDR0_10 otherwise. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic inline u32 ibm4xx_denali_get_cs(void) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci void *devp; 17162306a36Sopenharmony_ci char model[64]; 17262306a36Sopenharmony_ci u32 val, cs; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci devp = finddevice("/"); 17562306a36Sopenharmony_ci if (!devp) 17662306a36Sopenharmony_ci goto read_cs; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (getprop(devp, "model", model, sizeof(model)) <= 0) 17962306a36Sopenharmony_ci goto read_cs; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci model[sizeof(model)-1] = 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (!strcmp(model, "amcc,sequoia") || 18462306a36Sopenharmony_ci !strcmp(model, "amcc,rainier")) 18562306a36Sopenharmony_ci return 1; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciread_cs: 18862306a36Sopenharmony_ci /* get CS value */ 18962306a36Sopenharmony_ci val = SDRAM0_READ(DDR0_10); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT); 19262306a36Sopenharmony_ci cs = 0; 19362306a36Sopenharmony_ci while (val) { 19462306a36Sopenharmony_ci if (val & 0x1) 19562306a36Sopenharmony_ci cs++; 19662306a36Sopenharmony_ci val = val >> 1; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci return cs; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_civoid ibm4xx_denali_fixup_memsize(void) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci u32 val, max_cs, max_col, max_row; 20462306a36Sopenharmony_ci u32 cs, col, row, bank, dpath; 20562306a36Sopenharmony_ci unsigned long memsize; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci val = SDRAM0_READ(DDR0_02); 20862306a36Sopenharmony_ci if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT)) 20962306a36Sopenharmony_ci fatal("DDR controller is not initialized\n"); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* get maximum cs col and row values */ 21262306a36Sopenharmony_ci max_cs = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT); 21362306a36Sopenharmony_ci max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT); 21462306a36Sopenharmony_ci max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci cs = ibm4xx_denali_get_cs(); 21762306a36Sopenharmony_ci if (!cs) 21862306a36Sopenharmony_ci fatal("No memory installed\n"); 21962306a36Sopenharmony_ci if (cs > max_cs) 22062306a36Sopenharmony_ci fatal("DDR wrong CS configuration\n"); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* get data path bytes */ 22362306a36Sopenharmony_ci val = SDRAM0_READ(DDR0_14); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT)) 22662306a36Sopenharmony_ci dpath = 4; /* 32 bits */ 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci dpath = 8; /* 64 bits */ 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* get address pins (rows) */ 23162306a36Sopenharmony_ci val = SDRAM0_READ(DDR0_42); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT); 23462306a36Sopenharmony_ci if (row > max_row) 23562306a36Sopenharmony_ci fatal("DDR wrong APIN configuration\n"); 23662306a36Sopenharmony_ci row = max_row - row; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* get collomn size and banks */ 23962306a36Sopenharmony_ci val = SDRAM0_READ(DDR0_43); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT); 24262306a36Sopenharmony_ci if (col > max_col) 24362306a36Sopenharmony_ci fatal("DDR wrong COL configuration\n"); 24462306a36Sopenharmony_ci col = max_col - col; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT)) 24762306a36Sopenharmony_ci bank = 8; /* 8 banks */ 24862306a36Sopenharmony_ci else 24962306a36Sopenharmony_ci bank = 4; /* 4 banks */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci memsize = cs * (1 << (col+row)) * bank * dpath; 25262306a36Sopenharmony_ci memsize = chip_11_errata(memsize); 25362306a36Sopenharmony_ci dt_fixup_memory(0, memsize); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci#define SPRN_DBCR0_40X 0x3F2 25762306a36Sopenharmony_ci#define SPRN_DBCR0_44X 0x134 25862306a36Sopenharmony_ci#define DBCR0_RST_SYSTEM 0x30000000 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_civoid ibm44x_dbcr_reset(void) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci unsigned long tmp; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci asm volatile ( 26562306a36Sopenharmony_ci "mfspr %0,%1\n" 26662306a36Sopenharmony_ci "oris %0,%0,%2@h\n" 26762306a36Sopenharmony_ci "mtspr %1,%0" 26862306a36Sopenharmony_ci : "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM) 26962306a36Sopenharmony_ci ); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_civoid ibm40x_dbcr_reset(void) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci unsigned long tmp; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci asm volatile ( 27862306a36Sopenharmony_ci "mfspr %0,%1\n" 27962306a36Sopenharmony_ci "oris %0,%0,%2@h\n" 28062306a36Sopenharmony_ci "mtspr %1,%0" 28162306a36Sopenharmony_ci : "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM) 28262306a36Sopenharmony_ci ); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#define EMAC_RESET 0x20000000 28662306a36Sopenharmony_civoid ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't 28962306a36Sopenharmony_ci * do this for us 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci if (emac0) 29262306a36Sopenharmony_ci *emac0 = EMAC_RESET; 29362306a36Sopenharmony_ci if (emac1) 29462306a36Sopenharmony_ci *emac1 = EMAC_RESET; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mtdcr(DCRN_MAL0_CFG, MAL_RESET); 29762306a36Sopenharmony_ci while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET) 29862306a36Sopenharmony_ci ; /* loop until reset takes effect */ 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* Read 4xx EBC bus bridge registers to get mappings of the peripheral 30262306a36Sopenharmony_ci * banks into the OPB address space */ 30362306a36Sopenharmony_civoid ibm4xx_fixup_ebc_ranges(const char *ebc) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci void *devp; 30662306a36Sopenharmony_ci u32 bxcr; 30762306a36Sopenharmony_ci u32 ranges[EBC_NUM_BANKS*4]; 30862306a36Sopenharmony_ci u32 *p = ranges; 30962306a36Sopenharmony_ci int i; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci for (i = 0; i < EBC_NUM_BANKS; i++) { 31262306a36Sopenharmony_ci mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i)); 31362306a36Sopenharmony_ci bxcr = mfdcr(DCRN_EBC0_CFGDATA); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) { 31662306a36Sopenharmony_ci *p++ = i; 31762306a36Sopenharmony_ci *p++ = 0; 31862306a36Sopenharmony_ci *p++ = bxcr & EBC_BXCR_BAS; 31962306a36Sopenharmony_ci *p++ = EBC_BXCR_BANK_SIZE(bxcr); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci devp = finddevice(ebc); 32462306a36Sopenharmony_ci if (! devp) 32562306a36Sopenharmony_ci fatal("Couldn't locate EBC node %s\n\r", ebc); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32)); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/* Calculate 440GP clocks */ 33162306a36Sopenharmony_civoid ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci u32 sys0 = mfdcr(DCRN_CPC0_SYS0); 33462306a36Sopenharmony_ci u32 cr0 = mfdcr(DCRN_CPC0_CR0); 33562306a36Sopenharmony_ci u32 cpu, plb, opb, ebc, tb, uart0, uart1, m; 33662306a36Sopenharmony_ci u32 opdv = CPC0_SYS0_OPDV(sys0); 33762306a36Sopenharmony_ci u32 epdv = CPC0_SYS0_EPDV(sys0); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (sys0 & CPC0_SYS0_BYPASS) { 34062306a36Sopenharmony_ci /* Bypass system PLL */ 34162306a36Sopenharmony_ci cpu = plb = sys_clk; 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci if (sys0 & CPC0_SYS0_EXTSL) 34462306a36Sopenharmony_ci /* PerClk */ 34562306a36Sopenharmony_ci m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv; 34662306a36Sopenharmony_ci else 34762306a36Sopenharmony_ci /* CPU clock */ 34862306a36Sopenharmony_ci m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0); 34962306a36Sopenharmony_ci cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0); 35062306a36Sopenharmony_ci plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci opb = plb / opdv; 35462306a36Sopenharmony_ci ebc = opb / epdv; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* FIXME: Check if this is for all 440GP, or just Ebony */ 35762306a36Sopenharmony_ci if ((mfpvr() & 0xf0000fff) == 0x40000440) 35862306a36Sopenharmony_ci /* Rev. B 440GP, use external system clock */ 35962306a36Sopenharmony_ci tb = sys_clk; 36062306a36Sopenharmony_ci else 36162306a36Sopenharmony_ci /* Rev. C 440GP, errata force us to use internal clock */ 36262306a36Sopenharmony_ci tb = cpu; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (cr0 & CPC0_CR0_U0EC) 36562306a36Sopenharmony_ci /* External UART clock */ 36662306a36Sopenharmony_ci uart0 = ser_clk; 36762306a36Sopenharmony_ci else 36862306a36Sopenharmony_ci /* Internal UART clock */ 36962306a36Sopenharmony_ci uart0 = plb / CPC0_CR0_UDIV(cr0); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (cr0 & CPC0_CR0_U1EC) 37262306a36Sopenharmony_ci /* External UART clock */ 37362306a36Sopenharmony_ci uart1 = ser_clk; 37462306a36Sopenharmony_ci else 37562306a36Sopenharmony_ci /* Internal UART clock */ 37662306a36Sopenharmony_ci uart1 = plb / CPC0_CR0_UDIV(cr0); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci printf("PPC440GP: SysClk = %dMHz (%x)\n\r", 37962306a36Sopenharmony_ci (sys_clk + 500000) / 1000000, sys_clk); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci dt_fixup_cpu_clocks(cpu, tb, 0); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci dt_fixup_clock("/plb", plb); 38462306a36Sopenharmony_ci dt_fixup_clock("/plb/opb", opb); 38562306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/ebc", ebc); 38662306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@40000200", uart0); 38762306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@40000300", uart1); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci#define SPRN_CCR1 0x378 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic inline u32 __fix_zero(u32 v, u32 def) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci return v ? v : def; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk, 39862306a36Sopenharmony_ci unsigned int tmr_clk, 39962306a36Sopenharmony_ci int per_clk_from_opb) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci /* PLL config */ 40262306a36Sopenharmony_ci u32 pllc = CPR0_READ(DCRN_CPR0_PLLC); 40362306a36Sopenharmony_ci u32 plld = CPR0_READ(DCRN_CPR0_PLLD); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Dividers */ 40662306a36Sopenharmony_ci u32 fbdv = __fix_zero((plld >> 24) & 0x1f, 32); 40762306a36Sopenharmony_ci u32 fwdva = __fix_zero((plld >> 16) & 0xf, 16); 40862306a36Sopenharmony_ci u32 fwdvb = __fix_zero((plld >> 8) & 7, 8); 40962306a36Sopenharmony_ci u32 lfbdv = __fix_zero(plld & 0x3f, 64); 41062306a36Sopenharmony_ci u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8); 41162306a36Sopenharmony_ci u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8); 41262306a36Sopenharmony_ci u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4); 41362306a36Sopenharmony_ci u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Input clocks for primary dividers */ 41662306a36Sopenharmony_ci u32 clk_a, clk_b; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* Resulting clocks */ 41962306a36Sopenharmony_ci u32 cpu, plb, opb, ebc, vco; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Timebase */ 42262306a36Sopenharmony_ci u32 ccr1, tb = tmr_clk; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (pllc & 0x40000000) { 42562306a36Sopenharmony_ci u32 m; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Feedback path */ 42862306a36Sopenharmony_ci switch ((pllc >> 24) & 7) { 42962306a36Sopenharmony_ci case 0: 43062306a36Sopenharmony_ci /* PLLOUTx */ 43162306a36Sopenharmony_ci m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv; 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case 1: 43462306a36Sopenharmony_ci /* CPU */ 43562306a36Sopenharmony_ci m = fwdva * pradv0; 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci case 5: 43862306a36Sopenharmony_ci /* PERClk */ 43962306a36Sopenharmony_ci m = fwdvb * prbdv0 * opbdv0 * perdv0; 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci printf("WARNING ! Invalid PLL feedback source !\n"); 44362306a36Sopenharmony_ci goto bypass; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci m *= fbdv; 44662306a36Sopenharmony_ci vco = sys_clk * m; 44762306a36Sopenharmony_ci clk_a = vco / fwdva; 44862306a36Sopenharmony_ci clk_b = vco / fwdvb; 44962306a36Sopenharmony_ci } else { 45062306a36Sopenharmony_cibypass: 45162306a36Sopenharmony_ci /* Bypass system PLL */ 45262306a36Sopenharmony_ci vco = 0; 45362306a36Sopenharmony_ci clk_a = clk_b = sys_clk; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci cpu = clk_a / pradv0; 45762306a36Sopenharmony_ci plb = clk_b / prbdv0; 45862306a36Sopenharmony_ci opb = plb / opbdv0; 45962306a36Sopenharmony_ci ebc = (per_clk_from_opb ? opb : plb) / perdv0; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Figure out timebase. Either CPU or default TmrClk */ 46262306a36Sopenharmony_ci ccr1 = mfspr(SPRN_CCR1); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* If passed a 0 tmr_clk, force CPU clock */ 46562306a36Sopenharmony_ci if (tb == 0) { 46662306a36Sopenharmony_ci ccr1 &= ~0x80u; 46762306a36Sopenharmony_ci mtspr(SPRN_CCR1, ccr1); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci if ((ccr1 & 0x0080) == 0) 47062306a36Sopenharmony_ci tb = cpu; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci dt_fixup_cpu_clocks(cpu, tb, 0); 47362306a36Sopenharmony_ci dt_fixup_clock("/plb", plb); 47462306a36Sopenharmony_ci dt_fixup_clock("/plb/opb", opb); 47562306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/ebc", ebc); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return plb; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void eplike_fixup_uart_clk(int index, const char *path, 48162306a36Sopenharmony_ci unsigned int ser_clk, 48262306a36Sopenharmony_ci unsigned int plb_clk) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci unsigned int sdr; 48562306a36Sopenharmony_ci unsigned int clock; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci switch (index) { 48862306a36Sopenharmony_ci case 0: 48962306a36Sopenharmony_ci sdr = SDR0_READ(DCRN_SDR0_UART0); 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case 1: 49262306a36Sopenharmony_ci sdr = SDR0_READ(DCRN_SDR0_UART1); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case 2: 49562306a36Sopenharmony_ci sdr = SDR0_READ(DCRN_SDR0_UART2); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case 3: 49862306a36Sopenharmony_ci sdr = SDR0_READ(DCRN_SDR0_UART3); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci default: 50162306a36Sopenharmony_ci return; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (sdr & 0x00800000u) 50562306a36Sopenharmony_ci clock = ser_clk; 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci clock = plb_clk / __fix_zero(sdr & 0xff, 256); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci dt_fixup_clock(path, clock); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_civoid ibm440ep_fixup_clocks(unsigned int sys_clk, 51362306a36Sopenharmony_ci unsigned int ser_clk, 51462306a36Sopenharmony_ci unsigned int tmr_clk) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* serial clocks need fixup based on int/ext */ 51962306a36Sopenharmony_ci eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk); 52062306a36Sopenharmony_ci eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk); 52162306a36Sopenharmony_ci eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk); 52262306a36Sopenharmony_ci eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_civoid ibm440gx_fixup_clocks(unsigned int sys_clk, 52662306a36Sopenharmony_ci unsigned int ser_clk, 52762306a36Sopenharmony_ci unsigned int tmr_clk) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* serial clocks need fixup based on int/ext */ 53262306a36Sopenharmony_ci eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk); 53362306a36Sopenharmony_ci eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_civoid ibm440spe_fixup_clocks(unsigned int sys_clk, 53762306a36Sopenharmony_ci unsigned int ser_clk, 53862306a36Sopenharmony_ci unsigned int tmr_clk) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* serial clocks need fixup based on int/ext */ 54362306a36Sopenharmony_ci eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk); 54462306a36Sopenharmony_ci eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk); 54562306a36Sopenharmony_ci eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_civoid ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci u32 pllmr = mfdcr(DCRN_CPC0_PLLMR); 55162306a36Sopenharmony_ci u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0); 55262306a36Sopenharmony_ci u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1); 55362306a36Sopenharmony_ci u32 psr = mfdcr(DCRN_405_CPC0_PSR); 55462306a36Sopenharmony_ci u32 cpu, plb, opb, ebc, tb, uart0, uart1, m; 55562306a36Sopenharmony_ci u32 fwdv, fwdvb, fbdv, cbdv, opdv, epdv, ppdv, udiv; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci fwdv = (8 - ((pllmr & 0xe0000000) >> 29)); 55862306a36Sopenharmony_ci fbdv = (pllmr & 0x1e000000) >> 25; 55962306a36Sopenharmony_ci if (fbdv == 0) 56062306a36Sopenharmony_ci fbdv = 16; 56162306a36Sopenharmony_ci cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */ 56262306a36Sopenharmony_ci opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */ 56362306a36Sopenharmony_ci ppdv = ((pllmr & 0x00006000) >> 13) + 1; /* PLB:PCI */ 56462306a36Sopenharmony_ci epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */ 56562306a36Sopenharmony_ci udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* check for 405GPr */ 56862306a36Sopenharmony_ci if ((mfpvr() & 0xfffffff0) == (0x50910951 & 0xfffffff0)) { 56962306a36Sopenharmony_ci fwdvb = 8 - (pllmr & 0x00000007); 57062306a36Sopenharmony_ci if (!(psr & 0x00001000)) /* PCI async mode enable == 0 */ 57162306a36Sopenharmony_ci if (psr & 0x00000020) /* New mode enable */ 57262306a36Sopenharmony_ci m = fwdvb * 2 * ppdv; 57362306a36Sopenharmony_ci else 57462306a36Sopenharmony_ci m = fwdvb * cbdv * ppdv; 57562306a36Sopenharmony_ci else if (psr & 0x00000020) /* New mode enable */ 57662306a36Sopenharmony_ci if (psr & 0x00000800) /* PerClk synch mode */ 57762306a36Sopenharmony_ci m = fwdvb * 2 * epdv; 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci m = fbdv * fwdv; 58062306a36Sopenharmony_ci else if (epdv == fbdv) 58162306a36Sopenharmony_ci m = fbdv * cbdv * epdv; 58262306a36Sopenharmony_ci else 58362306a36Sopenharmony_ci m = fbdv * fwdvb * cbdv; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci cpu = sys_clk * m / fwdv; 58662306a36Sopenharmony_ci plb = sys_clk * m / (fwdvb * cbdv); 58762306a36Sopenharmony_ci } else { 58862306a36Sopenharmony_ci m = fwdv * fbdv * cbdv; 58962306a36Sopenharmony_ci cpu = sys_clk * m / fwdv; 59062306a36Sopenharmony_ci plb = cpu / cbdv; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci opb = plb / opdv; 59362306a36Sopenharmony_ci ebc = plb / epdv; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (cpc0_cr0 & 0x80) 59662306a36Sopenharmony_ci /* uart0 uses the external clock */ 59762306a36Sopenharmony_ci uart0 = ser_clk; 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci uart0 = cpu / udiv; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (cpc0_cr0 & 0x40) 60262306a36Sopenharmony_ci /* uart1 uses the external clock */ 60362306a36Sopenharmony_ci uart1 = ser_clk; 60462306a36Sopenharmony_ci else 60562306a36Sopenharmony_ci uart1 = cpu / udiv; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* setup the timebase clock to tick at the cpu frequency */ 60862306a36Sopenharmony_ci cpc0_cr1 = cpc0_cr1 & ~0x00800000; 60962306a36Sopenharmony_ci mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1); 61062306a36Sopenharmony_ci tb = cpu; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci dt_fixup_cpu_clocks(cpu, tb, 0); 61362306a36Sopenharmony_ci dt_fixup_clock("/plb", plb); 61462306a36Sopenharmony_ci dt_fixup_clock("/plb/opb", opb); 61562306a36Sopenharmony_ci dt_fixup_clock("/plb/ebc", ebc); 61662306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@ef600300", uart0); 61762306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@ef600400", uart1); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_civoid ibm405ep_fixup_clocks(unsigned int sys_clk) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci u32 pllmr0 = mfdcr(DCRN_CPC0_PLLMR0); 62462306a36Sopenharmony_ci u32 pllmr1 = mfdcr(DCRN_CPC0_PLLMR1); 62562306a36Sopenharmony_ci u32 cpc0_ucr = mfdcr(DCRN_CPC0_UCR); 62662306a36Sopenharmony_ci u32 cpu, plb, opb, ebc, uart0, uart1; 62762306a36Sopenharmony_ci u32 fwdva, fwdvb, fbdv, cbdv, opdv, epdv; 62862306a36Sopenharmony_ci u32 pllmr0_ccdv, tb, m; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci fwdva = 8 - ((pllmr1 & 0x00070000) >> 16); 63162306a36Sopenharmony_ci fwdvb = 8 - ((pllmr1 & 0x00007000) >> 12); 63262306a36Sopenharmony_ci fbdv = (pllmr1 & 0x00f00000) >> 20; 63362306a36Sopenharmony_ci if (fbdv == 0) 63462306a36Sopenharmony_ci fbdv = 16; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci cbdv = ((pllmr0 & 0x00030000) >> 16) + 1; /* CPU:PLB */ 63762306a36Sopenharmony_ci epdv = ((pllmr0 & 0x00000300) >> 8) + 2; /* PLB:EBC */ 63862306a36Sopenharmony_ci opdv = ((pllmr0 & 0x00003000) >> 12) + 1; /* PLB:OPB */ 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci m = fbdv * fwdvb; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci pllmr0_ccdv = ((pllmr0 & 0x00300000) >> 20) + 1; 64362306a36Sopenharmony_ci if (pllmr1 & 0x80000000) 64462306a36Sopenharmony_ci cpu = sys_clk * m / (fwdva * pllmr0_ccdv); 64562306a36Sopenharmony_ci else 64662306a36Sopenharmony_ci cpu = sys_clk / pllmr0_ccdv; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci plb = cpu / cbdv; 64962306a36Sopenharmony_ci opb = plb / opdv; 65062306a36Sopenharmony_ci ebc = plb / epdv; 65162306a36Sopenharmony_ci tb = cpu; 65262306a36Sopenharmony_ci uart0 = cpu / (cpc0_ucr & 0x0000007f); 65362306a36Sopenharmony_ci uart1 = cpu / ((cpc0_ucr & 0x00007f00) >> 8); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci dt_fixup_cpu_clocks(cpu, tb, 0); 65662306a36Sopenharmony_ci dt_fixup_clock("/plb", plb); 65762306a36Sopenharmony_ci dt_fixup_clock("/plb/opb", opb); 65862306a36Sopenharmony_ci dt_fixup_clock("/plb/ebc", ebc); 65962306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@ef600300", uart0); 66062306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@ef600400", uart1); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic u8 ibm405ex_fwdv_multi_bits[] = { 66462306a36Sopenharmony_ci /* values for: 1 - 16 */ 66562306a36Sopenharmony_ci 0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05, 66662306a36Sopenharmony_ci 0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03 66762306a36Sopenharmony_ci}; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ciu32 ibm405ex_get_fwdva(unsigned long cpr_fwdv) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci u32 index; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++) 67462306a36Sopenharmony_ci if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index]) 67562306a36Sopenharmony_ci return index + 1; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic u8 ibm405ex_fbdv_multi_bits[] = { 68162306a36Sopenharmony_ci /* values for: 1 - 100 */ 68262306a36Sopenharmony_ci 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4, 68362306a36Sopenharmony_ci 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb, 68462306a36Sopenharmony_ci 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96, 68562306a36Sopenharmony_ci 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde, 68662306a36Sopenharmony_ci 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb, 68762306a36Sopenharmony_ci 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91, 68862306a36Sopenharmony_ci 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b, 68962306a36Sopenharmony_ci 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95, 69062306a36Sopenharmony_ci 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4, 69162306a36Sopenharmony_ci 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc, 69262306a36Sopenharmony_ci /* values for: 101 - 200 */ 69362306a36Sopenharmony_ci 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3, 69462306a36Sopenharmony_ci 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90, 69562306a36Sopenharmony_ci 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe, 69662306a36Sopenharmony_ci 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6, 69762306a36Sopenharmony_ci 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd, 69862306a36Sopenharmony_ci 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1, 69962306a36Sopenharmony_ci 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6, 70062306a36Sopenharmony_ci 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9, 70162306a36Sopenharmony_ci 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e, 70262306a36Sopenharmony_ci 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf, 70362306a36Sopenharmony_ci /* values for: 201 - 255 */ 70462306a36Sopenharmony_ci 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae, 70562306a36Sopenharmony_ci 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2, 70662306a36Sopenharmony_ci 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2, 70762306a36Sopenharmony_ci 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98, 70862306a36Sopenharmony_ci 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81, 70962306a36Sopenharmony_ci 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */ 71062306a36Sopenharmony_ci}; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ciu32 ibm405ex_get_fbdv(unsigned long cpr_fbdv) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci u32 index; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++) 71762306a36Sopenharmony_ci if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index]) 71862306a36Sopenharmony_ci return index + 1; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_civoid ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci /* PLL config */ 72662306a36Sopenharmony_ci u32 pllc = CPR0_READ(DCRN_CPR0_PLLC); 72762306a36Sopenharmony_ci u32 plld = CPR0_READ(DCRN_CPR0_PLLD); 72862306a36Sopenharmony_ci u32 cpud = CPR0_READ(DCRN_CPR0_PRIMAD); 72962306a36Sopenharmony_ci u32 plbd = CPR0_READ(DCRN_CPR0_PRIMBD); 73062306a36Sopenharmony_ci u32 opbd = CPR0_READ(DCRN_CPR0_OPBD); 73162306a36Sopenharmony_ci u32 perd = CPR0_READ(DCRN_CPR0_PERD); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* Dividers */ 73462306a36Sopenharmony_ci u32 fbdv = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1)); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci u32 fwdva = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1)); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* PLBDV0 is hardwared to 010. */ 74162306a36Sopenharmony_ci u32 plbdv0 = 2; 74262306a36Sopenharmony_ci u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci u32 perdv0 = __fix_zero((perd >> 24) & 3, 4); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* Resulting clocks */ 74962306a36Sopenharmony_ci u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* PLL's VCO is the source for primary forward ? */ 75262306a36Sopenharmony_ci if (pllc & 0x40000000) { 75362306a36Sopenharmony_ci u32 m; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* Feedback path */ 75662306a36Sopenharmony_ci switch ((pllc >> 24) & 7) { 75762306a36Sopenharmony_ci case 0: 75862306a36Sopenharmony_ci /* PLLOUTx */ 75962306a36Sopenharmony_ci m = fbdv; 76062306a36Sopenharmony_ci break; 76162306a36Sopenharmony_ci case 1: 76262306a36Sopenharmony_ci /* CPU */ 76362306a36Sopenharmony_ci m = fbdv * fwdva * cpudv0; 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci case 5: 76662306a36Sopenharmony_ci /* PERClk */ 76762306a36Sopenharmony_ci m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci default: 77062306a36Sopenharmony_ci printf("WARNING ! Invalid PLL feedback source !\n"); 77162306a36Sopenharmony_ci goto bypass; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci vco = (unsigned int)(sys_clk * m); 77562306a36Sopenharmony_ci } else { 77662306a36Sopenharmony_cibypass: 77762306a36Sopenharmony_ci /* Bypass system PLL */ 77862306a36Sopenharmony_ci vco = 0; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* CPU = VCO / ( FWDVA x CPUDV0) */ 78262306a36Sopenharmony_ci cpu = vco / (fwdva * cpudv0); 78362306a36Sopenharmony_ci /* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */ 78462306a36Sopenharmony_ci plb = vco / (fwdva * plb2xdv0 * plbdv0); 78562306a36Sopenharmony_ci /* OPB = PLB / OPBDV0 */ 78662306a36Sopenharmony_ci opb = plb / opbdv0; 78762306a36Sopenharmony_ci /* EBC = OPB / PERDV0 */ 78862306a36Sopenharmony_ci ebc = opb / perdv0; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci tb = cpu; 79162306a36Sopenharmony_ci uart0 = uart1 = uart_clk; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci dt_fixup_cpu_clocks(cpu, tb, 0); 79462306a36Sopenharmony_ci dt_fixup_clock("/plb", plb); 79562306a36Sopenharmony_ci dt_fixup_clock("/plb/opb", opb); 79662306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/ebc", ebc); 79762306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@ef600200", uart0); 79862306a36Sopenharmony_ci dt_fixup_clock("/plb/opb/serial@ef600300", uart1); 79962306a36Sopenharmony_ci} 800