diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx297520v3.c index 68bfeab84d74..d5f8bc4064bd 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -812,6 +812,528 @@ static const struct zx_clk_data zx297520v3_topclk_data = { .num_exports = ARRAY_SIZE(zx297520v3_top_exports), }; +enum matrix_clock_ids { + ZX_CLK_MATRIX_OSC26M_D4, + ZX_CLK_MATRIX_MPLL_D2_PREGATE, + ZX_CLK_MATRIX_MPLL_D4_PREGATE, + ZX_CLK_MATRIX_MPLL_D6_PREGATE, + ZX_CLK_MATRIX_MPLL_D8_PREGATE, + ZX_CLK_MATRIX_MPLL_D12_PREGATE, + ZX_CLK_MATRIX_MPLL_D16_PREGATE, + ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE, + ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE, + ZX_CLK_MATRIX_DPLL_D2_PREGATE, + ZX_CLK_MATRIX_DPLL_D4_PREGATE, + + ZX_CLK_MATRIX_MPLL_D16, + ZX_CLK_MATRIX_MPLL_D12, + ZX_CLK_MATRIX_MPLL_D8, + ZX_CLK_MATRIX_MPLL_D6, + ZX_CLK_MATRIX_MPLL_D4, + ZX_CLK_MATRIX_MPLL_D2, + ZX_CLK_MATRIX_DPLL_D4, + ZX_CLK_MATRIX_DPLL_D2, + ZX_CLK_MATRIX_GPLL_D2_D4, + ZX_CLK_MATRIX_GPLL_D2_D2, + + ZX_CLK_CPU_MUX, + ZX_CLK_ZSP_MUX, + ZX_CLK_DDR_CTRL_MUX, + ZX_CLK_SD0_MUX, + ZX_CLK_SD1_MUX, + ZX_CLK_NAND_MUX, + ZX_CLK_EDCP_MUX, + ZX_CLK_TDM_MUX, + ZX_CLK_AXI_MUX, + + ZX_CLK_SYS_TIMER_WCLK, + ZX_CLK_CPU_WCLK, + ZX_CLK_CPU_PCLK, + ZX_CLK_ZSP_WCLK, + ZX_CLK_ZSP_PCLK, + ZX_CLK_DDR_CTRL_PCLK, + ZX_CLK_DDR_CTRL_WCLK, + ZX_CLK_SD0_PCLK, + ZX_CLK_SD0_WCLK, + ZX_CLK_SD0_CDET, + ZX_CLK_SD1_PCLK, + ZX_CLK_SD1_WCLK, + ZX_CLK_SD1_CDET, + ZX_CLK_NAND_WCLK, + ZX_CLK_NAND_PCLK, + ZX_CLK_LTE_MODEM_WCLK, + ZX_CLK_LTE_MODEM_PCLK, + ZX_CLK_EDCP_PCLK, + ZX_CLK_EDCP_WCLK, + ZX_CLK_RFFE_WCLK, + ZX_CLK_SSC_WCLK, + ZX_CLK_SSC_PCLK, + ZX_CLK_PDCFG_WCLK, + ZX_CLK_PDCFG_PCLK, + ZX_CLK_MBOX_PCLK, + ZX_CLK_SRAM0_PCLK, + ZX_CLK_GSM_CFG_PCLK, + ZX_CLK_GMAC_WCLK, + ZX_CLK_GMAC_PCLK, + ZX_CLK_GMAC_AHB, + ZX_CLK_AXI_WCLK, + ZX_CLK_DMA_PCLK, + ZX_CLK_VOU_WCLK, + ZX_CLK_VOU_PCLK, + ZX_CLK_TOLSP_MPLL_D5_WCLK, + ZX_CLK_TOLSP_MPLL_D4_WCLK, + ZX_CLK_TOLSP_MPLL_D6_WCLK, + ZX_CLK_TOLSP_MPLL_D8_WCLK, + ZX_CLK_TOLSP_MPLL_D12_WCLK, + ZX_CLK_TOLSP_OSC26M_WCLK, + ZX_CLK_TOLSP_OSC32K_WCLK, + ZX_CLK_TOLSP_PCLK, + ZX_CLK_TOLSP_TDM_WCLK, + ZX_CLK_TOLSP_DPLL_D4_WCLK, +}; + +/* + * For devices which have a working driver the work clock can be figured out by gating off registers + * in topcrm+0x140. This is used for devices where I can't interpret the register contents yet. + */ +static const struct zx_parent_desc matrix_unk = PARENT_FW("wclk-osc26m"); + +static const struct zx_parent_desc cpu_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_FW("mpll"), /* 624 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2), /* 312 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +/* + * Figuring these values out is a bit tricky. The best liveness check of the ZSP is reading its TCM + * at 0x81000000. If it is clocked up and out of reset reading it will succeed. Otherwise, reading + * will stall. Value 1 depends on topcrm+0x140, bit 13, but not any matrixcrm+0x118 gate, so it is + * likely dpll without a div. Mux value 2 depends on 0x118 bit 5, so mpll-d2. Mux value 3 depends on + * 0x118 bit 4, so mpll-d4. Mux value 0 in turn depends on topcrm+0x140, bit 24 (osc26m), so it + * follows the usual pattern that mux 0 is osc26m. + * + * If the firmware is running and fed with initialization data it will start writing status messages + * on UART1. An interruption of these messages or a failure to respond to rpmsg is not proof that + * the ZSP's clock has been disabled. The firmware's workings depend on regular timer and LTE device + * IRQs, so one of these devices might have been stopped instead. + */ +static const struct zx_parent_desc zsp_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_FW("dpll"), /* 491.52 MHz, boot default */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2), /* 312 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +/* + * We can't realistically change DDR speed while running an OS out of DDR (it reads garbage for a + * short while on transition), but we need to know if we have to keep gpll alive. 32 MB devices use + * 200 MHz, while 64/128 MB ones use 156 MHz. + */ +static const struct zx_parent_desc ddr_ctrl_sel[] = { + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("gpll"), /* 200 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ +}; + +static const struct zx_parent_desc sd0_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("gpll-d2"), /* 100 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2), /* 50 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4), /* 25 MHz */ +}; + +static const struct zx_parent_desc sd1_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_FW("gpll-d2"), /* 100 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2), /* 50 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16), /* 39 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4), /* 25 MHz */ +}; + +/* + * ZTE's kernel puts the high frequency first, but this is against the usual convention on this SoC. + * I don't have any device that has a raw NAND controller though. + */ +static const struct zx_parent_desc nand_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +static const struct zx_parent_desc edcp_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("mpll-d5"), /* 124.8 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ +}; + +/* + * The 122.88 MHz selection of value 1 is given in ZTE's kernel and matches up to observation: Print + * the TDM counter at regular intervals and look at its increase at values 0/1/2. It increases by + * about 310*26 for value 0, 310*122.88 for value 1 and 310*104 for value 2. + * + * Mux value 1 is gated off by matrix+0x118 bit 8. Values 2 and 3 are both gated off by 0x118 bit 3, + * suggesting that they select the same parent. + */ +static const struct zx_parent_desc tdm_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_DPLL_D4), /* 122.88 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), +}; + +/* + * ZTE's firmware uses 0x128 as the PHY's vote and names 0x120 as "PS" and 0x124 as "AP" vote. + * However, their cpufreq driver ultimately uses the "PS" define and thus writes to 0x120, which can + * be observed in the running system. + */ +#define ZX297520V3_AXI_AP_VOTE 0x120 +static const struct zx_parent_desc axi_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("mpll-d5"), /* 124.8 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D12), /* 52 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16), /* 39 MHz */ + PARENT_ID(ZX_CLK_MATRIX_OSC26M_D4), /* 6.5 MHz */ +}; + +static const struct zx_clock zx297520v3_matrix_clocks[] = { + [ZX_CLK_MATRIX_OSC26M_D4] = FIXED_DIV("matrix-osc26m-d4", PARENT_FW("wclk-osc26m"), 4), + [ZX_CLK_MATRIX_MPLL_D2_PREGATE] = FIXED_DIV("matrix-mpll-d2-pregate", PARENT_FW("mpll"), 2), + [ZX_CLK_MATRIX_MPLL_D4_PREGATE] = FIXED_DIV("matrix-mpll-d4-pregate", PARENT_FW("mpll"), 4), + /* div 5: provided as a separate line from topcrm */ + [ZX_CLK_MATRIX_MPLL_D6_PREGATE] = FIXED_DIV("matrix-mpll-d6-pregate", PARENT_FW("mpll"), 6), + [ZX_CLK_MATRIX_MPLL_D8_PREGATE] = FIXED_DIV("matrix-mpll-d8-pregate", PARENT_FW("mpll"), 8), + [ZX_CLK_MATRIX_MPLL_D12_PREGATE] = FIXED_DIV("matrix-mpll-d12-pregate", PARENT_FW("mpll"), + 12), + [ZX_CLK_MATRIX_MPLL_D16_PREGATE] = FIXED_DIV("matrix-mpll-d16-pregate", PARENT_FW("mpll"), + 16), + + [ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE] = FIXED_DIV("matrix-gpll-d2-d2-pregate", + PARENT_FW("gpll-d2"), 2), + [ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE] = FIXED_DIV("matrix-gpll-d2-d4-pregate", + PARENT_FW("gpll-d2"), 4), + + [ZX_CLK_MATRIX_DPLL_D2_PREGATE] = FIXED_DIV("matrix-dpll-d2-pregate", PARENT_FW("dpll"), 2), + [ZX_CLK_MATRIX_DPLL_D4_PREGATE] = FIXED_DIV("matrix-dpll-d4-pregate", PARENT_FW("dpll"), 4), + + /* + * Matrix distribution gates: Every matrix-generated subdivision of the input PLLs + * has a gate in 0x118. The original inputs from topcrm (mpll 624, mpll 124.8, gpll 200, + * gpll 100, dpll 491.52) do not. + * + * Bit 8 is consumed by TDM and the frequency dpll/4 holds up to observation. Bit 9 is + * consumed by an unknown device and the frequency is guessed from the pattern that lower + * bits gate lower frequencies. + */ + [ZX_CLK_MATRIX_MPLL_D16] = GATE("matrix-mpll-d16", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16_PREGATE), 0x118, 0, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D12] = GATE("matrix-mpll-d12", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D12_PREGATE), 0x118, 1, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D8] = GATE("matrix-mpll-d8", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8_PREGATE), 0x118, 2, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D6] = GATE("matrix-mpll-d6", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6_PREGATE), 0x118, 3, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D4] = GATE("matrix-mpll-d4", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4_PREGATE), 0x118, 4, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D2] = GATE("matrix-mpll-d2", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2_PREGATE), 0x118, 5, 0), + + [ZX_CLK_MATRIX_DPLL_D4] = GATE("matrix-dpll-d4", + PARENT_ID(ZX_CLK_MATRIX_DPLL_D4_PREGATE), 0x118, 8, 0), + [ZX_CLK_MATRIX_DPLL_D2] = GATE("matrix-dpll-d2", + PARENT_ID(ZX_CLK_MATRIX_DPLL_D2_PREGATE), 0x118, 9, 0), + + [ZX_CLK_MATRIX_GPLL_D2_D4] = GATE("matrix-gpll-d2-d4", + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE), + 0x118, 12, 0), + [ZX_CLK_MATRIX_GPLL_D2_D2] = GATE("matrix-gpll-d2-d2", + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE), + 0x118, 13, 0), + + [ZX_CLK_CPU_MUX] = MUX("cpu-mux", cpu_sel, 0x20, 0, 2), + [ZX_CLK_ZSP_MUX] = MUX("zsp-mux", zsp_sel, 0x30, 0, 2), + [ZX_CLK_DDR_CTRL_MUX] = MUX("ddr-ctrl-mux", ddr_ctrl_sel, 0x50, 0, 2), + [ZX_CLK_SD0_MUX] = MUX("sd0-mux", sd0_sel, 0x50, 4, 3), + [ZX_CLK_SD1_MUX] = MUX("sd1-mux", sd1_sel, 0x50, 8, 3), + [ZX_CLK_NAND_MUX] = MUX("nand-mux", nand_sel, 0x50, 12, 2), + [ZX_CLK_EDCP_MUX] = MUX("edcp-mux", edcp_sel, 0x50, 16, 2), + [ZX_CLK_TDM_MUX] = MUX("tdm-mux", tdm_sel, 0x50, 24, 2), + [ZX_CLK_AXI_MUX] = MUX("axi-mux", axi_sel, ZX297520V3_AXI_AP_VOTE, 0, 3), + + /* + * This bit cuts off the clock signal to the ARM architected timer, which the kernel uses + * as its main timer. It isn't critical per se - there are plenty of proprietary timers + * available that could be used - but the arm arch timer binding does not accept a clock, so + * this CCF driver won't know if the timer is in use. + * + * This clock is fed by the osc26m gate in topcrm+0x140 - this critical clock here protects + * its parent. + * + * Registers 0x148, 0x14c, 0x150, 0x154 allow setting and clearing the timer counter. To + * set the timer, load a value into 0x148 (high 32 bits) and 0x14c (low 32 bits), then + * toggle 0x150 to 1. 0x150 will automatically reset to 0. 0x154 sets the timer to some + * "clear" value, but this value isn't 0. + */ + [ZX_CLK_SYS_TIMER_WCLK] = GATE("sys-timer-wclk", PARENT_FW("wclk-osc26m"), 0x144, 1, + CLK_IS_CRITICAL), + + /* + * Both 0x24 and 0x28 bits 1 and 2 stop the CPU. There is also a bit in topcrm+0x138, which + * ZTE's uboot calls "A53 reset", which also stops the CPU. I can't really tell the + * difference between matrix+0x28 and top+0x138. The clock (matrix+0x24) can be disabled + * and enabled from the Cortex M0 and it will nicely stop and restart the A53, retaining + * all state. + */ + [ZX_CLK_CPU_WCLK] = GATE("cpu-wclk", PARENT_ID(ZX_CLK_CPU_MUX), 0x24, 1, + CLK_IS_CRITICAL), + [ZX_CLK_CPU_PCLK] = GATE("cpu-pclk", clk_main[0], 0x24, 2, CLK_IS_CRITICAL), + + /* + * There are a lot more controls in matrix+0x100. 13-16 appear to be 4 different AXI + * channels for different priorities. Bit 19 appears to be the DDR PHY wclk. + * + * The important task is to keep gpll enabled if the bootloader selected a gpll-based rate + * for RAM. + */ + [ZX_CLK_DDR_CTRL_PCLK] = GATE("ddr-ctrl-pclk", clk_main[0], 0x100, 17, CLK_IS_CRITICAL), + [ZX_CLK_DDR_CTRL_WCLK] = GATE("ddr-ctrl-wclk", PARENT_ID(ZX_CLK_DDR_CTRL_MUX), 0x100, 18, + CLK_IS_CRITICAL), + + [ZX_CLK_ZSP_PCLK] = GATE("zsp-pclk", clk_main[0], 0x34, 0, 0), + [ZX_CLK_ZSP_WCLK] = GATE("zsp-wclk", PARENT_ID(ZX_CLK_ZSP_MUX), 0x34, 1, 0), + + /* Both SDIO controllers depend on the ahb-pclk for register access. */ + [ZX_CLK_SD0_PCLK] = GATE("sd0-pclk", PARENT_FW("ahb"), 0x54, 12, 0), + [ZX_CLK_SD0_WCLK] = GATE("sd0-wclk", PARENT_ID(ZX_CLK_SD0_MUX), 0x54, 13, 0), + [ZX_CLK_SD0_CDET] = GATE("sd0-cdet", PARENT_FW("osc32k"), 0x54, 14, 0), + [ZX_CLK_SD1_PCLK] = GATE("sd1-pclk", PARENT_FW("ahb"), 0x54, 4, 0), + [ZX_CLK_SD1_WCLK] = GATE("sd1-wclk", PARENT_ID(ZX_CLK_SD1_MUX), 0x54, 5, 0), + /* + * I don't know how the cdet clock works. Card detection in the way the dwc,mmc driver uses + * it appears broken no matter this clock's setting. + */ + [ZX_CLK_SD1_CDET] = GATE("sd1-cdet", PARENT_FW("osc32k"), 0x54, 6, 0), + + /* This is some "denali" NAND, not the qspi connected one */ + [ZX_CLK_NAND_WCLK] = GATE("nand-wclk", PARENT_ID(ZX_CLK_NAND_MUX), 0x54, 20, 0), + [ZX_CLK_NAND_PCLK] = GATE("nand-pclk", clk_main[0], 0x54, 21, 0), + + /* + * There is a set of gates for an unknown device at matrix+0x60. It is some LTE related + * device and the pclk gates off mmio areas 0xf8000000 and 0xfc000000. These areas are only + * accessible to M0 and ZSP, not the AP. + * + * If it is fed an incorrect clock, e.g. because dpll is not locked and outputs 26 MHz, it + * will spam IRQs at SPI 68. This is likely a distress notification that some + * internal PLL did not lock or similar. ZTE's kernel has two defines for SPI 68: + * "LTE_TPU_INT_PS_INT" and "VOU_OSD_INT". The latter is unlikely because VOU related clocks + * sit in matrix+0x168. + * + * The address space in 0xfc000000 appears to contain a number of different devices, so I + * have named the clock LTE_MODEM_{W/P}CLK. It is not known how this mmio area and clock + * relates to SPI 68 or the ABB clock in topcrm+0x144. Because it is not accessible to the + * AP at all, I don't think we need to care beyond turning on the clocks before booting the + * ZSP. + * + * Bit 9 in register 0x118 turns the IRQs off, so it is the immediate wclk parent. It isn't + * clear what divisor of dpll it is using though. Following the pattern that lower + * frequencies are gated by lower bits, it would indicate dpll/2 or dpll/3. + */ + [ZX_CLK_LTE_MODEM_WCLK] = GATE("lte-modem-wclk", PARENT_ID(ZX_CLK_MATRIX_DPLL_D2), + 0x60, 0, 0), + [ZX_CLK_LTE_MODEM_PCLK] = GATE("lte-modem-pclk", clk_main[0], + 0x60, 2, 0), + + [ZX_CLK_EDCP_PCLK] = GATE("edcp-pclk", clk_main[0], 0x64, 1, 0), + [ZX_CLK_EDCP_WCLK] = GATE("edcp-wclk", PARENT_ID(ZX_CLK_EDCP_MUX), 0x64, 2, 0), + + /* + * This seems to be another SPI-Like device. cpko.ko uses it to send calibration blobs to + * the LTE radio hardware. After initialization the ZSP firmware takes over control of this + * device. + * + * Testing reveals the parent as matrix's 104 MHz mpll fraction. + */ + [ZX_CLK_RFFE_WCLK] = GATE("rffe-wclk", PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), 0x84, 0, 0), + [ZX_CLK_SSC_WCLK] = GATE("ssc-wclk", PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), 0x84, 1, 0), + [ZX_CLK_SSC_PCLK] = GATE("ssc-pclk", clk_main[0], 0x84, 2, 0), + + /* + * PDCFG. Like PMM, either clock bit will allow the device to function. Probably there is + * no wclk line at all and the two bits are just an artifact of generally having two bits + * per device. + */ + [ZX_CLK_PDCFG_WCLK] = GATE("pdcfg-wclk", matrix_unk, 0x88, 0, CLK_IS_CRITICAL), + [ZX_CLK_PDCFG_PCLK] = GATE("pdcfg-pclk", clk_main[0], 0x88, 1, CLK_IS_CRITICAL), + [ZX_CLK_MBOX_PCLK] = GATE("mbox-pclk", clk_main[0], 0x88, 2, 0), + [ZX_CLK_SRAM0_PCLK] = GATE("sram0-pclk", clk_main[0], 0x88, 4, 0), + [ZX_CLK_GSM_CFG_PCLK] = GATE("gsm-cfg-pclk", clk_main[0], 0x88, 8, 0), + + /* + * ZTE's driver has a statement to the effect of *(top->base+0x11c) = 5, with a comment + * suggesting that this sets a 50 MHz clock. The clock code itself lists GMAC clocks in + * matrix+0x110 and lists the parents of these clocks as 50 MHz gpll output, but + * the downstream ZTE GMAC driver never enables the clocks. It turns out ZTE's code is + * highly misleading. + * + * The GMAC's work clock is definitely not any gpll output because it keeps working fine + * with gpll disabled. Gating off matrix-osc26m breaks GMAC, so it must be its parent. + * + * The GMAC Gates are left enabled by the boot loader and are required for the GMAC to work. + * + * As for the 50 MHz comment: See rmiiphy-wclk. + * + * The gmac-ahb clock is a child of topcrm's ahb-pclk and is required for DMA transfers in + * and out of GMAC. Without it, GMAC still receives ethernet frames, but can't drain them + * to memory and will eventually set the RX FIFO overflow flag. + */ + [ZX_CLK_GMAC_WCLK] = GATE("gmac-wclk", PARENT_FW("wclk-osc26m"), 0x110, 0, 0), + [ZX_CLK_GMAC_PCLK] = GATE("gmac-pclk", clk_main[0], 0x110, 1, 0), + [ZX_CLK_GMAC_AHB] = GATE("gmac-ahb", PARENT_FW("ahb"), 0x110, 2, 0), + + /* + * Is there an AXI bus gate? The symptom of cutting off the AXI mux selection in top+0x140 + * is that matrixcrm becomes unreadable from m0 and A53 hangs. Inside matrix itself only 3 + * bits fit that bill: 0x8c bits 5, 6, 7. It seems a bit self-defeating to have a clock + * gate that shuts off access to itself though. I expect a clock gate for the bus + * somewhere, and the mux exists, so exposing one AXI clock in the bindings is the correct + * thing to do. It also serves to tell the kernel to keep the mux's parent enabled. + * + * Register 0x8c has 12 settable bits (0xfff). Ultimately it doesn't matter much which + * do-not-remove bit we don't remove. Other bits in this register behave like gates (e.g + * bits 11:8 cut off USB temporarily), so I think we are looking in the right place. + * + * If an explanation for the remaining bits surfaces and they are further gates and/or + * resets, add them to the bindings. + */ + [ZX_CLK_AXI_WCLK] = GATE("axi-wclk", PARENT_ID(ZX_CLK_AXI_MUX), 0x8c, 5, + CLK_IS_CRITICAL), + + [ZX_CLK_DMA_PCLK] = GATE("dma-pclk", clk_main[0], 0x94, 3, 0), + + /* + * There are a lot more VOU related controls in these registers, but turning off the main + * clock seems to shut off the entire VOU MMIO range. + */ + [ZX_CLK_VOU_WCLK] = GATE("vou-wclk", matrix_unk, 0x168, 0, 0), + [ZX_CLK_VOU_PCLK] = GATE("vou-pclk", clk_main[0], 0x168, 1, 0), + + /* + * LSP uplink clocks. The pclk is fairly obvious (disabling it shuts off the entire LSP + * register area). The wclk speeds were deduced by setting timers and qspi muxes to a + * specific speed and seeing which bit in matrix+0x7c needs to be enabled for the device + * to work. + * + * Due to the timers I am certain about the 26 MHz and 32 kHz clocks. I cannot directly + * observe the qspi mux frequency, so the clock rates depend on ZTE's qspi mux selection + * being correct. + * + * Two additional bits are specific to sound components - the mux for the LSP's TDM IP is + * in matrixcrm and gets passed down. I2S has a mux in LSP, which can select the dpll-d4 + * clock. + */ + [ZX_CLK_TOLSP_MPLL_D5_WCLK] = GATE("lsp-mpll-d5", PARENT_FW("mpll-d5"), 0x7c, 0, 0), + [ZX_CLK_TOLSP_MPLL_D4_WCLK] = GATE("lsp-mpll-d4", PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), + 0x7c, 1, 0), + [ZX_CLK_TOLSP_MPLL_D6_WCLK] = GATE("lsp-mpll-d6", PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), + 0x7c, 2, 0), + [ZX_CLK_TOLSP_MPLL_D8_WCLK] = GATE("lsp-mpll-d8", PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), + 0x7c, 3, 0), + [ZX_CLK_TOLSP_MPLL_D12_WCLK] = GATE("lsp-mpll-d12", PARENT_ID(ZX_CLK_MATRIX_MPLL_D12), + 0x7c, 4, 0), + [ZX_CLK_TOLSP_OSC26M_WCLK] = GATE("lsp-osc26m", PARENT_FW("wclk-osc26m"), 0x7c, 5, 0), + [ZX_CLK_TOLSP_OSC32K_WCLK] = GATE("lsp-osc32k", PARENT_FW("osc32k"), 0x7c, 6, 0), + [ZX_CLK_TOLSP_PCLK] = GATE("lsp-pclk", clk_main[0], 0x7c, 7, 0), + [ZX_CLK_TOLSP_TDM_WCLK] = GATE("lsp-tdm-wclk", PARENT_ID(ZX_CLK_TDM_MUX), 0x7c, 8, 0), + [ZX_CLK_TOLSP_DPLL_D4_WCLK] = GATE("lsp-dpll-d4", PARENT_ID(ZX_CLK_MATRIX_DPLL_D4), + 0x7c, 9, 0), +}; + +static int zx297520v3_matrix_init(struct regmap *map) +{ + u32 axi_val; + int res; + + /* Read the global AXI speed selection, insert it into our ballot and enable voting */ + res = regmap_read(map, 0x0, &axi_val); + if (res) + return res; + + axi_val &= 0x7; + res = regmap_write(map, ZX297520V3_AXI_AP_VOTE, axi_val); + if (res) + return res; + + return regmap_write(map, 0x12c, 1); +} + +static const unsigned int zx297520v3_matrix_exports[] = { + [ZX297520V3_SYS_TIMER_WCLK] = ZX_CLK_SYS_TIMER_WCLK, + [ZX297520V3_CPU_WCLK] = ZX_CLK_CPU_WCLK, + [ZX297520V3_CPU_PCLK] = ZX_CLK_CPU_PCLK, + [ZX297520V3_ZSP_WCLK] = ZX_CLK_ZSP_WCLK, + [ZX297520V3_ZSP_PCLK] = ZX_CLK_ZSP_PCLK, + [ZX297520V3_DDR_CTRL_PCLK] = ZX_CLK_DDR_CTRL_PCLK, + [ZX297520V3_DDR_CTRL_WCLK] = ZX_CLK_DDR_CTRL_WCLK, + [ZX297520V3_EDCP_WCLK] = ZX_CLK_EDCP_WCLK, + [ZX297520V3_EDCP_PCLK] = ZX_CLK_EDCP_PCLK, + [ZX297520V3_SD0_WCLK] = ZX_CLK_SD0_WCLK, + [ZX297520V3_SD0_PCLK] = ZX_CLK_SD0_PCLK, + [ZX297520V3_SD0_CDET] = ZX_CLK_SD0_CDET, + [ZX297520V3_SD1_WCLK] = ZX_CLK_SD1_WCLK, + [ZX297520V3_SD1_PCLK] = ZX_CLK_SD1_PCLK, + [ZX297520V3_SD1_CDET] = ZX_CLK_SD1_CDET, + [ZX297520V3_NAND_WCLK] = ZX_CLK_NAND_WCLK, + [ZX297520V3_NAND_PCLK] = ZX_CLK_NAND_PCLK, + [ZX297520V3_DMA_PCLK] = ZX_CLK_DMA_PCLK, + [ZX297520V3_MBOX_PCLK] = ZX_CLK_MBOX_PCLK, + [ZX297520V3_PDCFG_WCLK] = ZX_CLK_PDCFG_WCLK, + [ZX297520V3_PDCFG_PCLK] = ZX_CLK_PDCFG_PCLK, + [ZX297520V3_RFFE_WCLK] = ZX_CLK_RFFE_WCLK, + [ZX297520V3_SSC_WCLK] = ZX_CLK_SSC_WCLK, + [ZX297520V3_SSC_PCLK] = ZX_CLK_SSC_PCLK, + [ZX297520V3_AXI_WCLK] = ZX_CLK_AXI_WCLK, + [ZX297520V3_GMAC_WCLK] = ZX_CLK_GMAC_WCLK, + [ZX297520V3_GMAC_PCLK] = ZX_CLK_GMAC_PCLK, + [ZX297520V3_GMAC_AHB] = ZX_CLK_GMAC_AHB, + [ZX297520V3_VOU_WCLK] = ZX_CLK_VOU_WCLK, + [ZX297520V3_VOU_PCLK] = ZX_CLK_VOU_PCLK, + [ZX297520V3_LSP_MPLL_D5_WCLK] = ZX_CLK_TOLSP_MPLL_D5_WCLK, + [ZX297520V3_LSP_MPLL_D4_WCLK] = ZX_CLK_TOLSP_MPLL_D4_WCLK, + [ZX297520V3_LSP_MPLL_D6_WCLK] = ZX_CLK_TOLSP_MPLL_D6_WCLK, + [ZX297520V3_LSP_MPLL_D8_WCLK] = ZX_CLK_TOLSP_MPLL_D8_WCLK, + [ZX297520V3_LSP_MPLL_D12_WCLK] = ZX_CLK_TOLSP_MPLL_D12_WCLK, + [ZX297520V3_LSP_OSC26M_WCLK] = ZX_CLK_TOLSP_OSC26M_WCLK, + [ZX297520V3_LSP_OSC32K_WCLK] = ZX_CLK_TOLSP_OSC32K_WCLK, + [ZX297520V3_LSP_PCLK] = ZX_CLK_TOLSP_PCLK, + [ZX297520V3_LSP_TDM_WCLK] = ZX_CLK_TOLSP_TDM_WCLK, + [ZX297520V3_LSP_DPLL_D4_WCLK] = ZX_CLK_TOLSP_DPLL_D4_WCLK, + [ZX297520V3_SRAM0_PCLK] = ZX_CLK_SRAM0_PCLK, + [ZX297520V3_GSM_CFG_PCLK] = ZX_CLK_GSM_CFG_PCLK, + [ZX297520V3_LTE_MODEM_WCLK] = ZX_CLK_LTE_MODEM_WCLK, + [ZX297520V3_LTE_MODEM_PCLK] = ZX_CLK_LTE_MODEM_PCLK, +}; + +static const struct zx_clk_data zx297520v3_matrixclk_data = { + .init = zx297520v3_matrix_init, + .clocks = zx297520v3_matrix_clocks, + .num_clocks = ARRAY_SIZE(zx297520v3_matrix_clocks), + .exports = zx297520v3_matrix_exports, + .num_exports = ARRAY_SIZE(zx297520v3_matrix_exports), +}; + static int clk_zx297520v3_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -828,6 +1350,10 @@ static const struct platform_device_id clk_zx297520v3_ids[] = { .name = "zx297520v3-topclk", .driver_data = (kernel_ulong_t)&zx297520v3_topclk_data, }, + { + .name = "zx297520v3-matrixclk", + .driver_data = (kernel_ulong_t)&zx297520v3_matrixclk_data, + }, { } }; MODULE_DEVICE_TABLE(platform, clk_zx297520v3_ids);