Re: [PATCH V2 4/4] clk: meson: c3: add c3 clock peripherals controller driver

From: Jerome Brunet
Date: Tue Oct 17 2023 - 11:36:37 EST



On Tue 17 Oct 2023 at 22:59, Chuan Liu <chuan.liu@xxxxxxxxxxx> wrote:

>>>>> +
>>>>> +static struct clk_regmap saradc = {
>>>>> + .data = &(struct clk_regmap_gate_data){
>>>>> + .offset = SAR_CLK_CTRL0,
>>>>> + .bit_idx = 8,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data) {
>>>>> + .name = "saradc",
>>>>> + .ops = &clk_regmap_gate_ops,
>>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>>> + &saradc_div.hw
>>>>> + },
>>>>> + .num_parents = 1,
>>>>> + .flags = CLK_SET_RATE_PARENT,
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static u32 pwm_parent_table[] = { 0, 2, 3 };
>>>> What's pwm parent 1, why can't it be used ?
>>> This 1 corresponds to gp1 pll, which is currently dedicated to emmc.
>> Given that gp1 does not exist in your PLL controller, it is going to be
>> hard to dedicate it to eMMC ;)
> Because the register corresponding to gp1_pll has permission restrictions,
> the corresponding register is read-only in the kernel (can read and write
> in the bl31 environment), here first mask the source to solve the
> permission problem before opening

The PWM sel clock does not have CLK_SET_RATE_PARENT so it is not going to
request rate change for any parent clock, it will just what is available.

Your reason does not apply here.

Also, if gp1 registers are read-only from the kernel, you can still
expose it with RO ops, possibly with CLK_GET_RATE_NOCACHE if the bl31
may change at runtime.

