162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Wrapper driver for SERDES used in J721E 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 662306a36Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <dt-bindings/phy/phy.h> 1062306a36Sopenharmony_ci#include <dt-bindings/phy/phy-ti.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/clk-provider.h> 1462306a36Sopenharmony_ci#include <linux/gpio.h> 1562306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1962306a36Sopenharmony_ci#include <linux/mux/consumer.h> 2062306a36Sopenharmony_ci#include <linux/of_address.h> 2162306a36Sopenharmony_ci#include <linux/of_platform.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2462306a36Sopenharmony_ci#include <linux/regmap.h> 2562306a36Sopenharmony_ci#include <linux/reset-controller.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define REF_CLK_19_2MHZ 19200000 2862306a36Sopenharmony_ci#define REF_CLK_25MHZ 25000000 2962306a36Sopenharmony_ci#define REF_CLK_100MHZ 100000000 3062306a36Sopenharmony_ci#define REF_CLK_156_25MHZ 156250000 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* SCM offsets */ 3362306a36Sopenharmony_ci#define SERDES_SUP_CTRL 0x4400 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* SERDES offsets */ 3662306a36Sopenharmony_ci#define WIZ_SERDES_CTRL 0x404 3762306a36Sopenharmony_ci#define WIZ_SERDES_TOP_CTRL 0x408 3862306a36Sopenharmony_ci#define WIZ_SERDES_RST 0x40c 3962306a36Sopenharmony_ci#define WIZ_SERDES_TYPEC 0x410 4062306a36Sopenharmony_ci#define WIZ_LANECTL(n) (0x480 + (0x40 * (n))) 4162306a36Sopenharmony_ci#define WIZ_LANEDIV(n) (0x484 + (0x40 * (n))) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define WIZ_MAX_INPUT_CLOCKS 4 4462306a36Sopenharmony_ci/* To include mux clocks, divider clocks and gate clocks */ 4562306a36Sopenharmony_ci#define WIZ_MAX_OUTPUT_CLOCKS 32 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define WIZ_MAX_LANES 4 4862306a36Sopenharmony_ci#define WIZ_MUX_NUM_CLOCKS 3 4962306a36Sopenharmony_ci#define WIZ_DIV_NUM_CLOCKS_16G 2 5062306a36Sopenharmony_ci#define WIZ_DIV_NUM_CLOCKS_10G 1 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define WIZ_SERDES_TYPEC_LN10_SWAP BIT(30) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cienum wiz_lane_standard_mode { 5562306a36Sopenharmony_ci LANE_MODE_GEN1, 5662306a36Sopenharmony_ci LANE_MODE_GEN2, 5762306a36Sopenharmony_ci LANE_MODE_GEN3, 5862306a36Sopenharmony_ci LANE_MODE_GEN4, 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * List of master lanes used for lane swapping 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cienum wiz_typec_master_lane { 6562306a36Sopenharmony_ci LANE0 = 0, 6662306a36Sopenharmony_ci LANE2 = 2, 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cienum wiz_refclk_mux_sel { 7062306a36Sopenharmony_ci PLL0_REFCLK, 7162306a36Sopenharmony_ci PLL1_REFCLK, 7262306a36Sopenharmony_ci REFCLK_DIG, 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cienum wiz_refclk_div_sel { 7662306a36Sopenharmony_ci CMN_REFCLK_DIG_DIV, 7762306a36Sopenharmony_ci CMN_REFCLK1_DIG_DIV, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cienum wiz_clock_input { 8162306a36Sopenharmony_ci WIZ_CORE_REFCLK, 8262306a36Sopenharmony_ci WIZ_EXT_REFCLK, 8362306a36Sopenharmony_ci WIZ_CORE_REFCLK1, 8462306a36Sopenharmony_ci WIZ_EXT_REFCLK1, 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic const struct reg_field por_en = REG_FIELD(WIZ_SERDES_CTRL, 31, 31); 8862306a36Sopenharmony_cistatic const struct reg_field phy_reset_n = REG_FIELD(WIZ_SERDES_RST, 31, 31); 8962306a36Sopenharmony_cistatic const struct reg_field phy_en_refclk = REG_FIELD(WIZ_SERDES_RST, 30, 30); 9062306a36Sopenharmony_cistatic const struct reg_field pll1_refclk_mux_sel = 9162306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_RST, 29, 29); 9262306a36Sopenharmony_cistatic const struct reg_field pll1_refclk_mux_sel_2 = 9362306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_RST, 22, 23); 9462306a36Sopenharmony_cistatic const struct reg_field pll0_refclk_mux_sel = 9562306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_RST, 28, 28); 9662306a36Sopenharmony_cistatic const struct reg_field pll0_refclk_mux_sel_2 = 9762306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_RST, 28, 29); 9862306a36Sopenharmony_cistatic const struct reg_field refclk_dig_sel_16g = 9962306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_RST, 24, 25); 10062306a36Sopenharmony_cistatic const struct reg_field refclk_dig_sel_10g = 10162306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_RST, 24, 24); 10262306a36Sopenharmony_cistatic const struct reg_field pma_cmn_refclk_int_mode = 10362306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_TOP_CTRL, 28, 29); 10462306a36Sopenharmony_cistatic const struct reg_field pma_cmn_refclk1_int_mode = 10562306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_TOP_CTRL, 20, 21); 10662306a36Sopenharmony_cistatic const struct reg_field pma_cmn_refclk_mode = 10762306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_TOP_CTRL, 30, 31); 10862306a36Sopenharmony_cistatic const struct reg_field pma_cmn_refclk_dig_div = 10962306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_TOP_CTRL, 26, 27); 11062306a36Sopenharmony_cistatic const struct reg_field pma_cmn_refclk1_dig_div = 11162306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_TOP_CTRL, 24, 25); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic const struct reg_field sup_pll0_refclk_mux_sel = 11462306a36Sopenharmony_ci REG_FIELD(SERDES_SUP_CTRL, 0, 1); 11562306a36Sopenharmony_cistatic const struct reg_field sup_pll1_refclk_mux_sel = 11662306a36Sopenharmony_ci REG_FIELD(SERDES_SUP_CTRL, 2, 3); 11762306a36Sopenharmony_cistatic const struct reg_field sup_pma_cmn_refclk1_int_mode = 11862306a36Sopenharmony_ci REG_FIELD(SERDES_SUP_CTRL, 4, 5); 11962306a36Sopenharmony_cistatic const struct reg_field sup_refclk_dig_sel_10g = 12062306a36Sopenharmony_ci REG_FIELD(SERDES_SUP_CTRL, 6, 7); 12162306a36Sopenharmony_cistatic const struct reg_field sup_legacy_clk_override = 12262306a36Sopenharmony_ci REG_FIELD(SERDES_SUP_CTRL, 8, 8); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic const char * const output_clk_names[] = { 12562306a36Sopenharmony_ci [TI_WIZ_PLL0_REFCLK] = "pll0-refclk", 12662306a36Sopenharmony_ci [TI_WIZ_PLL1_REFCLK] = "pll1-refclk", 12762306a36Sopenharmony_ci [TI_WIZ_REFCLK_DIG] = "refclk-dig", 12862306a36Sopenharmony_ci [TI_WIZ_PHY_EN_REFCLK] = "phy-en-refclk", 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic const struct reg_field p_enable[WIZ_MAX_LANES] = { 13262306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 30, 31), 13362306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 30, 31), 13462306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 30, 31), 13562306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 30, 31), 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cienum p_enable { P_ENABLE = 2, P_ENABLE_FORCE = 1, P_ENABLE_DISABLE = 0 }; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic const struct reg_field p_align[WIZ_MAX_LANES] = { 14162306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 29, 29), 14262306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 29, 29), 14362306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 29, 29), 14462306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 29, 29), 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic const struct reg_field p_raw_auto_start[WIZ_MAX_LANES] = { 14862306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 28, 28), 14962306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 28, 28), 15062306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 28, 28), 15162306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 28, 28), 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic const struct reg_field p_standard_mode[WIZ_MAX_LANES] = { 15562306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 24, 25), 15662306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 24, 25), 15762306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 24, 25), 15862306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 24, 25), 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic const struct reg_field p0_fullrt_div[WIZ_MAX_LANES] = { 16262306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 22, 23), 16362306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 22, 23), 16462306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 22, 23), 16562306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 22, 23), 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic const struct reg_field p0_mac_src_sel[WIZ_MAX_LANES] = { 16962306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 20, 21), 17062306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 20, 21), 17162306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 20, 21), 17262306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 20, 21), 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic const struct reg_field p0_rxfclk_sel[WIZ_MAX_LANES] = { 17662306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 6, 7), 17762306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 6, 7), 17862306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 6, 7), 17962306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 6, 7), 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const struct reg_field p0_refclk_sel[WIZ_MAX_LANES] = { 18362306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(0), 18, 19), 18462306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(1), 18, 19), 18562306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(2), 18, 19), 18662306a36Sopenharmony_ci REG_FIELD(WIZ_LANECTL(3), 18, 19), 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_cistatic const struct reg_field p_mac_div_sel0[WIZ_MAX_LANES] = { 18962306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(0), 16, 22), 19062306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(1), 16, 22), 19162306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(2), 16, 22), 19262306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(3), 16, 22), 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic const struct reg_field p_mac_div_sel1[WIZ_MAX_LANES] = { 19662306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(0), 0, 8), 19762306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(1), 0, 8), 19862306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(2), 0, 8), 19962306a36Sopenharmony_ci REG_FIELD(WIZ_LANEDIV(3), 0, 8), 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic const struct reg_field typec_ln10_swap = 20362306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_TYPEC, 30, 30); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic const struct reg_field typec_ln23_swap = 20662306a36Sopenharmony_ci REG_FIELD(WIZ_SERDES_TYPEC, 31, 31); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistruct wiz_clk_mux { 20962306a36Sopenharmony_ci struct clk_hw hw; 21062306a36Sopenharmony_ci struct regmap_field *field; 21162306a36Sopenharmony_ci const u32 *table; 21262306a36Sopenharmony_ci struct clk_init_data clk_data; 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#define to_wiz_clk_mux(_hw) container_of(_hw, struct wiz_clk_mux, hw) 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistruct wiz_clk_divider { 21862306a36Sopenharmony_ci struct clk_hw hw; 21962306a36Sopenharmony_ci struct regmap_field *field; 22062306a36Sopenharmony_ci const struct clk_div_table *table; 22162306a36Sopenharmony_ci struct clk_init_data clk_data; 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define to_wiz_clk_div(_hw) container_of(_hw, struct wiz_clk_divider, hw) 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistruct wiz_clk_mux_sel { 22762306a36Sopenharmony_ci u32 table[WIZ_MAX_INPUT_CLOCKS]; 22862306a36Sopenharmony_ci const char *node_name; 22962306a36Sopenharmony_ci u32 num_parents; 23062306a36Sopenharmony_ci u32 parents[WIZ_MAX_INPUT_CLOCKS]; 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistruct wiz_clk_div_sel { 23462306a36Sopenharmony_ci const struct clk_div_table *table; 23562306a36Sopenharmony_ci const char *node_name; 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistruct wiz_phy_en_refclk { 23962306a36Sopenharmony_ci struct clk_hw hw; 24062306a36Sopenharmony_ci struct regmap_field *phy_en_refclk; 24162306a36Sopenharmony_ci struct clk_init_data clk_data; 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci#define to_wiz_phy_en_refclk(_hw) container_of(_hw, struct wiz_phy_en_refclk, hw) 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic const struct wiz_clk_mux_sel clk_mux_sel_16g[] = { 24762306a36Sopenharmony_ci { 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * Mux value to be configured for each of the input clocks 25062306a36Sopenharmony_ci * in the order populated in device tree 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci .table = { 1, 0 }, 25362306a36Sopenharmony_ci .node_name = "pll0-refclk", 25462306a36Sopenharmony_ci }, 25562306a36Sopenharmony_ci { 25662306a36Sopenharmony_ci .table = { 1, 0 }, 25762306a36Sopenharmony_ci .node_name = "pll1-refclk", 25862306a36Sopenharmony_ci }, 25962306a36Sopenharmony_ci { 26062306a36Sopenharmony_ci .table = { 1, 3, 0, 2 }, 26162306a36Sopenharmony_ci .node_name = "refclk-dig", 26262306a36Sopenharmony_ci }, 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic const struct wiz_clk_mux_sel clk_mux_sel_10g[] = { 26662306a36Sopenharmony_ci { 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * Mux value to be configured for each of the input clocks 26962306a36Sopenharmony_ci * in the order populated in device tree 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci .num_parents = 2, 27262306a36Sopenharmony_ci .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, 27362306a36Sopenharmony_ci .table = { 1, 0 }, 27462306a36Sopenharmony_ci .node_name = "pll0-refclk", 27562306a36Sopenharmony_ci }, 27662306a36Sopenharmony_ci { 27762306a36Sopenharmony_ci .num_parents = 2, 27862306a36Sopenharmony_ci .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, 27962306a36Sopenharmony_ci .table = { 1, 0 }, 28062306a36Sopenharmony_ci .node_name = "pll1-refclk", 28162306a36Sopenharmony_ci }, 28262306a36Sopenharmony_ci { 28362306a36Sopenharmony_ci .num_parents = 2, 28462306a36Sopenharmony_ci .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, 28562306a36Sopenharmony_ci .table = { 1, 0 }, 28662306a36Sopenharmony_ci .node_name = "refclk-dig", 28762306a36Sopenharmony_ci }, 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic const struct wiz_clk_mux_sel clk_mux_sel_10g_2_refclk[] = { 29162306a36Sopenharmony_ci { 29262306a36Sopenharmony_ci .num_parents = 3, 29362306a36Sopenharmony_ci .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK }, 29462306a36Sopenharmony_ci .table = { 2, 3, 0 }, 29562306a36Sopenharmony_ci .node_name = "pll0-refclk", 29662306a36Sopenharmony_ci }, 29762306a36Sopenharmony_ci { 29862306a36Sopenharmony_ci .num_parents = 3, 29962306a36Sopenharmony_ci .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK }, 30062306a36Sopenharmony_ci .table = { 2, 3, 0 }, 30162306a36Sopenharmony_ci .node_name = "pll1-refclk", 30262306a36Sopenharmony_ci }, 30362306a36Sopenharmony_ci { 30462306a36Sopenharmony_ci .num_parents = 3, 30562306a36Sopenharmony_ci .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK }, 30662306a36Sopenharmony_ci .table = { 2, 3, 0 }, 30762306a36Sopenharmony_ci .node_name = "refclk-dig", 30862306a36Sopenharmony_ci }, 30962306a36Sopenharmony_ci}; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic const struct clk_div_table clk_div_table[] = { 31262306a36Sopenharmony_ci { .val = 0, .div = 1, }, 31362306a36Sopenharmony_ci { .val = 1, .div = 2, }, 31462306a36Sopenharmony_ci { .val = 2, .div = 4, }, 31562306a36Sopenharmony_ci { .val = 3, .div = 8, }, 31662306a36Sopenharmony_ci { /* sentinel */ }, 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic const struct wiz_clk_div_sel clk_div_sel[] = { 32062306a36Sopenharmony_ci { 32162306a36Sopenharmony_ci .table = clk_div_table, 32262306a36Sopenharmony_ci .node_name = "cmn-refclk-dig-div", 32362306a36Sopenharmony_ci }, 32462306a36Sopenharmony_ci { 32562306a36Sopenharmony_ci .table = clk_div_table, 32662306a36Sopenharmony_ci .node_name = "cmn-refclk1-dig-div", 32762306a36Sopenharmony_ci }, 32862306a36Sopenharmony_ci}; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cienum wiz_type { 33162306a36Sopenharmony_ci J721E_WIZ_16G, 33262306a36Sopenharmony_ci J721E_WIZ_10G, /* Also for J7200 SR1.0 */ 33362306a36Sopenharmony_ci AM64_WIZ_10G, 33462306a36Sopenharmony_ci J7200_WIZ_10G, /* J7200 SR2.0 */ 33562306a36Sopenharmony_ci J784S4_WIZ_10G, 33662306a36Sopenharmony_ci J721S2_WIZ_10G, 33762306a36Sopenharmony_ci}; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistruct wiz_data { 34062306a36Sopenharmony_ci enum wiz_type type; 34162306a36Sopenharmony_ci const struct reg_field *pll0_refclk_mux_sel; 34262306a36Sopenharmony_ci const struct reg_field *pll1_refclk_mux_sel; 34362306a36Sopenharmony_ci const struct reg_field *refclk_dig_sel; 34462306a36Sopenharmony_ci const struct reg_field *pma_cmn_refclk1_dig_div; 34562306a36Sopenharmony_ci const struct reg_field *pma_cmn_refclk1_int_mode; 34662306a36Sopenharmony_ci const struct wiz_clk_mux_sel *clk_mux_sel; 34762306a36Sopenharmony_ci unsigned int clk_div_sel_num; 34862306a36Sopenharmony_ci}; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci#define WIZ_TYPEC_DIR_DEBOUNCE_MIN 100 /* ms */ 35162306a36Sopenharmony_ci#define WIZ_TYPEC_DIR_DEBOUNCE_MAX 1000 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistruct wiz { 35462306a36Sopenharmony_ci struct regmap *regmap; 35562306a36Sopenharmony_ci struct regmap *scm_regmap; 35662306a36Sopenharmony_ci enum wiz_type type; 35762306a36Sopenharmony_ci const struct wiz_clk_mux_sel *clk_mux_sel; 35862306a36Sopenharmony_ci const struct wiz_clk_div_sel *clk_div_sel; 35962306a36Sopenharmony_ci unsigned int clk_div_sel_num; 36062306a36Sopenharmony_ci struct regmap_field *por_en; 36162306a36Sopenharmony_ci struct regmap_field *phy_reset_n; 36262306a36Sopenharmony_ci struct regmap_field *phy_en_refclk; 36362306a36Sopenharmony_ci struct regmap_field *p_enable[WIZ_MAX_LANES]; 36462306a36Sopenharmony_ci struct regmap_field *p_align[WIZ_MAX_LANES]; 36562306a36Sopenharmony_ci struct regmap_field *p_raw_auto_start[WIZ_MAX_LANES]; 36662306a36Sopenharmony_ci struct regmap_field *p_standard_mode[WIZ_MAX_LANES]; 36762306a36Sopenharmony_ci struct regmap_field *p_mac_div_sel0[WIZ_MAX_LANES]; 36862306a36Sopenharmony_ci struct regmap_field *p_mac_div_sel1[WIZ_MAX_LANES]; 36962306a36Sopenharmony_ci struct regmap_field *p0_fullrt_div[WIZ_MAX_LANES]; 37062306a36Sopenharmony_ci struct regmap_field *p0_mac_src_sel[WIZ_MAX_LANES]; 37162306a36Sopenharmony_ci struct regmap_field *p0_rxfclk_sel[WIZ_MAX_LANES]; 37262306a36Sopenharmony_ci struct regmap_field *p0_refclk_sel[WIZ_MAX_LANES]; 37362306a36Sopenharmony_ci struct regmap_field *pma_cmn_refclk_int_mode; 37462306a36Sopenharmony_ci struct regmap_field *pma_cmn_refclk1_int_mode; 37562306a36Sopenharmony_ci struct regmap_field *pma_cmn_refclk_mode; 37662306a36Sopenharmony_ci struct regmap_field *pma_cmn_refclk_dig_div; 37762306a36Sopenharmony_ci struct regmap_field *pma_cmn_refclk1_dig_div; 37862306a36Sopenharmony_ci struct regmap_field *mux_sel_field[WIZ_MUX_NUM_CLOCKS]; 37962306a36Sopenharmony_ci struct regmap_field *div_sel_field[WIZ_DIV_NUM_CLOCKS_16G]; 38062306a36Sopenharmony_ci struct regmap_field *typec_ln10_swap; 38162306a36Sopenharmony_ci struct regmap_field *typec_ln23_swap; 38262306a36Sopenharmony_ci struct regmap_field *sup_legacy_clk_override; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci struct device *dev; 38562306a36Sopenharmony_ci u32 num_lanes; 38662306a36Sopenharmony_ci struct platform_device *serdes_pdev; 38762306a36Sopenharmony_ci struct reset_controller_dev wiz_phy_reset_dev; 38862306a36Sopenharmony_ci struct gpio_desc *gpio_typec_dir; 38962306a36Sopenharmony_ci int typec_dir_delay; 39062306a36Sopenharmony_ci u32 lane_phy_type[WIZ_MAX_LANES]; 39162306a36Sopenharmony_ci u32 master_lane_num[WIZ_MAX_LANES]; 39262306a36Sopenharmony_ci struct clk *input_clks[WIZ_MAX_INPUT_CLOCKS]; 39362306a36Sopenharmony_ci struct clk *output_clks[WIZ_MAX_OUTPUT_CLOCKS]; 39462306a36Sopenharmony_ci struct clk_onecell_data clk_data; 39562306a36Sopenharmony_ci const struct wiz_data *data; 39662306a36Sopenharmony_ci}; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int wiz_reset(struct wiz *wiz) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci int ret; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci ret = regmap_field_write(wiz->por_en, 0x1); 40362306a36Sopenharmony_ci if (ret) 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci mdelay(1); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = regmap_field_write(wiz->por_en, 0x0); 40962306a36Sopenharmony_ci if (ret) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int wiz_p_mac_div_sel(struct wiz *wiz) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci u32 num_lanes = wiz->num_lanes; 41862306a36Sopenharmony_ci int ret; 41962306a36Sopenharmony_ci int i; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci for (i = 0; i < num_lanes; i++) { 42262306a36Sopenharmony_ci if (wiz->lane_phy_type[i] == PHY_TYPE_SGMII || 42362306a36Sopenharmony_ci wiz->lane_phy_type[i] == PHY_TYPE_QSGMII || 42462306a36Sopenharmony_ci wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) { 42562306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_mac_div_sel0[i], 1); 42662306a36Sopenharmony_ci if (ret) 42762306a36Sopenharmony_ci return ret; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_mac_div_sel1[i], 2); 43062306a36Sopenharmony_ci if (ret) 43162306a36Sopenharmony_ci return ret; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int wiz_mode_select(struct wiz *wiz) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci u32 num_lanes = wiz->num_lanes; 44162306a36Sopenharmony_ci enum wiz_lane_standard_mode mode; 44262306a36Sopenharmony_ci int ret; 44362306a36Sopenharmony_ci int i; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci for (i = 0; i < num_lanes; i++) { 44662306a36Sopenharmony_ci if (wiz->lane_phy_type[i] == PHY_TYPE_DP) { 44762306a36Sopenharmony_ci mode = LANE_MODE_GEN1; 44862306a36Sopenharmony_ci } else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) { 44962306a36Sopenharmony_ci mode = LANE_MODE_GEN2; 45062306a36Sopenharmony_ci } else if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) { 45162306a36Sopenharmony_ci ret = regmap_field_write(wiz->p0_mac_src_sel[i], 0x3); 45262306a36Sopenharmony_ci ret = regmap_field_write(wiz->p0_rxfclk_sel[i], 0x3); 45362306a36Sopenharmony_ci ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x3); 45462306a36Sopenharmony_ci mode = LANE_MODE_GEN1; 45562306a36Sopenharmony_ci } else { 45662306a36Sopenharmony_ci continue; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_standard_mode[i], mode); 46062306a36Sopenharmony_ci if (ret) 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int wiz_init_raw_interface(struct wiz *wiz, bool enable) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci u32 num_lanes = wiz->num_lanes; 47062306a36Sopenharmony_ci int i; 47162306a36Sopenharmony_ci int ret; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci for (i = 0; i < num_lanes; i++) { 47462306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_align[i], enable); 47562306a36Sopenharmony_ci if (ret) 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_raw_auto_start[i], enable); 47962306a36Sopenharmony_ci if (ret) 48062306a36Sopenharmony_ci return ret; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic int wiz_init(struct wiz *wiz) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct device *dev = wiz->dev; 48962306a36Sopenharmony_ci int ret; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci ret = wiz_reset(wiz); 49262306a36Sopenharmony_ci if (ret) { 49362306a36Sopenharmony_ci dev_err(dev, "WIZ reset failed\n"); 49462306a36Sopenharmony_ci return ret; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci ret = wiz_mode_select(wiz); 49862306a36Sopenharmony_ci if (ret) { 49962306a36Sopenharmony_ci dev_err(dev, "WIZ mode select failed\n"); 50062306a36Sopenharmony_ci return ret; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ret = wiz_p_mac_div_sel(wiz); 50462306a36Sopenharmony_ci if (ret) { 50562306a36Sopenharmony_ci dev_err(dev, "Configuring P0 MAC DIV SEL failed\n"); 50662306a36Sopenharmony_ci return ret; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ret = wiz_init_raw_interface(wiz, true); 51062306a36Sopenharmony_ci if (ret) { 51162306a36Sopenharmony_ci dev_err(dev, "WIZ interface initialization failed\n"); 51262306a36Sopenharmony_ci return ret; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic int wiz_regfield_init(struct wiz *wiz) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct regmap *regmap = wiz->regmap; 52162306a36Sopenharmony_ci struct regmap *scm_regmap = wiz->regmap; /* updated later to scm_regmap if applicable */ 52262306a36Sopenharmony_ci int num_lanes = wiz->num_lanes; 52362306a36Sopenharmony_ci struct device *dev = wiz->dev; 52462306a36Sopenharmony_ci const struct wiz_data *data = wiz->data; 52562306a36Sopenharmony_ci int i; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci wiz->por_en = devm_regmap_field_alloc(dev, regmap, por_en); 52862306a36Sopenharmony_ci if (IS_ERR(wiz->por_en)) { 52962306a36Sopenharmony_ci dev_err(dev, "POR_EN reg field init failed\n"); 53062306a36Sopenharmony_ci return PTR_ERR(wiz->por_en); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci wiz->phy_reset_n = devm_regmap_field_alloc(dev, regmap, 53462306a36Sopenharmony_ci phy_reset_n); 53562306a36Sopenharmony_ci if (IS_ERR(wiz->phy_reset_n)) { 53662306a36Sopenharmony_ci dev_err(dev, "PHY_RESET_N reg field init failed\n"); 53762306a36Sopenharmony_ci return PTR_ERR(wiz->phy_reset_n); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci wiz->pma_cmn_refclk_int_mode = 54162306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk_int_mode); 54262306a36Sopenharmony_ci if (IS_ERR(wiz->pma_cmn_refclk_int_mode)) { 54362306a36Sopenharmony_ci dev_err(dev, "PMA_CMN_REFCLK_INT_MODE reg field init failed\n"); 54462306a36Sopenharmony_ci return PTR_ERR(wiz->pma_cmn_refclk_int_mode); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci wiz->pma_cmn_refclk_mode = 54862306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk_mode); 54962306a36Sopenharmony_ci if (IS_ERR(wiz->pma_cmn_refclk_mode)) { 55062306a36Sopenharmony_ci dev_err(dev, "PMA_CMN_REFCLK_MODE reg field init failed\n"); 55162306a36Sopenharmony_ci return PTR_ERR(wiz->pma_cmn_refclk_mode); 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci wiz->div_sel_field[CMN_REFCLK_DIG_DIV] = 55562306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk_dig_div); 55662306a36Sopenharmony_ci if (IS_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV])) { 55762306a36Sopenharmony_ci dev_err(dev, "PMA_CMN_REFCLK_DIG_DIV reg field init failed\n"); 55862306a36Sopenharmony_ci return PTR_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV]); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (data->pma_cmn_refclk1_dig_div) { 56262306a36Sopenharmony_ci wiz->div_sel_field[CMN_REFCLK1_DIG_DIV] = 56362306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, 56462306a36Sopenharmony_ci *data->pma_cmn_refclk1_dig_div); 56562306a36Sopenharmony_ci if (IS_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV])) { 56662306a36Sopenharmony_ci dev_err(dev, "PMA_CMN_REFCLK1_DIG_DIV reg field init failed\n"); 56762306a36Sopenharmony_ci return PTR_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV]); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (wiz->scm_regmap) { 57262306a36Sopenharmony_ci scm_regmap = wiz->scm_regmap; 57362306a36Sopenharmony_ci wiz->sup_legacy_clk_override = 57462306a36Sopenharmony_ci devm_regmap_field_alloc(dev, scm_regmap, sup_legacy_clk_override); 57562306a36Sopenharmony_ci if (IS_ERR(wiz->sup_legacy_clk_override)) { 57662306a36Sopenharmony_ci dev_err(dev, "SUP_LEGACY_CLK_OVERRIDE reg field init failed\n"); 57762306a36Sopenharmony_ci return PTR_ERR(wiz->sup_legacy_clk_override); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci wiz->mux_sel_field[PLL0_REFCLK] = 58262306a36Sopenharmony_ci devm_regmap_field_alloc(dev, scm_regmap, *data->pll0_refclk_mux_sel); 58362306a36Sopenharmony_ci if (IS_ERR(wiz->mux_sel_field[PLL0_REFCLK])) { 58462306a36Sopenharmony_ci dev_err(dev, "PLL0_REFCLK_SEL reg field init failed\n"); 58562306a36Sopenharmony_ci return PTR_ERR(wiz->mux_sel_field[PLL0_REFCLK]); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci wiz->mux_sel_field[PLL1_REFCLK] = 58962306a36Sopenharmony_ci devm_regmap_field_alloc(dev, scm_regmap, *data->pll1_refclk_mux_sel); 59062306a36Sopenharmony_ci if (IS_ERR(wiz->mux_sel_field[PLL1_REFCLK])) { 59162306a36Sopenharmony_ci dev_err(dev, "PLL1_REFCLK_SEL reg field init failed\n"); 59262306a36Sopenharmony_ci return PTR_ERR(wiz->mux_sel_field[PLL1_REFCLK]); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, scm_regmap, 59662306a36Sopenharmony_ci *data->refclk_dig_sel); 59762306a36Sopenharmony_ci if (IS_ERR(wiz->mux_sel_field[REFCLK_DIG])) { 59862306a36Sopenharmony_ci dev_err(dev, "REFCLK_DIG_SEL reg field init failed\n"); 59962306a36Sopenharmony_ci return PTR_ERR(wiz->mux_sel_field[REFCLK_DIG]); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (data->pma_cmn_refclk1_int_mode) { 60362306a36Sopenharmony_ci wiz->pma_cmn_refclk1_int_mode = 60462306a36Sopenharmony_ci devm_regmap_field_alloc(dev, scm_regmap, *data->pma_cmn_refclk1_int_mode); 60562306a36Sopenharmony_ci if (IS_ERR(wiz->pma_cmn_refclk1_int_mode)) { 60662306a36Sopenharmony_ci dev_err(dev, "PMA_CMN_REFCLK1_INT_MODE reg field init failed\n"); 60762306a36Sopenharmony_ci return PTR_ERR(wiz->pma_cmn_refclk1_int_mode); 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci for (i = 0; i < num_lanes; i++) { 61262306a36Sopenharmony_ci wiz->p_enable[i] = devm_regmap_field_alloc(dev, regmap, 61362306a36Sopenharmony_ci p_enable[i]); 61462306a36Sopenharmony_ci if (IS_ERR(wiz->p_enable[i])) { 61562306a36Sopenharmony_ci dev_err(dev, "P%d_ENABLE reg field init failed\n", i); 61662306a36Sopenharmony_ci return PTR_ERR(wiz->p_enable[i]); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci wiz->p_align[i] = devm_regmap_field_alloc(dev, regmap, 62062306a36Sopenharmony_ci p_align[i]); 62162306a36Sopenharmony_ci if (IS_ERR(wiz->p_align[i])) { 62262306a36Sopenharmony_ci dev_err(dev, "P%d_ALIGN reg field init failed\n", i); 62362306a36Sopenharmony_ci return PTR_ERR(wiz->p_align[i]); 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci wiz->p_raw_auto_start[i] = 62762306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, p_raw_auto_start[i]); 62862306a36Sopenharmony_ci if (IS_ERR(wiz->p_raw_auto_start[i])) { 62962306a36Sopenharmony_ci dev_err(dev, "P%d_RAW_AUTO_START reg field init fail\n", 63062306a36Sopenharmony_ci i); 63162306a36Sopenharmony_ci return PTR_ERR(wiz->p_raw_auto_start[i]); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci wiz->p_standard_mode[i] = 63562306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, p_standard_mode[i]); 63662306a36Sopenharmony_ci if (IS_ERR(wiz->p_standard_mode[i])) { 63762306a36Sopenharmony_ci dev_err(dev, "P%d_STANDARD_MODE reg field init fail\n", 63862306a36Sopenharmony_ci i); 63962306a36Sopenharmony_ci return PTR_ERR(wiz->p_standard_mode[i]); 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci wiz->p0_fullrt_div[i] = devm_regmap_field_alloc(dev, regmap, p0_fullrt_div[i]); 64362306a36Sopenharmony_ci if (IS_ERR(wiz->p0_fullrt_div[i])) { 64462306a36Sopenharmony_ci dev_err(dev, "P%d_FULLRT_DIV reg field init failed\n", i); 64562306a36Sopenharmony_ci return PTR_ERR(wiz->p0_fullrt_div[i]); 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci wiz->p0_mac_src_sel[i] = devm_regmap_field_alloc(dev, regmap, p0_mac_src_sel[i]); 64962306a36Sopenharmony_ci if (IS_ERR(wiz->p0_mac_src_sel[i])) { 65062306a36Sopenharmony_ci dev_err(dev, "P%d_MAC_SRC_SEL reg field init failed\n", i); 65162306a36Sopenharmony_ci return PTR_ERR(wiz->p0_mac_src_sel[i]); 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci wiz->p0_rxfclk_sel[i] = devm_regmap_field_alloc(dev, regmap, p0_rxfclk_sel[i]); 65562306a36Sopenharmony_ci if (IS_ERR(wiz->p0_rxfclk_sel[i])) { 65662306a36Sopenharmony_ci dev_err(dev, "P%d_RXFCLK_SEL reg field init failed\n", i); 65762306a36Sopenharmony_ci return PTR_ERR(wiz->p0_rxfclk_sel[i]); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci wiz->p0_refclk_sel[i] = devm_regmap_field_alloc(dev, regmap, p0_refclk_sel[i]); 66162306a36Sopenharmony_ci if (IS_ERR(wiz->p0_refclk_sel[i])) { 66262306a36Sopenharmony_ci dev_err(dev, "P%d_REFCLK_SEL reg field init failed\n", i); 66362306a36Sopenharmony_ci return PTR_ERR(wiz->p0_refclk_sel[i]); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci wiz->p_mac_div_sel0[i] = 66762306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, p_mac_div_sel0[i]); 66862306a36Sopenharmony_ci if (IS_ERR(wiz->p_mac_div_sel0[i])) { 66962306a36Sopenharmony_ci dev_err(dev, "P%d_MAC_DIV_SEL0 reg field init fail\n", 67062306a36Sopenharmony_ci i); 67162306a36Sopenharmony_ci return PTR_ERR(wiz->p_mac_div_sel0[i]); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci wiz->p_mac_div_sel1[i] = 67562306a36Sopenharmony_ci devm_regmap_field_alloc(dev, regmap, p_mac_div_sel1[i]); 67662306a36Sopenharmony_ci if (IS_ERR(wiz->p_mac_div_sel1[i])) { 67762306a36Sopenharmony_ci dev_err(dev, "P%d_MAC_DIV_SEL1 reg field init fail\n", 67862306a36Sopenharmony_ci i); 67962306a36Sopenharmony_ci return PTR_ERR(wiz->p_mac_div_sel1[i]); 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci wiz->typec_ln10_swap = devm_regmap_field_alloc(dev, regmap, 68462306a36Sopenharmony_ci typec_ln10_swap); 68562306a36Sopenharmony_ci if (IS_ERR(wiz->typec_ln10_swap)) { 68662306a36Sopenharmony_ci dev_err(dev, "LN10_SWAP reg field init failed\n"); 68762306a36Sopenharmony_ci return PTR_ERR(wiz->typec_ln10_swap); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci wiz->typec_ln23_swap = devm_regmap_field_alloc(dev, regmap, 69162306a36Sopenharmony_ci typec_ln23_swap); 69262306a36Sopenharmony_ci if (IS_ERR(wiz->typec_ln23_swap)) { 69362306a36Sopenharmony_ci dev_err(dev, "LN23_SWAP reg field init failed\n"); 69462306a36Sopenharmony_ci return PTR_ERR(wiz->typec_ln23_swap); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci wiz->phy_en_refclk = devm_regmap_field_alloc(dev, regmap, phy_en_refclk); 69862306a36Sopenharmony_ci if (IS_ERR(wiz->phy_en_refclk)) { 69962306a36Sopenharmony_ci dev_err(dev, "PHY_EN_REFCLK reg field init failed\n"); 70062306a36Sopenharmony_ci return PTR_ERR(wiz->phy_en_refclk); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int wiz_phy_en_refclk_enable(struct clk_hw *hw) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); 70962306a36Sopenharmony_ci struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci regmap_field_write(phy_en_refclk, 1); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void wiz_phy_en_refclk_disable(struct clk_hw *hw) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); 71962306a36Sopenharmony_ci struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci regmap_field_write(phy_en_refclk, 0); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int wiz_phy_en_refclk_is_enabled(struct clk_hw *hw) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); 72762306a36Sopenharmony_ci struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; 72862306a36Sopenharmony_ci int val; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci regmap_field_read(phy_en_refclk, &val); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci return !!val; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic const struct clk_ops wiz_phy_en_refclk_ops = { 73662306a36Sopenharmony_ci .enable = wiz_phy_en_refclk_enable, 73762306a36Sopenharmony_ci .disable = wiz_phy_en_refclk_disable, 73862306a36Sopenharmony_ci .is_enabled = wiz_phy_en_refclk_is_enabled, 73962306a36Sopenharmony_ci}; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int wiz_phy_en_refclk_register(struct wiz *wiz) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct wiz_phy_en_refclk *wiz_phy_en_refclk; 74462306a36Sopenharmony_ci struct device *dev = wiz->dev; 74562306a36Sopenharmony_ci struct clk_init_data *init; 74662306a36Sopenharmony_ci struct clk *clk; 74762306a36Sopenharmony_ci char *clk_name; 74862306a36Sopenharmony_ci unsigned int sz; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci wiz_phy_en_refclk = devm_kzalloc(dev, sizeof(*wiz_phy_en_refclk), GFP_KERNEL); 75162306a36Sopenharmony_ci if (!wiz_phy_en_refclk) 75262306a36Sopenharmony_ci return -ENOMEM; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci init = &wiz_phy_en_refclk->clk_data; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci init->ops = &wiz_phy_en_refclk_ops; 75762306a36Sopenharmony_ci init->flags = 0; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci sz = strlen(dev_name(dev)) + strlen(output_clk_names[TI_WIZ_PHY_EN_REFCLK]) + 2; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci clk_name = kzalloc(sz, GFP_KERNEL); 76262306a36Sopenharmony_ci if (!clk_name) 76362306a36Sopenharmony_ci return -ENOMEM; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci snprintf(clk_name, sz, "%s_%s", dev_name(dev), output_clk_names[TI_WIZ_PHY_EN_REFCLK]); 76662306a36Sopenharmony_ci init->name = clk_name; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci wiz_phy_en_refclk->phy_en_refclk = wiz->phy_en_refclk; 76962306a36Sopenharmony_ci wiz_phy_en_refclk->hw.init = init; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci clk = devm_clk_register(dev, &wiz_phy_en_refclk->hw); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci kfree(clk_name); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (IS_ERR(clk)) 77662306a36Sopenharmony_ci return PTR_ERR(clk); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci wiz->output_clks[TI_WIZ_PHY_EN_REFCLK] = clk; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return 0; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic u8 wiz_clk_mux_get_parent(struct clk_hw *hw) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct wiz_clk_mux *mux = to_wiz_clk_mux(hw); 78662306a36Sopenharmony_ci struct regmap_field *field = mux->field; 78762306a36Sopenharmony_ci unsigned int val; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci regmap_field_read(field, &val); 79062306a36Sopenharmony_ci return clk_mux_val_to_index(hw, (u32 *)mux->table, 0, val); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic int wiz_clk_mux_set_parent(struct clk_hw *hw, u8 index) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct wiz_clk_mux *mux = to_wiz_clk_mux(hw); 79662306a36Sopenharmony_ci struct regmap_field *field = mux->field; 79762306a36Sopenharmony_ci int val; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci val = mux->table[index]; 80062306a36Sopenharmony_ci return regmap_field_write(field, val); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic const struct clk_ops wiz_clk_mux_ops = { 80462306a36Sopenharmony_ci .determine_rate = __clk_mux_determine_rate, 80562306a36Sopenharmony_ci .set_parent = wiz_clk_mux_set_parent, 80662306a36Sopenharmony_ci .get_parent = wiz_clk_mux_get_parent, 80762306a36Sopenharmony_ci}; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic int wiz_mux_clk_register(struct wiz *wiz, struct regmap_field *field, 81062306a36Sopenharmony_ci const struct wiz_clk_mux_sel *mux_sel, int clk_index) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct device *dev = wiz->dev; 81362306a36Sopenharmony_ci struct clk_init_data *init; 81462306a36Sopenharmony_ci const char **parent_names; 81562306a36Sopenharmony_ci unsigned int num_parents; 81662306a36Sopenharmony_ci struct wiz_clk_mux *mux; 81762306a36Sopenharmony_ci char clk_name[100]; 81862306a36Sopenharmony_ci struct clk *clk; 81962306a36Sopenharmony_ci int ret = 0, i; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); 82262306a36Sopenharmony_ci if (!mux) 82362306a36Sopenharmony_ci return -ENOMEM; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci num_parents = mux_sel->num_parents; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); 82862306a36Sopenharmony_ci if (!parent_names) 82962306a36Sopenharmony_ci return -ENOMEM; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci for (i = 0; i < num_parents; i++) { 83262306a36Sopenharmony_ci clk = wiz->input_clks[mux_sel->parents[i]]; 83362306a36Sopenharmony_ci if (IS_ERR_OR_NULL(clk)) { 83462306a36Sopenharmony_ci dev_err(dev, "Failed to get parent clk for %s\n", 83562306a36Sopenharmony_ci output_clk_names[clk_index]); 83662306a36Sopenharmony_ci ret = -EINVAL; 83762306a36Sopenharmony_ci goto err; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci parent_names[i] = __clk_get_name(clk); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), output_clk_names[clk_index]); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci init = &mux->clk_data; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci init->ops = &wiz_clk_mux_ops; 84762306a36Sopenharmony_ci init->flags = CLK_SET_RATE_NO_REPARENT; 84862306a36Sopenharmony_ci init->parent_names = parent_names; 84962306a36Sopenharmony_ci init->num_parents = num_parents; 85062306a36Sopenharmony_ci init->name = clk_name; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci mux->field = field; 85362306a36Sopenharmony_ci mux->table = mux_sel->table; 85462306a36Sopenharmony_ci mux->hw.init = init; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci clk = devm_clk_register(dev, &mux->hw); 85762306a36Sopenharmony_ci if (IS_ERR(clk)) { 85862306a36Sopenharmony_ci ret = PTR_ERR(clk); 85962306a36Sopenharmony_ci goto err; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci wiz->output_clks[clk_index] = clk; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cierr: 86562306a36Sopenharmony_ci kfree(parent_names); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return ret; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic int wiz_mux_of_clk_register(struct wiz *wiz, struct device_node *node, 87162306a36Sopenharmony_ci struct regmap_field *field, const u32 *table) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct device *dev = wiz->dev; 87462306a36Sopenharmony_ci struct clk_init_data *init; 87562306a36Sopenharmony_ci const char **parent_names; 87662306a36Sopenharmony_ci unsigned int num_parents; 87762306a36Sopenharmony_ci struct wiz_clk_mux *mux; 87862306a36Sopenharmony_ci char clk_name[100]; 87962306a36Sopenharmony_ci struct clk *clk; 88062306a36Sopenharmony_ci int ret; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); 88362306a36Sopenharmony_ci if (!mux) 88462306a36Sopenharmony_ci return -ENOMEM; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci num_parents = of_clk_get_parent_count(node); 88762306a36Sopenharmony_ci if (num_parents < 2) { 88862306a36Sopenharmony_ci dev_err(dev, "SERDES clock must have parents\n"); 88962306a36Sopenharmony_ci return -EINVAL; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), 89362306a36Sopenharmony_ci GFP_KERNEL); 89462306a36Sopenharmony_ci if (!parent_names) 89562306a36Sopenharmony_ci return -ENOMEM; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci of_clk_parent_fill(node, parent_names, num_parents); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), 90062306a36Sopenharmony_ci node->name); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci init = &mux->clk_data; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci init->ops = &wiz_clk_mux_ops; 90562306a36Sopenharmony_ci init->flags = CLK_SET_RATE_NO_REPARENT; 90662306a36Sopenharmony_ci init->parent_names = parent_names; 90762306a36Sopenharmony_ci init->num_parents = num_parents; 90862306a36Sopenharmony_ci init->name = clk_name; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci mux->field = field; 91162306a36Sopenharmony_ci mux->table = table; 91262306a36Sopenharmony_ci mux->hw.init = init; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci clk = devm_clk_register(dev, &mux->hw); 91562306a36Sopenharmony_ci if (IS_ERR(clk)) 91662306a36Sopenharmony_ci return PTR_ERR(clk); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); 91962306a36Sopenharmony_ci if (ret) 92062306a36Sopenharmony_ci dev_err(dev, "Failed to add clock provider: %s\n", clk_name); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci return ret; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic unsigned long wiz_clk_div_recalc_rate(struct clk_hw *hw, 92662306a36Sopenharmony_ci unsigned long parent_rate) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci struct wiz_clk_divider *div = to_wiz_clk_div(hw); 92962306a36Sopenharmony_ci struct regmap_field *field = div->field; 93062306a36Sopenharmony_ci int val; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci regmap_field_read(field, &val); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return divider_recalc_rate(hw, parent_rate, val, div->table, 0x0, 2); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic long wiz_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, 93862306a36Sopenharmony_ci unsigned long *prate) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci struct wiz_clk_divider *div = to_wiz_clk_div(hw); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci return divider_round_rate(hw, rate, prate, div->table, 2, 0x0); 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic int wiz_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, 94662306a36Sopenharmony_ci unsigned long parent_rate) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci struct wiz_clk_divider *div = to_wiz_clk_div(hw); 94962306a36Sopenharmony_ci struct regmap_field *field = div->field; 95062306a36Sopenharmony_ci int val; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci val = divider_get_val(rate, parent_rate, div->table, 2, 0x0); 95362306a36Sopenharmony_ci if (val < 0) 95462306a36Sopenharmony_ci return val; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return regmap_field_write(field, val); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic const struct clk_ops wiz_clk_div_ops = { 96062306a36Sopenharmony_ci .recalc_rate = wiz_clk_div_recalc_rate, 96162306a36Sopenharmony_ci .round_rate = wiz_clk_div_round_rate, 96262306a36Sopenharmony_ci .set_rate = wiz_clk_div_set_rate, 96362306a36Sopenharmony_ci}; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic int wiz_div_clk_register(struct wiz *wiz, struct device_node *node, 96662306a36Sopenharmony_ci struct regmap_field *field, 96762306a36Sopenharmony_ci const struct clk_div_table *table) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci struct device *dev = wiz->dev; 97062306a36Sopenharmony_ci struct wiz_clk_divider *div; 97162306a36Sopenharmony_ci struct clk_init_data *init; 97262306a36Sopenharmony_ci const char **parent_names; 97362306a36Sopenharmony_ci char clk_name[100]; 97462306a36Sopenharmony_ci struct clk *clk; 97562306a36Sopenharmony_ci int ret; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); 97862306a36Sopenharmony_ci if (!div) 97962306a36Sopenharmony_ci return -ENOMEM; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), 98262306a36Sopenharmony_ci node->name); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci parent_names = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); 98562306a36Sopenharmony_ci if (!parent_names) 98662306a36Sopenharmony_ci return -ENOMEM; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci of_clk_parent_fill(node, parent_names, 1); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci init = &div->clk_data; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci init->ops = &wiz_clk_div_ops; 99362306a36Sopenharmony_ci init->flags = 0; 99462306a36Sopenharmony_ci init->parent_names = parent_names; 99562306a36Sopenharmony_ci init->num_parents = 1; 99662306a36Sopenharmony_ci init->name = clk_name; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci div->field = field; 99962306a36Sopenharmony_ci div->table = table; 100062306a36Sopenharmony_ci div->hw.init = init; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci clk = devm_clk_register(dev, &div->hw); 100362306a36Sopenharmony_ci if (IS_ERR(clk)) 100462306a36Sopenharmony_ci return PTR_ERR(clk); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); 100762306a36Sopenharmony_ci if (ret) 100862306a36Sopenharmony_ci dev_err(dev, "Failed to add clock provider: %s\n", clk_name); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return ret; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; 101662306a36Sopenharmony_ci struct device *dev = wiz->dev; 101762306a36Sopenharmony_ci struct device_node *clk_node; 101862306a36Sopenharmony_ci int i; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci switch (wiz->type) { 102162306a36Sopenharmony_ci case AM64_WIZ_10G: 102262306a36Sopenharmony_ci case J7200_WIZ_10G: 102362306a36Sopenharmony_ci case J784S4_WIZ_10G: 102462306a36Sopenharmony_ci case J721S2_WIZ_10G: 102562306a36Sopenharmony_ci of_clk_del_provider(dev->of_node); 102662306a36Sopenharmony_ci return; 102762306a36Sopenharmony_ci default: 102862306a36Sopenharmony_ci break; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { 103262306a36Sopenharmony_ci clk_node = of_get_child_by_name(node, clk_mux_sel[i].node_name); 103362306a36Sopenharmony_ci of_clk_del_provider(clk_node); 103462306a36Sopenharmony_ci of_node_put(clk_node); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci for (i = 0; i < wiz->clk_div_sel_num; i++) { 103862306a36Sopenharmony_ci clk_node = of_get_child_by_name(node, clk_div_sel[i].node_name); 103962306a36Sopenharmony_ci of_clk_del_provider(clk_node); 104062306a36Sopenharmony_ci of_node_put(clk_node); 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci of_clk_del_provider(wiz->dev->of_node); 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic int wiz_clock_register(struct wiz *wiz) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; 104962306a36Sopenharmony_ci struct device *dev = wiz->dev; 105062306a36Sopenharmony_ci struct device_node *node = dev->of_node; 105162306a36Sopenharmony_ci int clk_index; 105262306a36Sopenharmony_ci int ret; 105362306a36Sopenharmony_ci int i; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci clk_index = TI_WIZ_PLL0_REFCLK; 105662306a36Sopenharmony_ci for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++, clk_index++) { 105762306a36Sopenharmony_ci ret = wiz_mux_clk_register(wiz, wiz->mux_sel_field[i], &clk_mux_sel[i], clk_index); 105862306a36Sopenharmony_ci if (ret) { 105962306a36Sopenharmony_ci dev_err(dev, "Failed to register clk: %s\n", output_clk_names[clk_index]); 106062306a36Sopenharmony_ci return ret; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci ret = wiz_phy_en_refclk_register(wiz); 106562306a36Sopenharmony_ci if (ret) { 106662306a36Sopenharmony_ci dev_err(dev, "Failed to add phy-en-refclk\n"); 106762306a36Sopenharmony_ci return ret; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci wiz->clk_data.clks = wiz->output_clks; 107162306a36Sopenharmony_ci wiz->clk_data.clk_num = WIZ_MAX_OUTPUT_CLOCKS; 107262306a36Sopenharmony_ci ret = of_clk_add_provider(node, of_clk_src_onecell_get, &wiz->clk_data); 107362306a36Sopenharmony_ci if (ret) 107462306a36Sopenharmony_ci dev_err(dev, "Failed to add clock provider: %s\n", node->name); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return ret; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic int wiz_clock_init(struct wiz *wiz, struct device_node *node) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; 108262306a36Sopenharmony_ci struct device *dev = wiz->dev; 108362306a36Sopenharmony_ci struct device_node *clk_node; 108462306a36Sopenharmony_ci const char *node_name; 108562306a36Sopenharmony_ci unsigned long rate; 108662306a36Sopenharmony_ci struct clk *clk; 108762306a36Sopenharmony_ci int ret; 108862306a36Sopenharmony_ci int i; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci clk = devm_clk_get(dev, "core_ref_clk"); 109162306a36Sopenharmony_ci if (IS_ERR(clk)) { 109262306a36Sopenharmony_ci dev_err(dev, "core_ref_clk clock not found\n"); 109362306a36Sopenharmony_ci ret = PTR_ERR(clk); 109462306a36Sopenharmony_ci return ret; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci wiz->input_clks[WIZ_CORE_REFCLK] = clk; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci rate = clk_get_rate(clk); 109962306a36Sopenharmony_ci if (rate >= 100000000) 110062306a36Sopenharmony_ci regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x1); 110162306a36Sopenharmony_ci else 110262306a36Sopenharmony_ci regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x3); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci switch (wiz->type) { 110562306a36Sopenharmony_ci case AM64_WIZ_10G: 110662306a36Sopenharmony_ci case J7200_WIZ_10G: 110762306a36Sopenharmony_ci switch (rate) { 110862306a36Sopenharmony_ci case REF_CLK_100MHZ: 110962306a36Sopenharmony_ci regmap_field_write(wiz->div_sel_field[CMN_REFCLK_DIG_DIV], 0x2); 111062306a36Sopenharmony_ci break; 111162306a36Sopenharmony_ci case REF_CLK_156_25MHZ: 111262306a36Sopenharmony_ci regmap_field_write(wiz->div_sel_field[CMN_REFCLK_DIG_DIV], 0x3); 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci default: 111562306a36Sopenharmony_ci regmap_field_write(wiz->div_sel_field[CMN_REFCLK_DIG_DIV], 0); 111662306a36Sopenharmony_ci break; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci break; 111962306a36Sopenharmony_ci default: 112062306a36Sopenharmony_ci break; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci if (wiz->data->pma_cmn_refclk1_int_mode) { 112462306a36Sopenharmony_ci clk = devm_clk_get(dev, "core_ref1_clk"); 112562306a36Sopenharmony_ci if (IS_ERR(clk)) { 112662306a36Sopenharmony_ci dev_err(dev, "core_ref1_clk clock not found\n"); 112762306a36Sopenharmony_ci ret = PTR_ERR(clk); 112862306a36Sopenharmony_ci return ret; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci wiz->input_clks[WIZ_CORE_REFCLK1] = clk; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci rate = clk_get_rate(clk); 113362306a36Sopenharmony_ci if (rate >= 100000000) 113462306a36Sopenharmony_ci regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x1); 113562306a36Sopenharmony_ci else 113662306a36Sopenharmony_ci regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x3); 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci clk = devm_clk_get(dev, "ext_ref_clk"); 114062306a36Sopenharmony_ci if (IS_ERR(clk)) { 114162306a36Sopenharmony_ci dev_err(dev, "ext_ref_clk clock not found\n"); 114262306a36Sopenharmony_ci ret = PTR_ERR(clk); 114362306a36Sopenharmony_ci return ret; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci wiz->input_clks[WIZ_EXT_REFCLK] = clk; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci rate = clk_get_rate(clk); 114862306a36Sopenharmony_ci if (rate >= 100000000) 114962306a36Sopenharmony_ci regmap_field_write(wiz->pma_cmn_refclk_mode, 0x0); 115062306a36Sopenharmony_ci else 115162306a36Sopenharmony_ci regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci switch (wiz->type) { 115462306a36Sopenharmony_ci case AM64_WIZ_10G: 115562306a36Sopenharmony_ci case J7200_WIZ_10G: 115662306a36Sopenharmony_ci case J784S4_WIZ_10G: 115762306a36Sopenharmony_ci case J721S2_WIZ_10G: 115862306a36Sopenharmony_ci ret = wiz_clock_register(wiz); 115962306a36Sopenharmony_ci if (ret) 116062306a36Sopenharmony_ci dev_err(dev, "Failed to register wiz clocks\n"); 116162306a36Sopenharmony_ci return ret; 116262306a36Sopenharmony_ci default: 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { 116762306a36Sopenharmony_ci node_name = clk_mux_sel[i].node_name; 116862306a36Sopenharmony_ci clk_node = of_get_child_by_name(node, node_name); 116962306a36Sopenharmony_ci if (!clk_node) { 117062306a36Sopenharmony_ci dev_err(dev, "Unable to get %s node\n", node_name); 117162306a36Sopenharmony_ci ret = -EINVAL; 117262306a36Sopenharmony_ci goto err; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i], 117662306a36Sopenharmony_ci clk_mux_sel[i].table); 117762306a36Sopenharmony_ci if (ret) { 117862306a36Sopenharmony_ci dev_err(dev, "Failed to register %s clock\n", 117962306a36Sopenharmony_ci node_name); 118062306a36Sopenharmony_ci of_node_put(clk_node); 118162306a36Sopenharmony_ci goto err; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci of_node_put(clk_node); 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci for (i = 0; i < wiz->clk_div_sel_num; i++) { 118862306a36Sopenharmony_ci node_name = clk_div_sel[i].node_name; 118962306a36Sopenharmony_ci clk_node = of_get_child_by_name(node, node_name); 119062306a36Sopenharmony_ci if (!clk_node) { 119162306a36Sopenharmony_ci dev_err(dev, "Unable to get %s node\n", node_name); 119262306a36Sopenharmony_ci ret = -EINVAL; 119362306a36Sopenharmony_ci goto err; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci ret = wiz_div_clk_register(wiz, clk_node, wiz->div_sel_field[i], 119762306a36Sopenharmony_ci clk_div_sel[i].table); 119862306a36Sopenharmony_ci if (ret) { 119962306a36Sopenharmony_ci dev_err(dev, "Failed to register %s clock\n", 120062306a36Sopenharmony_ci node_name); 120162306a36Sopenharmony_ci of_node_put(clk_node); 120262306a36Sopenharmony_ci goto err; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci of_node_put(clk_node); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return 0; 120962306a36Sopenharmony_cierr: 121062306a36Sopenharmony_ci wiz_clock_cleanup(wiz, node); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci return ret; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic int wiz_phy_reset_assert(struct reset_controller_dev *rcdev, 121662306a36Sopenharmony_ci unsigned long id) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct device *dev = rcdev->dev; 121962306a36Sopenharmony_ci struct wiz *wiz = dev_get_drvdata(dev); 122062306a36Sopenharmony_ci int ret = 0; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (id == 0) { 122362306a36Sopenharmony_ci ret = regmap_field_write(wiz->phy_reset_n, false); 122462306a36Sopenharmony_ci return ret; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE_DISABLE); 122862306a36Sopenharmony_ci return ret; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int wiz_phy_fullrt_div(struct wiz *wiz, int lane) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci switch (wiz->type) { 123462306a36Sopenharmony_ci case AM64_WIZ_10G: 123562306a36Sopenharmony_ci if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE) 123662306a36Sopenharmony_ci return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1); 123762306a36Sopenharmony_ci break; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci case J721E_WIZ_16G: 124062306a36Sopenharmony_ci case J721E_WIZ_10G: 124162306a36Sopenharmony_ci case J7200_WIZ_10G: 124262306a36Sopenharmony_ci case J721S2_WIZ_10G: 124362306a36Sopenharmony_ci if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII) 124462306a36Sopenharmony_ci return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2); 124562306a36Sopenharmony_ci break; 124662306a36Sopenharmony_ci default: 124762306a36Sopenharmony_ci return 0; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev, 125362306a36Sopenharmony_ci unsigned long id) 125462306a36Sopenharmony_ci{ 125562306a36Sopenharmony_ci struct device *dev = rcdev->dev; 125662306a36Sopenharmony_ci struct wiz *wiz = dev_get_drvdata(dev); 125762306a36Sopenharmony_ci int ret; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (id == 0) { 126062306a36Sopenharmony_ci /* if typec-dir gpio was specified, set LN10 SWAP bit based on that */ 126162306a36Sopenharmony_ci if (wiz->gpio_typec_dir) { 126262306a36Sopenharmony_ci if (wiz->typec_dir_delay) 126362306a36Sopenharmony_ci msleep_interruptible(wiz->typec_dir_delay); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (gpiod_get_value_cansleep(wiz->gpio_typec_dir)) 126662306a36Sopenharmony_ci regmap_field_write(wiz->typec_ln10_swap, 1); 126762306a36Sopenharmony_ci else 126862306a36Sopenharmony_ci regmap_field_write(wiz->typec_ln10_swap, 0); 126962306a36Sopenharmony_ci } else { 127062306a36Sopenharmony_ci /* if no typec-dir gpio is specified and PHY type is USB3 127162306a36Sopenharmony_ci * with master lane number is '0' or '2', then set LN10 or 127262306a36Sopenharmony_ci * LN23 SWAP bit to '1' respectively. 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_ci u32 num_lanes = wiz->num_lanes; 127562306a36Sopenharmony_ci int i; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci for (i = 0; i < num_lanes; i++) { 127862306a36Sopenharmony_ci if (wiz->lane_phy_type[i] == PHY_TYPE_USB3) { 127962306a36Sopenharmony_ci switch (wiz->master_lane_num[i]) { 128062306a36Sopenharmony_ci case LANE0: 128162306a36Sopenharmony_ci regmap_field_write(wiz->typec_ln10_swap, 1); 128262306a36Sopenharmony_ci break; 128362306a36Sopenharmony_ci case LANE2: 128462306a36Sopenharmony_ci regmap_field_write(wiz->typec_ln23_swap, 1); 128562306a36Sopenharmony_ci break; 128662306a36Sopenharmony_ci default: 128762306a36Sopenharmony_ci break; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (id == 0) { 129562306a36Sopenharmony_ci ret = regmap_field_write(wiz->phy_reset_n, true); 129662306a36Sopenharmony_ci return ret; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci ret = wiz_phy_fullrt_div(wiz, id - 1); 130062306a36Sopenharmony_ci if (ret) 130162306a36Sopenharmony_ci return ret; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (wiz->lane_phy_type[id - 1] == PHY_TYPE_DP) 130462306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE); 130562306a36Sopenharmony_ci else 130662306a36Sopenharmony_ci ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE_FORCE); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return ret; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic const struct reset_control_ops wiz_phy_reset_ops = { 131262306a36Sopenharmony_ci .assert = wiz_phy_reset_assert, 131362306a36Sopenharmony_ci .deassert = wiz_phy_reset_deassert, 131462306a36Sopenharmony_ci}; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic const struct regmap_config wiz_regmap_config = { 131762306a36Sopenharmony_ci .reg_bits = 32, 131862306a36Sopenharmony_ci .val_bits = 32, 131962306a36Sopenharmony_ci .reg_stride = 4, 132062306a36Sopenharmony_ci .fast_io = true, 132162306a36Sopenharmony_ci}; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic struct wiz_data j721e_16g_data = { 132462306a36Sopenharmony_ci .type = J721E_WIZ_16G, 132562306a36Sopenharmony_ci .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, 132662306a36Sopenharmony_ci .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, 132762306a36Sopenharmony_ci .refclk_dig_sel = &refclk_dig_sel_16g, 132862306a36Sopenharmony_ci .pma_cmn_refclk1_dig_div = &pma_cmn_refclk1_dig_div, 132962306a36Sopenharmony_ci .clk_mux_sel = clk_mux_sel_16g, 133062306a36Sopenharmony_ci .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_16G, 133162306a36Sopenharmony_ci}; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic struct wiz_data j721e_10g_data = { 133462306a36Sopenharmony_ci .type = J721E_WIZ_10G, 133562306a36Sopenharmony_ci .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, 133662306a36Sopenharmony_ci .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, 133762306a36Sopenharmony_ci .refclk_dig_sel = &refclk_dig_sel_10g, 133862306a36Sopenharmony_ci .clk_mux_sel = clk_mux_sel_10g, 133962306a36Sopenharmony_ci .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, 134062306a36Sopenharmony_ci}; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic struct wiz_data am64_10g_data = { 134362306a36Sopenharmony_ci .type = AM64_WIZ_10G, 134462306a36Sopenharmony_ci .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, 134562306a36Sopenharmony_ci .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, 134662306a36Sopenharmony_ci .refclk_dig_sel = &refclk_dig_sel_10g, 134762306a36Sopenharmony_ci .clk_mux_sel = clk_mux_sel_10g, 134862306a36Sopenharmony_ci .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, 134962306a36Sopenharmony_ci}; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic struct wiz_data j7200_pg2_10g_data = { 135262306a36Sopenharmony_ci .type = J7200_WIZ_10G, 135362306a36Sopenharmony_ci .pll0_refclk_mux_sel = &sup_pll0_refclk_mux_sel, 135462306a36Sopenharmony_ci .pll1_refclk_mux_sel = &sup_pll1_refclk_mux_sel, 135562306a36Sopenharmony_ci .refclk_dig_sel = &sup_refclk_dig_sel_10g, 135662306a36Sopenharmony_ci .pma_cmn_refclk1_int_mode = &sup_pma_cmn_refclk1_int_mode, 135762306a36Sopenharmony_ci .clk_mux_sel = clk_mux_sel_10g_2_refclk, 135862306a36Sopenharmony_ci .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, 135962306a36Sopenharmony_ci}; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic struct wiz_data j784s4_10g_data = { 136262306a36Sopenharmony_ci .type = J784S4_WIZ_10G, 136362306a36Sopenharmony_ci .pll0_refclk_mux_sel = &pll0_refclk_mux_sel_2, 136462306a36Sopenharmony_ci .pll1_refclk_mux_sel = &pll1_refclk_mux_sel_2, 136562306a36Sopenharmony_ci .refclk_dig_sel = &refclk_dig_sel_16g, 136662306a36Sopenharmony_ci .pma_cmn_refclk1_int_mode = &pma_cmn_refclk1_int_mode, 136762306a36Sopenharmony_ci .clk_mux_sel = clk_mux_sel_10g_2_refclk, 136862306a36Sopenharmony_ci .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, 136962306a36Sopenharmony_ci}; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic struct wiz_data j721s2_10g_data = { 137262306a36Sopenharmony_ci .type = J721S2_WIZ_10G, 137362306a36Sopenharmony_ci .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, 137462306a36Sopenharmony_ci .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, 137562306a36Sopenharmony_ci .refclk_dig_sel = &refclk_dig_sel_10g, 137662306a36Sopenharmony_ci .clk_mux_sel = clk_mux_sel_10g, 137762306a36Sopenharmony_ci .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, 137862306a36Sopenharmony_ci}; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_cistatic const struct of_device_id wiz_id_table[] = { 138162306a36Sopenharmony_ci { 138262306a36Sopenharmony_ci .compatible = "ti,j721e-wiz-16g", .data = &j721e_16g_data, 138362306a36Sopenharmony_ci }, 138462306a36Sopenharmony_ci { 138562306a36Sopenharmony_ci .compatible = "ti,j721e-wiz-10g", .data = &j721e_10g_data, 138662306a36Sopenharmony_ci }, 138762306a36Sopenharmony_ci { 138862306a36Sopenharmony_ci .compatible = "ti,am64-wiz-10g", .data = &am64_10g_data, 138962306a36Sopenharmony_ci }, 139062306a36Sopenharmony_ci { 139162306a36Sopenharmony_ci .compatible = "ti,j7200-wiz-10g", .data = &j7200_pg2_10g_data, 139262306a36Sopenharmony_ci }, 139362306a36Sopenharmony_ci { 139462306a36Sopenharmony_ci .compatible = "ti,j784s4-wiz-10g", .data = &j784s4_10g_data, 139562306a36Sopenharmony_ci }, 139662306a36Sopenharmony_ci { 139762306a36Sopenharmony_ci .compatible = "ti,j721s2-wiz-10g", .data = &j721s2_10g_data, 139862306a36Sopenharmony_ci }, 139962306a36Sopenharmony_ci {} 140062306a36Sopenharmony_ci}; 140162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, wiz_id_table); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cistatic int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci struct device_node *serdes, *subnode; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci serdes = of_get_child_by_name(dev->of_node, "serdes"); 140862306a36Sopenharmony_ci if (!serdes) { 140962306a36Sopenharmony_ci dev_err(dev, "%s: Getting \"serdes\"-node failed\n", __func__); 141062306a36Sopenharmony_ci return -EINVAL; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci for_each_child_of_node(serdes, subnode) { 141462306a36Sopenharmony_ci u32 reg, num_lanes = 1, phy_type = PHY_NONE; 141562306a36Sopenharmony_ci int ret, i; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci if (!(of_node_name_eq(subnode, "phy") || 141862306a36Sopenharmony_ci of_node_name_eq(subnode, "link"))) 141962306a36Sopenharmony_ci continue; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci ret = of_property_read_u32(subnode, "reg", ®); 142262306a36Sopenharmony_ci if (ret) { 142362306a36Sopenharmony_ci of_node_put(subnode); 142462306a36Sopenharmony_ci dev_err(dev, 142562306a36Sopenharmony_ci "%s: Reading \"reg\" from \"%s\" failed: %d\n", 142662306a36Sopenharmony_ci __func__, subnode->name, ret); 142762306a36Sopenharmony_ci return ret; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes); 143062306a36Sopenharmony_ci of_property_read_u32(subnode, "cdns,phy-type", &phy_type); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci dev_dbg(dev, "%s: Lanes %u-%u have phy-type %u\n", __func__, 143362306a36Sopenharmony_ci reg, reg + num_lanes - 1, phy_type); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci for (i = reg; i < reg + num_lanes; i++) { 143662306a36Sopenharmony_ci wiz->master_lane_num[i] = reg; 143762306a36Sopenharmony_ci wiz->lane_phy_type[i] = phy_type; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci return 0; 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic int wiz_probe(struct platform_device *pdev) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci struct reset_controller_dev *phy_reset_dev; 144762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 144862306a36Sopenharmony_ci struct device_node *node = dev->of_node; 144962306a36Sopenharmony_ci struct platform_device *serdes_pdev; 145062306a36Sopenharmony_ci bool already_configured = false; 145162306a36Sopenharmony_ci struct device_node *child_node; 145262306a36Sopenharmony_ci struct regmap *regmap; 145362306a36Sopenharmony_ci struct resource res; 145462306a36Sopenharmony_ci void __iomem *base; 145562306a36Sopenharmony_ci struct wiz *wiz; 145662306a36Sopenharmony_ci int ret, val, i; 145762306a36Sopenharmony_ci u32 num_lanes; 145862306a36Sopenharmony_ci const struct wiz_data *data; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci wiz = devm_kzalloc(dev, sizeof(*wiz), GFP_KERNEL); 146162306a36Sopenharmony_ci if (!wiz) 146262306a36Sopenharmony_ci return -ENOMEM; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci data = of_device_get_match_data(dev); 146562306a36Sopenharmony_ci if (!data) { 146662306a36Sopenharmony_ci dev_err(dev, "NULL device data\n"); 146762306a36Sopenharmony_ci return -EINVAL; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci wiz->data = data; 147162306a36Sopenharmony_ci wiz->type = data->type; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci child_node = of_get_child_by_name(node, "serdes"); 147462306a36Sopenharmony_ci if (!child_node) { 147562306a36Sopenharmony_ci dev_err(dev, "Failed to get SERDES child DT node\n"); 147662306a36Sopenharmony_ci return -ENODEV; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci ret = of_address_to_resource(child_node, 0, &res); 148062306a36Sopenharmony_ci if (ret) { 148162306a36Sopenharmony_ci dev_err(dev, "Failed to get memory resource\n"); 148262306a36Sopenharmony_ci goto err_addr_to_resource; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci base = devm_ioremap(dev, res.start, resource_size(&res)); 148662306a36Sopenharmony_ci if (!base) { 148762306a36Sopenharmony_ci ret = -ENOMEM; 148862306a36Sopenharmony_ci goto err_addr_to_resource; 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci regmap = devm_regmap_init_mmio(dev, base, &wiz_regmap_config); 149262306a36Sopenharmony_ci if (IS_ERR(regmap)) { 149362306a36Sopenharmony_ci dev_err(dev, "Failed to initialize regmap\n"); 149462306a36Sopenharmony_ci ret = PTR_ERR(regmap); 149562306a36Sopenharmony_ci goto err_addr_to_resource; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci wiz->scm_regmap = syscon_regmap_lookup_by_phandle(node, "ti,scm"); 149962306a36Sopenharmony_ci if (IS_ERR(wiz->scm_regmap)) { 150062306a36Sopenharmony_ci if (wiz->type == J7200_WIZ_10G) { 150162306a36Sopenharmony_ci dev_err(dev, "Couldn't get ti,scm regmap\n"); 150262306a36Sopenharmony_ci ret = -ENODEV; 150362306a36Sopenharmony_ci goto err_addr_to_resource; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci wiz->scm_regmap = NULL; 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci ret = of_property_read_u32(node, "num-lanes", &num_lanes); 151062306a36Sopenharmony_ci if (ret) { 151162306a36Sopenharmony_ci dev_err(dev, "Failed to read num-lanes property\n"); 151262306a36Sopenharmony_ci goto err_addr_to_resource; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci if (num_lanes > WIZ_MAX_LANES) { 151662306a36Sopenharmony_ci dev_err(dev, "Cannot support %d lanes\n", num_lanes); 151762306a36Sopenharmony_ci ret = -ENODEV; 151862306a36Sopenharmony_ci goto err_addr_to_resource; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci wiz->gpio_typec_dir = devm_gpiod_get_optional(dev, "typec-dir", 152262306a36Sopenharmony_ci GPIOD_IN); 152362306a36Sopenharmony_ci if (IS_ERR(wiz->gpio_typec_dir)) { 152462306a36Sopenharmony_ci ret = PTR_ERR(wiz->gpio_typec_dir); 152562306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) 152662306a36Sopenharmony_ci dev_err(dev, "Failed to request typec-dir gpio: %d\n", 152762306a36Sopenharmony_ci ret); 152862306a36Sopenharmony_ci goto err_addr_to_resource; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (wiz->gpio_typec_dir) { 153262306a36Sopenharmony_ci ret = of_property_read_u32(node, "typec-dir-debounce-ms", 153362306a36Sopenharmony_ci &wiz->typec_dir_delay); 153462306a36Sopenharmony_ci if (ret && ret != -EINVAL) { 153562306a36Sopenharmony_ci dev_err(dev, "Invalid typec-dir-debounce property\n"); 153662306a36Sopenharmony_ci goto err_addr_to_resource; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* use min. debounce from Type-C spec if not provided in DT */ 154062306a36Sopenharmony_ci if (ret == -EINVAL) 154162306a36Sopenharmony_ci wiz->typec_dir_delay = WIZ_TYPEC_DIR_DEBOUNCE_MIN; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (wiz->typec_dir_delay < WIZ_TYPEC_DIR_DEBOUNCE_MIN || 154462306a36Sopenharmony_ci wiz->typec_dir_delay > WIZ_TYPEC_DIR_DEBOUNCE_MAX) { 154562306a36Sopenharmony_ci ret = -EINVAL; 154662306a36Sopenharmony_ci dev_err(dev, "Invalid typec-dir-debounce property\n"); 154762306a36Sopenharmony_ci goto err_addr_to_resource; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci ret = wiz_get_lane_phy_types(dev, wiz); 155262306a36Sopenharmony_ci if (ret) 155362306a36Sopenharmony_ci goto err_addr_to_resource; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci wiz->dev = dev; 155662306a36Sopenharmony_ci wiz->regmap = regmap; 155762306a36Sopenharmony_ci wiz->num_lanes = num_lanes; 155862306a36Sopenharmony_ci wiz->clk_mux_sel = data->clk_mux_sel; 155962306a36Sopenharmony_ci wiz->clk_div_sel = clk_div_sel; 156062306a36Sopenharmony_ci wiz->clk_div_sel_num = data->clk_div_sel_num; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci platform_set_drvdata(pdev, wiz); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci ret = wiz_regfield_init(wiz); 156562306a36Sopenharmony_ci if (ret) { 156662306a36Sopenharmony_ci dev_err(dev, "Failed to initialize regfields\n"); 156762306a36Sopenharmony_ci goto err_addr_to_resource; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci /* Enable supplemental Control override if available */ 157162306a36Sopenharmony_ci if (wiz->scm_regmap) 157262306a36Sopenharmony_ci regmap_field_write(wiz->sup_legacy_clk_override, 1); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci phy_reset_dev = &wiz->wiz_phy_reset_dev; 157562306a36Sopenharmony_ci phy_reset_dev->dev = dev; 157662306a36Sopenharmony_ci phy_reset_dev->ops = &wiz_phy_reset_ops, 157762306a36Sopenharmony_ci phy_reset_dev->owner = THIS_MODULE, 157862306a36Sopenharmony_ci phy_reset_dev->of_node = node; 157962306a36Sopenharmony_ci /* Reset for each of the lane and one for the entire SERDES */ 158062306a36Sopenharmony_ci phy_reset_dev->nr_resets = num_lanes + 1; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci ret = devm_reset_controller_register(dev, phy_reset_dev); 158362306a36Sopenharmony_ci if (ret < 0) { 158462306a36Sopenharmony_ci dev_warn(dev, "Failed to register reset controller\n"); 158562306a36Sopenharmony_ci goto err_addr_to_resource; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci pm_runtime_enable(dev); 158962306a36Sopenharmony_ci ret = pm_runtime_get_sync(dev); 159062306a36Sopenharmony_ci if (ret < 0) { 159162306a36Sopenharmony_ci dev_err(dev, "pm_runtime_get_sync failed\n"); 159262306a36Sopenharmony_ci goto err_get_sync; 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci ret = wiz_clock_init(wiz, node); 159662306a36Sopenharmony_ci if (ret < 0) { 159762306a36Sopenharmony_ci dev_warn(dev, "Failed to initialize clocks\n"); 159862306a36Sopenharmony_ci goto err_get_sync; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci for (i = 0; i < wiz->num_lanes; i++) { 160262306a36Sopenharmony_ci regmap_field_read(wiz->p_enable[i], &val); 160362306a36Sopenharmony_ci if (val & (P_ENABLE | P_ENABLE_FORCE)) { 160462306a36Sopenharmony_ci already_configured = true; 160562306a36Sopenharmony_ci break; 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci if (!already_configured) { 161062306a36Sopenharmony_ci ret = wiz_init(wiz); 161162306a36Sopenharmony_ci if (ret) { 161262306a36Sopenharmony_ci dev_err(dev, "WIZ initialization failed\n"); 161362306a36Sopenharmony_ci goto err_wiz_init; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci serdes_pdev = of_platform_device_create(child_node, NULL, dev); 161862306a36Sopenharmony_ci if (!serdes_pdev) { 161962306a36Sopenharmony_ci dev_WARN(dev, "Unable to create SERDES platform device\n"); 162062306a36Sopenharmony_ci ret = -ENOMEM; 162162306a36Sopenharmony_ci goto err_wiz_init; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci wiz->serdes_pdev = serdes_pdev; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci of_node_put(child_node); 162662306a36Sopenharmony_ci return 0; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cierr_wiz_init: 162962306a36Sopenharmony_ci wiz_clock_cleanup(wiz, node); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_cierr_get_sync: 163262306a36Sopenharmony_ci pm_runtime_put(dev); 163362306a36Sopenharmony_ci pm_runtime_disable(dev); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cierr_addr_to_resource: 163662306a36Sopenharmony_ci of_node_put(child_node); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci return ret; 163962306a36Sopenharmony_ci} 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_cistatic void wiz_remove(struct platform_device *pdev) 164262306a36Sopenharmony_ci{ 164362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 164462306a36Sopenharmony_ci struct device_node *node = dev->of_node; 164562306a36Sopenharmony_ci struct platform_device *serdes_pdev; 164662306a36Sopenharmony_ci struct wiz *wiz; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci wiz = dev_get_drvdata(dev); 164962306a36Sopenharmony_ci serdes_pdev = wiz->serdes_pdev; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci of_platform_device_destroy(&serdes_pdev->dev, NULL); 165262306a36Sopenharmony_ci wiz_clock_cleanup(wiz, node); 165362306a36Sopenharmony_ci pm_runtime_put(dev); 165462306a36Sopenharmony_ci pm_runtime_disable(dev); 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_cistatic struct platform_driver wiz_driver = { 165862306a36Sopenharmony_ci .probe = wiz_probe, 165962306a36Sopenharmony_ci .remove_new = wiz_remove, 166062306a36Sopenharmony_ci .driver = { 166162306a36Sopenharmony_ci .name = "wiz", 166262306a36Sopenharmony_ci .of_match_table = wiz_id_table, 166362306a36Sopenharmony_ci }, 166462306a36Sopenharmony_ci}; 166562306a36Sopenharmony_cimodule_platform_driver(wiz_driver); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ciMODULE_AUTHOR("Texas Instruments Inc."); 166862306a36Sopenharmony_ciMODULE_DESCRIPTION("TI J721E WIZ driver"); 166962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1670