// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2021 NXP */ #include #include #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; static struct cgc1_regs *cgc1_regs = (struct cgc1_regs *)0x292C0000UL; static struct cgc2_regs *cgc2_regs = (struct cgc2_regs *)0x2da60000UL; void cgc1_soscdiv_init(void) { /* Configure SOSC/FRO DIV1 ~ DIV3 */ clrbits_le32(&cgc1_regs->soscdiv, BIT(7)); clrbits_le32(&cgc1_regs->soscdiv, BIT(15)); clrbits_le32(&cgc1_regs->soscdiv, BIT(23)); clrbits_le32(&cgc1_regs->soscdiv, BIT(31)); clrbits_le32(&cgc1_regs->frodiv, BIT(7)); } void cgc1_pll2_init(void) { u32 reg; if (readl(&cgc1_regs->pll2csr) & BIT(23)) clrbits_le32(&cgc1_regs->pll2csr, BIT(23)); /* Disable PLL2 */ clrbits_le32(&cgc1_regs->pll2csr, BIT(0)); mdelay(1); /* wait valid bit false */ while ((readl(&cgc1_regs->pll2csr) & BIT(24))) ; /* Select SOSC as source, freq = 31 * 24 =744mhz */ reg = 31 << 16; writel(reg, &cgc1_regs->pll2cfg); /* Enable PLL2 */ setbits_le32(&cgc1_regs->pll2csr, BIT(0)); /* Wait for PLL2 clock ready */ while (!(readl(&cgc1_regs->pll2csr) & BIT(24))) ; } static void cgc1_set_a35_clk(u32 clk_src, u32 div_core) { u32 reg; /* ulock */ if (readl(&cgc1_regs->ca35clk) & BIT(31)) clrbits_le32(&cgc1_regs->ca35clk, BIT(31)); reg = readl(&cgc1_regs->ca35clk); reg &= ~GENMASK(29, 21); reg |= ((clk_src & 0x3) << 28); reg |= (((div_core - 1) & 0x3f) << 21); writel(reg, &cgc1_regs->ca35clk); while (!(readl(&cgc1_regs->ca35clk) & BIT(27))) ; } void cgc1_init_core_clk(void) { u32 reg = readl(&cgc1_regs->ca35clk); /* if already selected to PLL2, switch to FRO firstly */ if (((reg >> 28) & 0x3) == 0x1) cgc1_set_a35_clk(0, 1); /* Set pll2 to 750Mhz for 1V */ cgc1_pll2_init(); /* Set A35 clock to pll2 */ cgc1_set_a35_clk(1, 1); } void cgc1_enet_stamp_sel(u32 clk_src) { writel((clk_src & 0x7) << 24, &cgc1_regs->enetstamp); } void cgc1_pll3_init(void) { /* Gate off VCO */ setbits_le32(&cgc1_regs->pll3div_vco, BIT(7)); /* Disable PLL3 */ clrbits_le32(&cgc1_regs->pll3csr, BIT(0)); /* Gate off PFDxDIV */ setbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31)); setbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31)); /* Gate off PFDx */ setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7)); setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15)); setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23)); setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31)); /* Select SOSC as source */ clrbits_le32(&cgc1_regs->pll3cfg, BIT(0)); //setbits_le32(&cgc1_regs->pll3cfg, 22 << 16); writel(22 << 16, &cgc1_regs->pll3cfg); writel(578, &cgc1_regs->pll3num); writel(1000, &cgc1_regs->pll3denom); /* Enable PLL3 */ setbits_le32(&cgc1_regs->pll3csr, BIT(0)); /* Wait for PLL3 clock ready */ while (!(readl(&cgc1_regs->pll3csr) & BIT(24))) ; /* Gate on VCO */ clrbits_le32(&cgc1_regs->pll3div_vco, BIT(7)); /* * PFD0: 380MHz/396/396/328 */ clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F); setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 0); clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7)); while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(6))) ; clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 8); setbits_le32(&cgc1_regs->pll3pfdcfg, 24 << 8); clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15)); while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(14))) ; clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 16); setbits_le32(&cgc1_regs->pll3pfdcfg, 24 << 16); clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23)); while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(22))) ; clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 24); setbits_le32(&cgc1_regs->pll3pfdcfg, 29 << 24); clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31)); while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(30))) ; clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7)); clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(15)); clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(23)); clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(31)); clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7)); clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(15)); clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(23)); clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(31)); } void cgc2_pll4_init(void) { /* Disable PFD DIV and clear DIV */ writel(0x80808080, &cgc2_regs->pll4div_pfd0); writel(0x80808080, &cgc2_regs->pll4div_pfd1); /* Gate off and clear PFD */ writel(0x80808080, &cgc2_regs->pll4pfdcfg); /* Disable PLL4 */ writel(0x0, &cgc2_regs->pll4csr); /* Configure PLL4 to 528Mhz and clock source from SOSC */ writel(22 << 16, &cgc2_regs->pll4cfg); writel(0x1, &cgc2_regs->pll4csr); /* wait for PLL4 output valid */ while (!(readl(&cgc2_regs->pll4csr) & BIT(24))) ; /* Enable all 4 PFDs */ setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 0); /* 316.8Mhz for NIC_LPAV */ setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 8); setbits_le32(&cgc2_regs->pll4pfdcfg, 12 << 16); setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24); clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) | BIT(15) | BIT(23) | BIT(31)); while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(30) | BIT(22) | BIT(14) | BIT(6))) != (BIT(30) | BIT(22) | BIT(14) | BIT(6))) ; /* Enable PFD DIV */ clrbits_le32(&cgc2_regs->pll4div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31)); clrbits_le32(&cgc2_regs->pll4div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31)); } void cgc2_ddrclk_config(u32 src, u32 div) { writel((src << 28) | (div << 21), &cgc2_regs->ddrclk); /* wait for DDRCLK switching done */ while (!(readl(&cgc2_regs->ddrclk) & BIT(27))) ; } u32 decode_pll(enum cgc1_clk pll) { u32 reg, infreq, mult; u32 num, denom; infreq = 24000000U; /* * Alought there are four choices for the bypass src, * we choose SOSC 24M which is the default set in ROM. * TODO: check more the comments */ switch (pll) { case PLL2: reg = readl(&cgc1_regs->pll2csr); if (!(reg & BIT(24))) return 0; reg = readl(&cgc1_regs->pll2cfg); mult = (reg >> 16) & 0x7F; denom = readl(&cgc1_regs->pll2denom) & 0x3FFFFFFF; num = readl(&cgc1_regs->pll2num) & 0x3FFFFFFF; return (u64)infreq * mult + (u64)infreq * num / denom; case PLL3: reg = readl(&cgc1_regs->pll3csr); if (!(reg & BIT(24))) return 0; reg = readl(&cgc1_regs->pll3cfg); mult = (reg >> 16) & 0x7F; denom = readl(&cgc1_regs->pll3denom) & 0x3FFFFFFF; num = readl(&cgc1_regs->pll3num) & 0x3FFFFFFF; return (u64)infreq * mult + (u64)infreq * num / denom; default: printf("Unsupported pll clocks %d\n", pll); break; } return 0; } u32 cgc1_pll3_vcodiv_rate(void) { u32 reg, gate, div; reg = readl(&cgc1_regs->pll3div_vco); gate = BIT(7) & reg; div = reg & 0x3F; return gate ? 0 : decode_pll(PLL3) / (div + 1); } u32 cgc1_pll3_pfd_rate(enum cgc1_clk clk) { u32 index, gate, vld, reg; switch (clk) { case PLL3_PFD0: index = 0; break; case PLL3_PFD1: index = 1; break; case PLL3_PFD2: index = 2; break; case PLL3_PFD3: index = 3; break; default: return 0; } reg = readl(&cgc1_regs->pll3pfdcfg); gate = reg & (BIT(7) << (index * 8)); vld = reg & (BIT(6) << (index * 8)); if (gate || !vld) return 0; return (u64)decode_pll(PLL3) * 18 / ((reg >> (index * 8)) & 0x3F); } u32 cgc1_pll3_pfd_div(enum cgc1_clk clk) { void __iomem *base; u32 pfd, index, gate, reg; switch (clk) { case PLL3_PFD0_DIV1: base = &cgc1_regs->pll3div_pfd0; pfd = PLL3_PFD0; index = 0; break; case PLL3_PFD0_DIV2: base = &cgc1_regs->pll3div_pfd0; pfd = PLL3_PFD0; index = 1; break; case PLL3_PFD1_DIV1: base = &cgc1_regs->pll3div_pfd0; pfd = PLL3_PFD1; index = 2; break; case PLL3_PFD1_DIV2: base = &cgc1_regs->pll3div_pfd0; pfd = PLL3_PFD1; index = 3; break; case PLL3_PFD2_DIV1: base = &cgc1_regs->pll3div_pfd1; pfd = PLL3_PFD2; index = 0; break; case PLL3_PFD2_DIV2: base = &cgc1_regs->pll3div_pfd1; pfd = PLL3_PFD2; index = 1; break; case PLL3_PFD3_DIV1: base = &cgc1_regs->pll3div_pfd1; pfd = PLL3_PFD3; index = 2; break; case PLL3_PFD3_DIV2: base = &cgc1_regs->pll3div_pfd1; pfd = PLL3_PFD3; index = 3; break; default: return 0; } reg = readl(base); gate = reg & (BIT(7) << (index * 8)); if (gate) return 0; return cgc1_pll3_pfd_rate(pfd) / (((reg >> (index * 8)) & 0x3F) + 1); } u32 cgc1_sosc_div(enum cgc1_clk clk) { u32 reg, gate, index; switch (clk) { case SOSC: return 24000000; case SOSC_DIV1: index = 0; break; case SOSC_DIV2: index = 1; break; case SOSC_DIV3: index = 2; break; default: return 0; } reg = readl(&cgc1_regs->soscdiv); gate = reg & (BIT(7) << (index * 8)); if (gate) return 0; return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1); } u32 cgc1_fro_div(enum cgc1_clk clk) { u32 reg, gate, vld, index; switch (clk) { case FRO: return 192000000; case FRO_DIV1: index = 0; break; case FRO_DIV2: index = 1; break; case FRO_DIV3: index = 2; break; default: return 0; } reg = readl(&cgc1_regs->frodiv); gate = reg & (BIT(7) << (index * 8)); vld = reg & (BIT(6) << (index * 8)); if (gate || !vld) return 0; return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1); } u32 cgc1_clk_get_rate(enum cgc1_clk clk) { switch (clk) { case SOSC: case SOSC_DIV1: case SOSC_DIV2: case SOSC_DIV3: return cgc1_sosc_div(clk); case FRO: case FRO_DIV1: case FRO_DIV2: case FRO_DIV3: return cgc1_fro_div(clk); case PLL2: return decode_pll(PLL2); case PLL3: return decode_pll(PLL3); case PLL3_VCODIV: return cgc1_pll3_vcodiv_rate(); case PLL3_PFD0: case PLL3_PFD1: case PLL3_PFD2: case PLL3_PFD3: return cgc1_pll3_pfd_rate(clk); case PLL3_PFD0_DIV1: case PLL3_PFD0_DIV2: case PLL3_PFD1_DIV1: case PLL3_PFD1_DIV2: case PLL3_PFD2_DIV1: case PLL3_PFD2_DIV2: case PLL3_PFD3_DIV1: case PLL3_PFD3_DIV2: return cgc1_pll3_pfd_div(clk); default: printf("Unsupported cgc1 clock: %d\n", clk); return 0; } }