>>
>>>>> +
>>>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>>>> + { .fw_name = "xtal" },
>>>>> + { .fw_name = "fclk_div4" },
>>>>> + { .fw_name = "fclk_div3" }
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap pwm_a_sel = {
>>>>> + .data = &(struct clk_regmap_mux_data){
>>>>> + .offset = PWM_CLK_AB_CTRL,
>>>>> + .mask = 0x3,
>>>>> + .shift = 9,
>>>>> + .table = pwm_parent_table,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data){
>>>>> + .name = "pwm_a_sel",
>>>>> + .ops = &clk_regmap_mux_ops,
>>>>> + .parent_data = pwm_parent_data,
>>>>> + .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap pwm_a_div = {
>>>>> + .data = &(struct clk_regmap_div_data){
>>>>> + .offset = PWM_CLK_AB_CTRL,
>>>>> + .shift = 0,
>>>>> + .width = 8,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data){
>>>>> + .name = "pwm_a_div",
>>>>> + .ops = &clk_regmap_divider_ops,
>>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>>> + &pwm_a_sel.hw
>>>>> + },
>>>>> + .num_parents = 1,
>>>>> + .flags = CLK_SET_RATE_PARENT,
>>>>> + },
>>>>> +};

[...]

>>>>> +
>>>>> +static struct clk_regmap spifc = {
>>>>> + .data = &(struct clk_regmap_gate_data){
>>>>> + .offset = SPIFC_CLK_CTRL,
>>>>> + .bit_idx = 8,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data) {
>>>>> + .name = "spifc",
>>>>> + .ops = &clk_regmap_gate_ops,
>>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>>> + &spifc_div.hw
>>>>> + },
>>>>> + .num_parents = 1,
>>>>> + .flags = CLK_SET_RATE_PARENT,
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static u32 emmc_parent_table[] = { 0, 1, 2, 3, 4, 5, 7 };
>>>> What's 6 ? why can't it be used ?
>>>>
>> No answer ?
> 6 - gp1_pll,The permission reason is that the patch is submitted to open
> after the solution is resolved
>>
>>>>> +
>>>>> +static const struct clk_parent_data emmc_parent_data[] = {
>>>>> + { .fw_name = "xtal" },
>>>>> + { .fw_name = "fclk_div2" },
>>>>> + { .fw_name = "fclk_div3" },
>>>>> + { .fw_name = "hifi_pll" },
>>>>> + { .fw_name = "fclk_div2p5" },
>>>>> + { .fw_name = "fclk_div4" },
>>>>> + { .fw_name = "gp0_pll" }
>>>>> +};
>> Not seeing gp1 there ? why would you need to dedicate an GP pll for MMC
>> ? Maybe I missing something but it seems to me the usual MMC rate are
>> acheivable with the fclks, especially 2p5.
> Permission reason

use RO ops.

>>
>>>>> +
>>>>> +static struct clk_regmap sd_emmc_a_sel = {
>>>>> + .data = &(struct clk_regmap_mux_data){
>>>>> + .offset = SD_EMMC_CLK_CTRL,
>>>>> + .mask = 0x7,
>>>>> + .shift = 9,
>>>>> + .table = emmc_parent_table,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data){
>>>>> + .name = "sd_emmc_a_sel",
>>>>> + .ops = &clk_regmap_mux_ops,
>>>>> + .parent_data = emmc_parent_data,
>>>>> + .num_parents = ARRAY_SIZE(emmc_parent_data),
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap sd_emmc_a_div = {
>>>>> + .data = &(struct clk_regmap_div_data){
>>>>> + .offset = SD_EMMC_CLK_CTRL,
>>>>> + .shift = 0,
>>>>> + .width = 7,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data){
>>>>> + .name = "sd_emmc_a_div",
>>>>> + .ops = &clk_regmap_divider_ops,
>>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>>> + &sd_emmc_a_sel.hw
>>>>> + },
>>>>> + .num_parents = 1,
>>>>> + .flags = CLK_SET_RATE_PARENT,
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap sd_emmc_a = {
>>>>> + .data = &(struct clk_regmap_gate_data){
>>>>> + .offset = SD_EMMC_CLK_CTRL,
>>>>> + .bit_idx = 7,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data) {
>>>>> + .name = "sd_emmc_a",
>>>>> + .ops = &clk_regmap_gate_ops,
>>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>>> + &sd_emmc_a_div.hw
>>>>> + },
>>>>> + .num_parents = 1,
>>>>> + .flags = CLK_SET_RATE_PARENT,
>>>>> + },
>>>>> +};

[...]

>>>>> +static u32 csi_phy_parent_table[] = { 0, 1, 2, 3, 4, 5, 7 };
>>>> Same here and all following instance
>>>>
>>> This 1 corresponds to gp1 pll, which is currently dedicated to emmc.
>> No it is not. Again mainline drivers are slightly different from AML
>> fork you might be used to. No PLL is dedicated to the mmc driver.
>> Unless you can make a strong case for it, I don't think it will happen
>> in the near future.
> For performance considerations, emmc needs to use a higher frequency clock
> source (currently our emmc driver has been adapted to 1152M), so we
> internally allocate gp1_pll to emmc.As mentioned above, the gp1_pll
> register permission problem is masked here first🙂

Your GP1 is controlled by the SCP FW and RO for the kernel. That's all from
the clock controller POV.

No reason to remove it here and elsewhere AFAICT

>>>>> +
>>>>> +static const struct clk_parent_data csi_phy_parent_data[] = {
>>>>> + { .fw_name = "fclk_div2p5" },
>>>>> + { .fw_name = "fclk_div3" },
>>>>> + { .fw_name = "fclk_div4" },
>>>>> + { .fw_name = "fclk_div5" },
>>>>> + { .fw_name = "gp0_pll" },
>>>>> + { .fw_name = "hifi_pll" },
>>>>> + { .fw_name = "xtal" }
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap csi_phy0_sel = {
>>>>> + .data = &(struct clk_regmap_mux_data){
>>>>> + .offset = ISP0_CLK_CTRL,
>>>>> + .mask = 0x7,
>>>>> + .shift = 25,
>>>>> + .table = csi_phy_parent_table,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data){
>>>>> + .name = "csi_phy0_sel",
>>>>> + .ops = &clk_regmap_mux_ops,
>>>>> + .parent_data = csi_phy_parent_data,
>>>>> + .num_parents = ARRAY_SIZE(csi_phy_parent_data),
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap csi_phy0_div = {
>>>>> + .data = &(struct clk_regmap_div_data){
>>>>> + .offset = ISP0_CLK_CTRL,
>>>>> + .shift = 16,
>>>>> + .width = 7,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data){
>>>>> + .name = "csi_phy0_div",
>>>>> + .ops = &clk_regmap_divider_ops,
>>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>>> + &csi_phy0_sel.hw
>>>>> + },
>>>>> + .num_parents = 1,
>>>>> + .flags = CLK_SET_RATE_PARENT,
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap csi_phy0 = {
>>>>> + .data = &(struct clk_regmap_gate_data){
>>>>> + .offset = ISP0_CLK_CTRL,
>>>>> + .bit_idx = 24,
>>>>> + },
>>>>> + .hw.init = &(struct clk_init_data) {
>>>>> + .name = "csi_phy0",
>>>>> + .ops = &clk_regmap_gate_ops,
>>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>>> + &csi_phy0_div.hw
>>>>> + },
>>>>> + .num_parents = 1,
>>>>> + .flags = CLK_SET_RATE_PARENT,
>>>>> + },
>>>>> +};