diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c index bd54b9fa7..fd9c3abf4 100644 --- a/drivers/clk/meson/clk-regmap.c +++ b/drivers/clk/meson/clk-regmap.c @@ -8,6 +8,33 @@ #include #include "clk-regmap.h" +static int clk_regmap_check_is_satisfied(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); + unsigned int val; + int cnt = 3; + + if (gate->check_offset) { + do { + if (!cnt) { + pr_err("check %s failed!\n", clk_hw_get_name(hw)); + return -ETIMEDOUT; + } + /* + * FIXME: due to hardware reasons, the check will be delayed per 1ms, + * and the splinlock used during the enable period will be delayed + * for at least 1ms. + */ + udelay(1000); + cnt--; + regmap_read(clk->map, gate->check_offset, &val); + } while (!(val & BIT(gate->check_bit))); + } + + return 0; +} + static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) { struct clk_regmap *clk = to_clk_regmap(hw); @@ -22,7 +49,13 @@ static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) static int clk_regmap_gate_enable(struct clk_hw *hw) { - return clk_regmap_gate_endisable(hw, 1); + int ret; + + ret = clk_regmap_gate_endisable(hw, 1); + if (ret) + return ret; + + return clk_regmap_check_is_satisfied(hw); } static void clk_regmap_gate_disable(struct clk_hw *hw) diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h index 552ecb920..f41874f80 100644 --- a/drivers/clk/meson/clk-regmap.h +++ b/drivers/clk/meson/clk-regmap.h @@ -45,6 +45,8 @@ struct clk_regmap { struct clk_regmap_gate_data { unsigned int offset; u8 bit_idx; + unsigned int check_offset; + u8 check_bit; u8 flags; }; diff --git a/drivers/clk/meson/s7.c b/drivers/clk/meson/s7.c index 07bcbf5af..5cd468ab5 100644 --- a/drivers/clk/meson/s7.c +++ b/drivers/clk/meson/s7.c @@ -1246,19 +1246,103 @@ MESON_CLK_MUX_RW(vdec, CLKCTRL_VDEC3_CLK_CTRL, 0x1, 15, NULL, 0, vdec_parent_data, CLK_SET_RATE_PARENT); /* cts_hevcf_clk */ -MESON_CLK_COMPOSITE_RW(hevcf_0, CLKCTRL_VDEC2_CLK_CTRL, 0x7, 9, - NULL, 0, vdec_pre_parent_data, 0, - CLKCTRL_VDEC2_CLK_CTRL, 0, 7, NULL, - 0, CLK_SET_RATE_PARENT, - CLKCTRL_VDEC2_CLK_CTRL, 8, - 0, CLK_SET_RATE_PARENT); +static struct clk_regmap hevcf_0_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = vdec_pre_parent_data, + .num_parents = ARRAY_SIZE(vdec_pre_parent_data), + }, +}; -MESON_CLK_COMPOSITE_RW(hevcf_1, CLKCTRL_VDEC4_CLK_CTRL, 0x7, 9, - NULL, 0, vdec_pre_parent_data, 0, - CLKCTRL_VDEC4_CLK_CTRL, 0, 7, NULL, - 0, CLK_SET_RATE_PARENT, - CLKCTRL_VDEC4_CLK_CTRL, 8, - 0, CLK_SET_RATE_PARENT); +static struct clk_regmap hevcf_0_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &hevcf_0_sel.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap hevcf_0 = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .bit_idx = 8, + .check_offset = CLKCTRL_CHECK_CLK_RESULT, + .check_bit = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &hevcf_0_div.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap hevcf_1_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = vdec_pre_parent_data, + .num_parents = ARRAY_SIZE(vdec_pre_parent_data), + }, +}; + +static struct clk_regmap hevcf_1_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &hevcf_1_sel.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap hevcf_1 = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .bit_idx = 8, + .check_offset = CLKCTRL_CHECK_CLK_RESULT, + .check_bit = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &hevcf_1_div.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; static const struct clk_parent_data hevcf_parent_data[] = { { .hw = &hevcf_0.hw },