^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Old U-boot compatibility for Acadia
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright 2008 IBM Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "ops.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "io.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "dcr.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "stdio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "4xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "44x.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "cuboot.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define TARGET_4xx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "ppcboot.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static bd_t bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CPR_PERD0_SPIDV_MASK 0x000F0000 /* SPI Clock Divider */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define PLLC_SRC_MASK 0x20000000 /* PLL feedback source */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define PLLD_FBDV_MASK 0x1F000000 /* PLL feedback divider value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define PLLD_FWDVA_MASK 0x000F0000 /* PLL forward divider A value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define PLLD_FWDVB_MASK 0x00000700 /* PLL forward divider B value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define PRIMAD_CPUDV_MASK 0x0F000000 /* CPU Clock Divisor Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PRIMAD_PLBDV_MASK 0x000F0000 /* PLB Clock Divisor Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define PRIMAD_OPBDV_MASK 0x00000F00 /* OPB Clock Divisor Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define PRIMAD_EBCDV_MASK 0x0000000F /* EBC Clock Divisor Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define PERD0_PWMDV_MASK 0xFF000000 /* PWM Divider Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define PERD0_SPIDV_MASK 0x000F0000 /* SPI Divider Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define PERD0_U0DV_MASK 0x0000FF00 /* UART 0 Divider Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define PERD0_U1DV_MASK 0x000000FF /* UART 1 Divider Mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static void get_clocks(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned long sysclk, cpr_plld, cpr_pllc, cpr_primad, plloutb, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned long pllFwdDiv, pllFwdDivB, pllFbkDiv, pllPlbDiv, pllExtBusDiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) unsigned long pllOpbDiv, freqEBC, freqUART, freqOPB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned long div; /* total divisor udiv * bdiv */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned long umin; /* minimum udiv */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned short diff; /* smallest diff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) unsigned long udiv; /* best udiv */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned short idiff; /* current diff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned short ibdiv; /* current bdiv */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned long est; /* current estimate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned long baud;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) void *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* read the sysclk value from the CPLD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) sysclk = (in_8((unsigned char *)0x80000000) == 0xc) ? 66666666 : 33333000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * Read PLL Mode registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) cpr_plld = CPR0_READ(DCRN_CPR0_PLLD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) cpr_pllc = CPR0_READ(DCRN_CPR0_PLLC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Determine forward divider A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Determine forward divider B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (pllFwdDivB == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) pllFwdDivB = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Determine FBK_DIV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (pllFbkDiv == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) pllFbkDiv = 256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * Read CPR_PRIMAD register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) cpr_primad = CPR0_READ(DCRN_CPR0_PRIMAD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * Determine PLB_DIV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (pllPlbDiv == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) pllPlbDiv = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * Determine EXTBUS_DIV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (pllExtBusDiv == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) pllExtBusDiv = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * Determine OPB_DIV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (pllOpbDiv == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) pllOpbDiv = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* There is a bug in U-Boot that prevents us from using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * bd.bi_opbfreq because U-Boot doesn't populate it for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * 405EZ. We get to calculate it, yay!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) freqOPB = (sysclk *pllFbkDiv) /pllOpbDiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) freqEBC = (sysclk * pllFbkDiv) / pllExtBusDiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) plloutb = ((sysclk * ((cpr_pllc & PLLC_SRC_MASK) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) pllFwdDivB : pllFwdDiv) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) pllFbkDiv) / pllFwdDivB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) np = find_node_by_alias("serial0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (getprop(np, "current-speed", &baud, sizeof(baud)) != sizeof(baud))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) fatal("no current-speed property\n\r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) udiv = 256; /* Assume lowest possible serial clk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) div = plloutb / (16 * baud); /* total divisor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) umin = (plloutb / freqOPB) << 1; /* 2 x OPB divisor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) diff = 256; /* highest possible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* i is the test udiv value -- start with the largest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * possible (256) to minimize serial clock and constrain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * search to umin.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) for (i = 256; i > umin; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ibdiv = div / i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) est = i * ibdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) idiff = (est > div) ? (est-div) : (div-est);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (idiff == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) udiv = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) break; /* can't do better */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) } else if (idiff < diff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) udiv = i; /* best so far */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) diff = idiff; /* update lowest diff*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) freqUART = plloutb / udiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) dt_fixup_cpu_clocks(bd.bi_procfreq, bd.bi_intfreq, bd.bi_plb_busfreq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) dt_fixup_clock("/plb/ebc", freqEBC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) dt_fixup_clock("/plb/opb", freqOPB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) dt_fixup_clock("/plb/opb/serial@ef600300", freqUART);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) dt_fixup_clock("/plb/opb/serial@ef600400", freqUART);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static void acadia_fixups(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) get_clocks();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) unsigned long r6, unsigned long r7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) CUBOOT_INIT();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) platform_ops.fixups = acadia_fixups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) platform_ops.exit = ibm40x_dbcr_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) fdt_init(_dtb_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) serial_console_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }