From 06ad98030550d4bdc94d8ffdf7164288877ca1fb Mon Sep 17 00:00:00 2001 From: Mirela Simonovic Date: Mon, 17 Sep 2018 14:25:16 +0200 Subject: [PATCH] zynqmp: pm: Fix clock models and IDs of GEM-related clocks GEM-related clock models were incorrect and are fixed as follows (documented below for GEM0, but the same holds for any GEM ID): - CLK_GEM0_REF_UNGATED represents clock that has DIV0/1 divisors and the multiplexer controllable in GEM0_REF_CTRL (CRL_APB). The ID of this clock is newly introduced in this patch. - CLK_GEM0_REF models the clock mux that selects the reference clock for Tx, i.e. selects CLK_GEM0_REF_UNGATED or external Tx clock. This mux is controllable via GEM_CLK_CTRL (IOU_SLCR), bit GEM0_REF_SRC_SEL. Note that the routing of external clock to the mux is not modelled and is assumed to be configured by the FSBL if required, and not changeable at runtime. The ID of this clock is introduced in this patch. - CLK_GEM0_TX models clock with only a gate that is controlled via bit 25 in GEM0_REF_CTRL (CRL_APB). The parent of this clock is CLK_GEM0_REF. The clock ID of CLK_GEM0_TX matches the previous ID value of CLK_GEM0_REF. This is done in order to fix the clock models and incorrect binding without requiring to change device-tree (binding of clock IDs to GEM interface). - CLK_GEM0_RX models clock that has only gate controlled via RX_CLKACT bit (26) in GEM0_REF_CTRL (CRL_APB). Parent of this clock is sourced from external RGMII PHY (via MIO or EMIO). We do not model the whole clock path to the Rx gate, since this is configured by the FSBL and never changed at runtime (and there is no mechanism to change the path at runtime). The clock ID of CLK_GEM0_RX clock is equal to the previous ID value of CLK_GEM0_TX clock. This is done because the TX/RX were swapped in device tree, so by fixing the IDs this way there is no need for device tree fix. Rates of the external RX/TX clocks can be specified in device tree if needed. Right now, that's not necessary because Tx clock is sourced from an on-chip PLL (via CLK_GEM0_REF_UNGATED/CLK_GEM0_REF), whereas the Rx clock is sourced from external reference and the driver never attempts to get/get clock rate (only to enable it). If this changes in future, ATF clock model doesn't need to be changed. Instead, the clock rates for gem0_tx_ext and gem0_rx_ext have to be specified in device tree. Signed-off-by: Mirela Simonovic Acked-by: Will Wong Signed-off-by: Jolly Shah Change-Id: I6497d4309e92205c527bd81b3aa932f4474f5b79 --- plat/xilinx/zynqmp/pm_service/pm_api_clock.c | 357 +++++++++++-------- plat/xilinx/zynqmp/pm_service/pm_api_clock.h | 28 +- 2 files changed, 236 insertions(+), 149 deletions(-) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c index 375c0b6c7..347f5892f 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c @@ -562,13 +562,13 @@ static struct pm_clock_node gpu_pp1_nodes[] = { }, }; -static struct pm_clock_node gem_nodes[] = { +static struct pm_clock_node gem_ref_ungated_nodes[] = { GENERIC_MUX, { .type = TYPE_DIV1, .offset = 8, .width = 6, - .clkflags = CLK_IS_BASIC, + .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, @@ -577,11 +577,70 @@ static struct pm_clock_node gem_nodes[] = { .type = TYPE_DIV2, .offset = 16, .width = 6, - .clkflags = CLK_IS_BASIC, + .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, +}; + +static struct pm_clock_node gem0_ref_nodes[] = { + { + .type = TYPE_MUX, + .offset = 1, + .width = 1, + .clkflags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT | + CLK_IS_BASIC, + .typeflags = NA_TYPE_FLAGS, + .mult = NA_MULT, + .div = NA_DIV, + }, +}; + +static struct pm_clock_node gem1_ref_nodes[] = { + { + .type = TYPE_MUX, + .offset = 6, + .width = 1, + .clkflags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT | + CLK_IS_BASIC, + .typeflags = NA_TYPE_FLAGS, + .mult = NA_MULT, + .div = NA_DIV, + }, +}; + +static struct pm_clock_node gem2_ref_nodes[] = { + { + .type = TYPE_MUX, + .offset = 11, + .width = 1, + .clkflags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT | + CLK_IS_BASIC, + .typeflags = NA_TYPE_FLAGS, + .mult = NA_MULT, + .div = NA_DIV, + }, +}; + +static struct pm_clock_node gem3_ref_nodes[] = { + { + .type = TYPE_MUX, + .offset = 16, + .width = 1, + .clkflags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT | + CLK_IS_BASIC, + .typeflags = NA_TYPE_FLAGS, + .mult = NA_MULT, + .div = NA_DIV, + }, +}; + +static struct pm_clock_node gem_tx_nodes[] = { { .type = TYPE_GATE, .offset = 25, @@ -593,84 +652,12 @@ static struct pm_clock_node gem_nodes[] = { }, }; -static struct pm_clock_node gem0_tx_nodes[] = { - { - .type = TYPE_MUX, - .offset = 1, - .width = 1, - .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, - .typeflags = NA_TYPE_FLAGS, - .mult = NA_MULT, - .div = NA_DIV, - }, +static struct pm_clock_node gem_rx_nodes[] = { { .type = TYPE_GATE, .offset = 26, .width = PERIPH_GATE_WIDTH, - .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, - .typeflags = NA_TYPE_FLAGS, - .mult = NA_MULT, - .div = NA_DIV, - }, -}; - -static struct pm_clock_node gem1_tx_nodes[] = { - { - .type = TYPE_MUX, - .offset = 6, - .width = 1, - .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, - .typeflags = NA_TYPE_FLAGS, - .mult = NA_MULT, - .div = NA_DIV, - }, - { - .type = TYPE_GATE, - .offset = 26, - .width = PERIPH_GATE_WIDTH, - .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, - .typeflags = NA_TYPE_FLAGS, - .mult = NA_MULT, - .div = NA_DIV, - }, -}; - -static struct pm_clock_node gem2_tx_nodes[] = { - { - .type = TYPE_MUX, - .offset = 11, - .width = 1, - .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, - .typeflags = NA_TYPE_FLAGS, - .mult = NA_MULT, - .div = NA_DIV, - }, - { - .type = TYPE_GATE, - .offset = 26, - .width = PERIPH_GATE_WIDTH, - .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, - .typeflags = NA_TYPE_FLAGS, - .mult = NA_MULT, - .div = NA_DIV, - }, -}; - -static struct pm_clock_node gem3_tx_nodes[] = { - { - .type = TYPE_MUX, - .offset = 16, - .width = 1, - .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, - .typeflags = NA_TYPE_FLAGS, - .mult = NA_MULT, - .div = NA_DIV, - }, - { - .type = TYPE_GATE, - .offset = 26, - .width = PERIPH_GATE_WIDTH, - .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, + .clkflags = CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, @@ -1442,8 +1429,8 @@ static struct pm_clock clocks[] = { .nodes = &generic_mux_div_unused_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes), }, - [CLK_GEM0_REF] = { - .name = "gem0_ref", + [CLK_GEM0_REF_UNGATED] = { + .name = "gem0_ref_ung", .control_reg = CRL_APB_GEM0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { @@ -1453,11 +1440,11 @@ static struct pm_clock clocks[] = { CLK_DPLL_TO_LPD, CLK_NA_PARENT }), - .nodes = &gem_nodes, - .num_nodes = ARRAY_SIZE(gem_nodes), + .nodes = &gem_ref_ungated_nodes, + .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes), }, - [CLK_GEM1_REF] = { - .name = "gem1_ref", + [CLK_GEM1_REF_UNGATED] = { + .name = "gem1_ref_ung", .control_reg = CRL_APB_GEM1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { @@ -1467,11 +1454,11 @@ static struct pm_clock clocks[] = { CLK_DPLL_TO_LPD, CLK_NA_PARENT }), - .nodes = &gem_nodes, - .num_nodes = ARRAY_SIZE(gem_nodes), + .nodes = &gem_ref_ungated_nodes, + .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes), }, - [CLK_GEM2_REF] = { - .name = "gem2_ref", + [CLK_GEM2_REF_UNGATED] = { + .name = "gem2_ref_ung", .control_reg = CRL_APB_GEM2_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { @@ -1481,11 +1468,11 @@ static struct pm_clock clocks[] = { CLK_DPLL_TO_LPD, CLK_NA_PARENT }), - .nodes = &gem_nodes, - .num_nodes = ARRAY_SIZE(gem_nodes), + .nodes = &gem_ref_ungated_nodes, + .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes), }, - [CLK_GEM3_REF] = { - .name = "gem3_ref", + [CLK_GEM3_REF_UNGATED] = { + .name = "gem3_ref_ung", .control_reg = CRL_APB_GEM3_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { @@ -1495,8 +1482,60 @@ static struct pm_clock clocks[] = { CLK_DPLL_TO_LPD, CLK_NA_PARENT }), - .nodes = &gem_nodes, - .num_nodes = ARRAY_SIZE(gem_nodes), + .nodes = &gem_ref_ungated_nodes, + .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes), + }, + [CLK_GEM0_REF] = { + .name = "gem0_ref", + .control_reg = IOU_SLCR_GEM_CLK_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + CLK_GEM0_REF_UNGATED | + (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), + EXT_CLK_GEM0_TX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem0_ref_nodes, + .num_nodes = ARRAY_SIZE(gem0_ref_nodes), + }, + [CLK_GEM1_REF] = { + .name = "gem1_ref", + .control_reg = IOU_SLCR_GEM_CLK_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + CLK_GEM1_REF_UNGATED | + (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), + EXT_CLK_GEM1_TX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem1_ref_nodes, + .num_nodes = ARRAY_SIZE(gem1_ref_nodes), + }, + [CLK_GEM2_REF] = { + .name = "gem2_ref", + .control_reg = IOU_SLCR_GEM_CLK_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + CLK_GEM2_REF_UNGATED | + (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), + EXT_CLK_GEM2_TX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem2_ref_nodes, + .num_nodes = ARRAY_SIZE(gem2_ref_nodes), + }, + [CLK_GEM3_REF] = { + .name = "gem3_ref", + .control_reg = IOU_SLCR_GEM_CLK_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + CLK_GEM3_REF_UNGATED | + (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), + EXT_CLK_GEM3_TX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem3_ref_nodes, + .num_nodes = ARRAY_SIZE(gem3_ref_nodes), }, [CLK_USB0_BUS_REF] = { .name = "usb0_bus_ref", @@ -1960,69 +1999,93 @@ static struct pm_clock clocks[] = { .nodes = &generic_domain_crossing_nodes, .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes), }, - /* - * This clock control requires different registers for mux and gate. - * Use control and status registers for the same. - */ [CLK_GEM0_TX] = { .name = "gem0_tx", - .control_reg = IOU_SLCR_GEM_CLK_CTRL, - .status_reg = CRL_APB_GEM0_REF_CTRL, + .control_reg = CRL_APB_GEM0_REF_CTRL, + .status_reg = 0, .parents = &((int32_t []) { - CLK_GEM0_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), - EXT_CLK_GEM0_EMIO | CLK_EXTERNAL_PARENT, + CLK_GEM0_REF, CLK_NA_PARENT }), - .nodes = &gem0_tx_nodes, - .num_nodes = ARRAY_SIZE(gem0_tx_nodes), + .nodes = &gem_tx_nodes, + .num_nodes = ARRAY_SIZE(gem_tx_nodes), }, - /* - * This clock control requires different registers for mux and gate. - * Use control and status registers for the same. - */ [CLK_GEM1_TX] = { .name = "gem1_tx", - .control_reg = IOU_SLCR_GEM_CLK_CTRL, - .status_reg = CRL_APB_GEM1_REF_CTRL, + .control_reg = CRL_APB_GEM1_REF_CTRL, + .status_reg = 0, .parents = &((int32_t []) { - CLK_GEM1_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), - EXT_CLK_GEM1_EMIO | CLK_EXTERNAL_PARENT, + CLK_GEM1_REF, CLK_NA_PARENT }), - .nodes = &gem1_tx_nodes, - .num_nodes = ARRAY_SIZE(gem1_tx_nodes), + .nodes = &gem_tx_nodes, + .num_nodes = ARRAY_SIZE(gem_tx_nodes), }, - /* - * This clock control requires different registers for mux and gate. - * Use control and status registers for the same. - */ [CLK_GEM2_TX] = { .name = "gem2_tx", - .control_reg = IOU_SLCR_GEM_CLK_CTRL, - .status_reg = CRL_APB_GEM2_REF_CTRL, + .control_reg = CRL_APB_GEM2_REF_CTRL, + .status_reg = 0, .parents = &((int32_t []) { - CLK_GEM2_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), - EXT_CLK_GEM2_EMIO | CLK_EXTERNAL_PARENT, + CLK_GEM2_REF, CLK_NA_PARENT }), - .nodes = &gem2_tx_nodes, - .num_nodes = ARRAY_SIZE(gem2_tx_nodes), + .nodes = &gem_tx_nodes, + .num_nodes = ARRAY_SIZE(gem_tx_nodes), }, - /* - * This clock control requires different registers for mux and gate. - * Use control and status registers for the same. - */ [CLK_GEM3_TX] = { .name = "gem3_tx", - .control_reg = IOU_SLCR_GEM_CLK_CTRL, - .status_reg = CRL_APB_GEM3_REF_CTRL, + .control_reg = CRL_APB_GEM3_REF_CTRL, + .status_reg = 0, .parents = &((int32_t []) { - CLK_GEM3_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), - EXT_CLK_GEM3_EMIO | CLK_EXTERNAL_PARENT, + CLK_GEM3_REF, CLK_NA_PARENT }), - .nodes = &gem3_tx_nodes, - .num_nodes = ARRAY_SIZE(gem3_tx_nodes), + .nodes = &gem_tx_nodes, + .num_nodes = ARRAY_SIZE(gem_tx_nodes), + }, + [CLK_GEM0_RX] = { + .name = "gem0_rx", + .control_reg = CRL_APB_GEM0_REF_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + EXT_CLK_GEM0_RX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem_rx_nodes, + .num_nodes = ARRAY_SIZE(gem_rx_nodes), + }, + [CLK_GEM1_RX] = { + .name = "gem1_rx", + .control_reg = CRL_APB_GEM1_REF_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + EXT_CLK_GEM1_RX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem_rx_nodes, + .num_nodes = ARRAY_SIZE(gem_rx_nodes), + }, + [CLK_GEM2_RX] = { + .name = "gem2_rx", + .control_reg = CRL_APB_GEM2_REF_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + EXT_CLK_GEM2_RX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem_rx_nodes, + .num_nodes = ARRAY_SIZE(gem_rx_nodes), + }, + [CLK_GEM3_RX] = { + .name = "gem3_rx", + .control_reg = CRL_APB_GEM3_REF_CTRL, + .status_reg = 0, + .parents = &((int32_t []) { + EXT_CLK_GEM3_RX_EMIO | CLK_EXTERNAL_PARENT, + CLK_NA_PARENT + }), + .nodes = &gem_rx_nodes, + .num_nodes = ARRAY_SIZE(gem_rx_nodes), }, [CLK_ACPU_HALF] = { .name = "acpu_half", @@ -2159,17 +2222,29 @@ static struct pm_ext_clock ext_clocks[] = { [EXT_CLK_INDEX(EXT_CLK_SWDT1)] = { .name = "swdt1_ext_clk", }, - [EXT_CLK_INDEX(EXT_CLK_GEM0_EMIO)] = { - .name = "gem0_emio_clk", + [EXT_CLK_INDEX(EXT_CLK_GEM0_TX_EMIO)] = { + .name = "gem0_tx_ext", }, - [EXT_CLK_INDEX(EXT_CLK_GEM1_EMIO)] = { - .name = "gem1_emio_clk", + [EXT_CLK_INDEX(EXT_CLK_GEM1_TX_EMIO)] = { + .name = "gem1_tx_ext", }, - [EXT_CLK_INDEX(EXT_CLK_GEM2_EMIO)] = { - .name = "gem2_emio_clk", + [EXT_CLK_INDEX(EXT_CLK_GEM2_TX_EMIO)] = { + .name = "gem2_tx_ext", }, - [EXT_CLK_INDEX(EXT_CLK_GEM3_EMIO)] = { - .name = "gem3_emio_clk", + [EXT_CLK_INDEX(EXT_CLK_GEM3_TX_EMIO)] = { + .name = "gem3_tx_ext", + }, + [EXT_CLK_INDEX(EXT_CLK_GEM0_RX_EMIO)] = { + .name = "gem0_rx_ext", + }, + [EXT_CLK_INDEX(EXT_CLK_GEM1_RX_EMIO)] = { + .name = "gem1_rx_ext", + }, + [EXT_CLK_INDEX(EXT_CLK_GEM2_RX_EMIO)] = { + .name = "gem2_rx_ext", + }, + [EXT_CLK_INDEX(EXT_CLK_GEM3_RX_EMIO)] = { + .name = "gem3_rx_ext", }, [EXT_CLK_INDEX(EXT_CLK_MIO50_OR_MIO51)] = { .name = "mio_clk_50_51", diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h index c758efdfc..4c5f22dff 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h @@ -102,14 +102,14 @@ enum clock_id { CLK_IOU_SWITCH, CLK_GEM_TSU_REF, CLK_GEM_TSU, - CLK_GEM0_REF, - CLK_GEM1_REF, - CLK_GEM2_REF, - CLK_GEM3_REF, CLK_GEM0_TX, CLK_GEM1_TX, CLK_GEM2_TX, CLK_GEM3_TX, + CLK_GEM0_RX, + CLK_GEM1_RX, + CLK_GEM2_RX, + CLK_GEM3_RX, CLK_QSPI_REF, CLK_SDIO0_REF, CLK_SDIO1_REF, @@ -161,6 +161,14 @@ enum clock_id { CLK_CAN0_MIO, CLK_CAN1_MIO, CLK_ACPU_FULL, + CLK_GEM0_REF, + CLK_GEM1_REF, + CLK_GEM2_REF, + CLK_GEM3_REF, + CLK_GEM0_REF_UNGATED, + CLK_GEM1_REF_UNGATED, + CLK_GEM2_REF_UNGATED, + CLK_GEM3_REF_UNGATED, END_OF_OUTPUT_CLKS, }; @@ -175,10 +183,14 @@ enum { EXT_CLK_GT_CRX_REF, EXT_CLK_SWDT0, EXT_CLK_SWDT1, - EXT_CLK_GEM0_EMIO, - EXT_CLK_GEM1_EMIO, - EXT_CLK_GEM2_EMIO, - EXT_CLK_GEM3_EMIO, + EXT_CLK_GEM0_TX_EMIO, + EXT_CLK_GEM1_TX_EMIO, + EXT_CLK_GEM2_TX_EMIO, + EXT_CLK_GEM3_TX_EMIO, + EXT_CLK_GEM0_RX_EMIO, + EXT_CLK_GEM1_RX_EMIO, + EXT_CLK_GEM2_RX_EMIO, + EXT_CLK_GEM3_RX_EMIO, EXT_CLK_MIO50_OR_MIO51, EXT_CLK_MIO0, EXT_CLK_MIO1,