struct rk_priv_data;
struct rk_clock_fields {
+ /* io_clksel_cru_mask - io_clksel bit in clock GRF register which,
+ * when set, selects the tx clock from CRU.
+ */
+ u16 io_clksel_cru_mask;
+ /* io_clksel_io_mask - io_clksel bit in clock GRF register which,
+ * when set, selects the tx clock from IO.
+ */
+ u16 io_clksel_io_mask;
u16 gmii_clk_sel_mask;
u16 rmii_clk_sel_mask;
+ u16 rmii_gate_en_mask;
u16 mac_speed_mask;
};
void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
int (*set_speed)(struct rk_priv_data *bsp_priv,
phy_interface_t interface, int speed);
- void (*set_clock_selection)(struct rk_priv_data *bsp_priv, bool input,
- bool enable);
void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
void (*integrated_phy_powerdown)(struct rk_priv_data *bsp_priv);
return regmap_write(regmap, bsp_priv->clock_grf_reg, val);
}
+static int rk_set_rmii_gate_en(struct rk_priv_data *bsp_priv, bool state)
+{
+ u32 val;
+
+ if (!bsp_priv->clock.rmii_gate_en_mask)
+ return 0;
+
+ val = rk_encode_wm16(state, bsp_priv->clock.rmii_gate_en_mask);
+
+ return rk_write_clock_grf_reg(bsp_priv, val);
+}
+
+static int rk_ungate_rmii_clock(struct rk_priv_data *bsp_priv)
+{
+ return rk_set_rmii_gate_en(bsp_priv, false);
+}
+
+static int rk_gate_rmii_clock(struct rk_priv_data *bsp_priv)
+{
+ return rk_set_rmii_gate_en(bsp_priv, true);
+}
+
+static int rk_configure_io_clksel(struct rk_priv_data *bsp_priv)
+{
+ bool io, cru;
+ u32 val;
+
+ if (!bsp_priv->clock.io_clksel_io_mask &&
+ !bsp_priv->clock.io_clksel_cru_mask)
+ return 0;
+
+ io = bsp_priv->clock_input;
+ cru = !io;
+
+ /* The io_clksel configuration can be either:
+ * 0=CRU, 1=IO (rk3506, rk3520, rk3576) or
+ * 0=IO, 1=CRU (rk3588)
+ * where CRU means the transmit clock comes from the CRU and IO
+ * means the transmit clock comes from IO.
+ *
+ * Handle this by having two masks.
+ */
+ val = rk_encode_wm16(io, bsp_priv->clock.io_clksel_io_mask) |
+ rk_encode_wm16(cru, bsp_priv->clock.io_clksel_cru_mask);
+
+ return rk_write_clock_grf_reg(bsp_priv, val);
+}
+
static int rk_set_clk_mac_speed(struct rk_priv_data *bsp_priv,
phy_interface_t interface, int speed)
{
#define RK3506_GMAC_RMII_MODE GRF_BIT(1)
-#define RK3506_GMAC_CLK_SELECT_CRU GRF_CLR_BIT(5)
-#define RK3506_GMAC_CLK_SELECT_IO GRF_BIT(5)
-
-#define RK3506_GMAC_CLK_RMII_GATE GRF_BIT(2)
-#define RK3506_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(2)
-
static int rk3506_init(struct rk_priv_data *bsp_priv)
{
switch (bsp_priv->id) {
regmap_write(bsp_priv->grf, offset, RK3506_GMAC_RMII_MODE);
}
-static void rk3506_set_clock_selection(struct rk_priv_data *bsp_priv,
- bool input, bool enable)
-{
- unsigned int value, offset, id = bsp_priv->id;
-
- offset = (id == 1) ? RK3506_GRF_SOC_CON11 : RK3506_GRF_SOC_CON8;
-
- value = input ? RK3506_GMAC_CLK_SELECT_IO :
- RK3506_GMAC_CLK_SELECT_CRU;
- value |= enable ? RK3506_GMAC_CLK_RMII_NOGATE :
- RK3506_GMAC_CLK_RMII_GATE;
- regmap_write(bsp_priv->grf, offset, value);
-}
-
static const struct rk_gmac_ops rk3506_ops = {
.init = rk3506_init,
.set_to_rmii = rk3506_set_to_rmii,
- .set_clock_selection = rk3506_set_clock_selection,
+ .clock.io_clksel_io_mask = BIT_U16(5),
.clock.rmii_clk_sel_mask = BIT_U16(3),
+ .clock.rmii_gate_en_mask = BIT_U16(2),
.regs_valid = true,
.regs = {
#define RK3528_GMAC1_PHY_INTF_SEL_RGMII GRF_CLR_BIT(8)
#define RK3528_GMAC1_PHY_INTF_SEL_RMII GRF_BIT(8)
-#define RK3528_GMAC1_CLK_SELECT_CRU GRF_CLR_BIT(12)
-#define RK3528_GMAC1_CLK_SELECT_IO GRF_BIT(12)
-
-#define RK3528_GMAC0_CLK_RMII_GATE GRF_BIT(2)
-#define RK3528_GMAC0_CLK_RMII_NOGATE GRF_CLR_BIT(2)
-#define RK3528_GMAC1_CLK_RMII_GATE GRF_BIT(9)
-#define RK3528_GMAC1_CLK_RMII_NOGATE GRF_CLR_BIT(9)
-
static int rk3528_init(struct rk_priv_data *bsp_priv)
{
switch (bsp_priv->id) {
case 0:
bsp_priv->clock_grf_reg = RK3528_VO_GRF_GMAC_CON;
bsp_priv->clock.rmii_clk_sel_mask = BIT_U16(3);
+ bsp_priv->clock.rmii_gate_en_mask = BIT_U16(2);
bsp_priv->supports_rgmii = false;
return 0;
case 1:
bsp_priv->clock_grf_reg = RK3528_VPU_GRF_GMAC_CON5;
+ bsp_priv->clock.io_clksel_io_mask = BIT_U16(12);
bsp_priv->clock.gmii_clk_sel_mask = GENMASK_U16(11, 10);
bsp_priv->clock.rmii_clk_sel_mask = BIT_U16(10);
+ bsp_priv->clock.rmii_gate_en_mask = BIT_U16(9);
return 0;
default:
RK3528_GMAC0_PHY_INTF_SEL_RMII);
}
-static void rk3528_set_clock_selection(struct rk_priv_data *bsp_priv,
- bool input, bool enable)
-{
- unsigned int val;
-
- if (bsp_priv->id == 1) {
- val = input ? RK3528_GMAC1_CLK_SELECT_IO :
- RK3528_GMAC1_CLK_SELECT_CRU;
- val |= enable ? RK3528_GMAC1_CLK_RMII_NOGATE :
- RK3528_GMAC1_CLK_RMII_GATE;
- regmap_write(bsp_priv->grf, RK3528_VPU_GRF_GMAC_CON5, val);
- } else {
- val = enable ? RK3528_GMAC0_CLK_RMII_NOGATE :
- RK3528_GMAC0_CLK_RMII_GATE;
- regmap_write(bsp_priv->grf, RK3528_VO_GRF_GMAC_CON, val);
- }
-}
-
static void rk3528_integrated_phy_powerup(struct rk_priv_data *bsp_priv)
{
rk_gmac_integrated_fephy_powerup(bsp_priv, RK3528_VO_GRF_MACPHY_CON0);
.init = rk3528_init,
.set_to_rgmii = rk3528_set_to_rgmii,
.set_to_rmii = rk3528_set_to_rmii,
- .set_clock_selection = rk3528_set_clock_selection,
.integrated_phy_powerup = rk3528_integrated_phy_powerup,
.integrated_phy_powerdown = rk3528_integrated_phy_powerdown,
.regs_valid = true,
#define RK3576_GRF_GMAC_CON0 0X0020
#define RK3576_GRF_GMAC_CON1 0X0024
-#define RK3576_GMAC_CLK_SELECT_IO GRF_BIT(7)
-#define RK3576_GMAC_CLK_SELECT_CRU GRF_CLR_BIT(7)
-
-#define RK3576_GMAC_CLK_RMII_GATE GRF_BIT(4)
-#define RK3576_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(4)
-
static int rk3576_init(struct rk_priv_data *bsp_priv)
{
switch (bsp_priv->id) {
RK3576_GMAC_CLK_RX_DL_CFG(rx_delay));
}
-static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
- bool enable)
-{
- unsigned int val = input ? RK3576_GMAC_CLK_SELECT_IO :
- RK3576_GMAC_CLK_SELECT_CRU;
- unsigned int offset_con;
-
- val |= enable ? RK3576_GMAC_CLK_RMII_NOGATE :
- RK3576_GMAC_CLK_RMII_GATE;
-
- offset_con = bsp_priv->id == 1 ? RK3576_GRF_GMAC_CON1 :
- RK3576_GRF_GMAC_CON0;
-
- regmap_write(bsp_priv->grf, offset_con, val);
-}
-
static const struct rk_gmac_ops rk3576_ops = {
.init = rk3576_init,
.set_to_rgmii = rk3576_set_to_rgmii,
- .set_clock_selection = rk3576_set_clock_selection,
.gmac_rmii_mode_mask = BIT_U16(3),
+ .clock.io_clksel_io_mask = BIT_U16(7),
.clock.gmii_clk_sel_mask = GENMASK_U16(6, 5),
.clock.rmii_clk_sel_mask = BIT_U16(5),
+ .clock.rmii_gate_en_mask = BIT_U16(4),
.supports_rmii = true,
#define RK3588_GMAC_CLK_RMII_MODE(id) GRF_BIT(5 * (id))
#define RK3588_GMAC_CLK_RGMII_MODE(id) GRF_CLR_BIT(5 * (id))
-#define RK3588_GMAC_CLK_SELECT_CRU(id) GRF_BIT(5 * (id) + 4)
-#define RK3588_GMAC_CLK_SELECT_IO(id) GRF_CLR_BIT(5 * (id) + 4)
-
-#define RK3588_GMAC_CLK_RMII_GATE(id) GRF_BIT(5 * (id) + 1)
-#define RK3588_GMAC_CLK_RMII_NOGATE(id) GRF_CLR_BIT(5 * (id) + 1)
-
static int rk3588_init(struct rk_priv_data *bsp_priv)
{
switch (bsp_priv->id) {
case 0:
bsp_priv->gmac_phy_intf_sel_mask = GENMASK_U16(5, 3);
+ bsp_priv->clock.io_clksel_cru_mask = BIT_U16(4);
bsp_priv->clock.gmii_clk_sel_mask = GENMASK_U16(3, 2);
bsp_priv->clock.rmii_clk_sel_mask = BIT_U16(2);
+ bsp_priv->clock.rmii_gate_en_mask = BIT_U16(1);
return 0;
case 1:
bsp_priv->gmac_phy_intf_sel_mask = GENMASK_U16(11, 9);
+ bsp_priv->clock.io_clksel_cru_mask = BIT_U16(9);
bsp_priv->clock.gmii_clk_sel_mask = GENMASK_U16(8, 7);
bsp_priv->clock.rmii_clk_sel_mask = BIT_U16(7);
+ bsp_priv->clock.rmii_gate_en_mask = BIT_U16(6);
return 0;
default:
RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id));
}
-static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
- bool enable)
-{
- unsigned int val = input ? RK3588_GMAC_CLK_SELECT_IO(bsp_priv->id) :
- RK3588_GMAC_CLK_SELECT_CRU(bsp_priv->id);
-
- val |= enable ? RK3588_GMAC_CLK_RMII_NOGATE(bsp_priv->id) :
- RK3588_GMAC_CLK_RMII_GATE(bsp_priv->id);
-
- regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, val);
-}
-
static const struct rk_gmac_ops rk3588_ops = {
.init = rk3588_init,
.set_to_rgmii = rk3588_set_to_rgmii,
.set_to_rmii = rk3588_set_to_rmii,
- .set_clock_selection = rk3588_set_clock_selection,
.gmac_grf_reg_in_php = true,
.gmac_grf_reg = RK3588_GRF_GMAC_CON0,
if (ret)
return ret;
- if (bsp_priv->ops && bsp_priv->ops->set_clock_selection)
- bsp_priv->ops->set_clock_selection(bsp_priv,
- bsp_priv->clock_input, true);
+ rk_configure_io_clksel(bsp_priv);
+ rk_ungate_rmii_clock(bsp_priv);
mdelay(5);
bsp_priv->clk_enabled = true;
}
} else {
if (bsp_priv->clk_enabled) {
- if (bsp_priv->ops && bsp_priv->ops->set_clock_selection) {
- bsp_priv->ops->set_clock_selection(bsp_priv,
- bsp_priv->clock_input, false);
- }
+ rk_gate_rmii_clock(bsp_priv);
clk_bulk_disable_unprepare(bsp_priv->num_clks,
bsp_priv->clks);
}
}
+ if (bsp_priv->clock.io_clksel_cru_mask &&
+ bsp_priv->clock.io_clksel_io_mask)
+ dev_warn(dev, "both CRU and IO io_clksel masks should not be populated - driver may malfunction\n");
+
return bsp_priv;
}