Skip to content

Commit 081a9b7

Browse files
fancerbebarino
authored andcommitted
clk: baikal-t1: Add SATA internal ref clock buffer
It turns out the internal SATA reference clock signal will stay unavailable for the SATA interface consumer until the buffer on it's way is ungated. So aside with having the actual clock divider enabled we need to ungate a buffer placed on the signal way to the SATA controller (most likely some rudiment from the initial SoC release). Seeing the switch flag is placed in the same register as the SATA-ref clock divider at a non-standard ffset, let's implement it as a separate clock controller with the set-rate propagation to the parental clock divider wrapper. As such we'll be able to disable/enable and still change the original clock source rate. Fixes: 353afa3 ("clk: Add Baikal-T1 CCU Dividers driver") Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20220929225402.9696-5-Sergey.Semin@baikalelectronics.ru Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent e2eef31 commit 081a9b7

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

drivers/clk/baikal-t1/ccu-div.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#define CCU_DIV_CTL_CLKDIV_MASK(_width) \
3535
GENMASK((_width) + CCU_DIV_CTL_CLKDIV_FLD - 1, CCU_DIV_CTL_CLKDIV_FLD)
3636
#define CCU_DIV_CTL_LOCK_SHIFTED BIT(27)
37+
#define CCU_DIV_CTL_GATE_REF_BUF BIT(28)
3738
#define CCU_DIV_CTL_LOCK_NORMAL BIT(31)
3839

3940
#define CCU_DIV_RST_DELAY_US 1
@@ -170,6 +171,40 @@ static int ccu_div_gate_is_enabled(struct clk_hw *hw)
170171
return !!(val & CCU_DIV_CTL_EN);
171172
}
172173

174+
static int ccu_div_buf_enable(struct clk_hw *hw)
175+
{
176+
struct ccu_div *div = to_ccu_div(hw);
177+
unsigned long flags;
178+
179+
spin_lock_irqsave(&div->lock, flags);
180+
regmap_update_bits(div->sys_regs, div->reg_ctl,
181+
CCU_DIV_CTL_GATE_REF_BUF, 0);
182+
spin_unlock_irqrestore(&div->lock, flags);
183+
184+
return 0;
185+
}
186+
187+
static void ccu_div_buf_disable(struct clk_hw *hw)
188+
{
189+
struct ccu_div *div = to_ccu_div(hw);
190+
unsigned long flags;
191+
192+
spin_lock_irqsave(&div->lock, flags);
193+
regmap_update_bits(div->sys_regs, div->reg_ctl,
194+
CCU_DIV_CTL_GATE_REF_BUF, CCU_DIV_CTL_GATE_REF_BUF);
195+
spin_unlock_irqrestore(&div->lock, flags);
196+
}
197+
198+
static int ccu_div_buf_is_enabled(struct clk_hw *hw)
199+
{
200+
struct ccu_div *div = to_ccu_div(hw);
201+
u32 val = 0;
202+
203+
regmap_read(div->sys_regs, div->reg_ctl, &val);
204+
205+
return !(val & CCU_DIV_CTL_GATE_REF_BUF);
206+
}
207+
173208
static unsigned long ccu_div_var_recalc_rate(struct clk_hw *hw,
174209
unsigned long parent_rate)
175210
{
@@ -323,6 +358,7 @@ static const struct ccu_div_dbgfs_bit ccu_div_bits[] = {
323358
CCU_DIV_DBGFS_BIT_ATTR("div_en", CCU_DIV_CTL_EN),
324359
CCU_DIV_DBGFS_BIT_ATTR("div_rst", CCU_DIV_CTL_RST),
325360
CCU_DIV_DBGFS_BIT_ATTR("div_bypass", CCU_DIV_CTL_SET_CLKDIV),
361+
CCU_DIV_DBGFS_BIT_ATTR("div_buf", CCU_DIV_CTL_GATE_REF_BUF),
326362
CCU_DIV_DBGFS_BIT_ATTR("div_lock", CCU_DIV_CTL_LOCK_NORMAL)
327363
};
328364

@@ -441,6 +477,9 @@ static void ccu_div_var_debug_init(struct clk_hw *hw, struct dentry *dentry)
441477
continue;
442478
}
443479

480+
if (!strcmp("div_buf", name))
481+
continue;
482+
444483
bits[didx] = ccu_div_bits[bidx];
445484
bits[didx].div = div;
446485

@@ -477,6 +516,21 @@ static void ccu_div_gate_debug_init(struct clk_hw *hw, struct dentry *dentry)
477516
&ccu_div_dbgfs_fixed_clkdiv_fops);
478517
}
479518

519+
static void ccu_div_buf_debug_init(struct clk_hw *hw, struct dentry *dentry)
520+
{
521+
struct ccu_div *div = to_ccu_div(hw);
522+
struct ccu_div_dbgfs_bit *bit;
523+
524+
bit = kmalloc(sizeof(*bit), GFP_KERNEL);
525+
if (!bit)
526+
return;
527+
528+
*bit = ccu_div_bits[3];
529+
bit->div = div;
530+
debugfs_create_file_unsafe(bit->name, ccu_div_dbgfs_mode, dentry, bit,
531+
&ccu_div_dbgfs_bit_fops);
532+
}
533+
480534
static void ccu_div_fixed_debug_init(struct clk_hw *hw, struct dentry *dentry)
481535
{
482536
struct ccu_div *div = to_ccu_div(hw);
@@ -489,6 +543,7 @@ static void ccu_div_fixed_debug_init(struct clk_hw *hw, struct dentry *dentry)
489543

490544
#define ccu_div_var_debug_init NULL
491545
#define ccu_div_gate_debug_init NULL
546+
#define ccu_div_buf_debug_init NULL
492547
#define ccu_div_fixed_debug_init NULL
493548

494549
#endif /* !CONFIG_DEBUG_FS */
@@ -520,6 +575,13 @@ static const struct clk_ops ccu_div_gate_ops = {
520575
.debug_init = ccu_div_gate_debug_init
521576
};
522577

578+
static const struct clk_ops ccu_div_buf_ops = {
579+
.enable = ccu_div_buf_enable,
580+
.disable = ccu_div_buf_disable,
581+
.is_enabled = ccu_div_buf_is_enabled,
582+
.debug_init = ccu_div_buf_debug_init
583+
};
584+
523585
static const struct clk_ops ccu_div_fixed_ops = {
524586
.recalc_rate = ccu_div_fixed_recalc_rate,
525587
.round_rate = ccu_div_fixed_round_rate,
@@ -566,6 +628,8 @@ struct ccu_div *ccu_div_hw_register(const struct ccu_div_init_data *div_init)
566628
} else if (div_init->type == CCU_DIV_GATE) {
567629
hw_init.ops = &ccu_div_gate_ops;
568630
div->divider = div_init->divider;
631+
} else if (div_init->type == CCU_DIV_BUF) {
632+
hw_init.ops = &ccu_div_buf_ops;
569633
} else if (div_init->type == CCU_DIV_FIXED) {
570634
hw_init.ops = &ccu_div_fixed_ops;
571635
div->divider = div_init->divider;

drivers/clk/baikal-t1/ccu-div.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515

1616
/*
1717
* CCU Divider private clock IDs
18+
* @CCU_SYS_SATA_CLK: CCU SATA internal clock
1819
* @CCU_SYS_XGMAC_CLK: CCU XGMAC internal clock
1920
*/
21+
#define CCU_SYS_SATA_CLK -1
2022
#define CCU_SYS_XGMAC_CLK -2
2123

2224
/*
@@ -37,11 +39,13 @@
3739
* enum ccu_div_type - CCU Divider types
3840
* @CCU_DIV_VAR: Clocks gate with variable divider.
3941
* @CCU_DIV_GATE: Clocks gate with fixed divider.
42+
* @CCU_DIV_BUF: Clock gate with no divider.
4043
* @CCU_DIV_FIXED: Ungateable clock with fixed divider.
4144
*/
4245
enum ccu_div_type {
4346
CCU_DIV_VAR,
4447
CCU_DIV_GATE,
48+
CCU_DIV_BUF,
4549
CCU_DIV_FIXED
4650
};
4751

drivers/clk/baikal-t1/clk-ccu-div.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@
7676
.divider = _divider \
7777
}
7878

79+
#define CCU_DIV_BUF_INFO(_id, _name, _pname, _base, _flags) \
80+
{ \
81+
.id = _id, \
82+
.name = _name, \
83+
.parent_name = _pname, \
84+
.base = _base, \
85+
.type = CCU_DIV_BUF, \
86+
.flags = _flags \
87+
}
88+
7989
#define CCU_DIV_FIXED_INFO(_id, _name, _pname, _divider) \
8090
{ \
8191
.id = _id, \
@@ -188,11 +198,14 @@ static const struct ccu_div_rst_map axi_rst_map[] = {
188198
* for the SoC devices registers IO-operations.
189199
*/
190200
static const struct ccu_div_info sys_info[] = {
191-
CCU_DIV_VAR_INFO(CCU_SYS_SATA_REF_CLK, "sys_sata_ref_clk",
201+
CCU_DIV_VAR_INFO(CCU_SYS_SATA_CLK, "sys_sata_clk",
192202
"sata_clk", CCU_SYS_SATA_REF_BASE, 4,
193203
CLK_SET_RATE_GATE,
194204
CCU_DIV_SKIP_ONE | CCU_DIV_LOCK_SHIFTED |
195205
CCU_DIV_RESET_DOMAIN),
206+
CCU_DIV_BUF_INFO(CCU_SYS_SATA_REF_CLK, "sys_sata_ref_clk",
207+
"sys_sata_clk", CCU_SYS_SATA_REF_BASE,
208+
CLK_SET_RATE_PARENT),
196209
CCU_DIV_VAR_INFO(CCU_SYS_APB_CLK, "sys_apb_clk",
197210
"pcie_clk", CCU_SYS_APB_BASE, 5,
198211
CLK_IS_CRITICAL, CCU_DIV_RESET_DOMAIN),
@@ -398,6 +411,9 @@ static int ccu_div_clk_register(struct ccu_div_data *data)
398411
init.base = info->base;
399412
init.sys_regs = data->sys_regs;
400413
init.divider = info->divider;
414+
} else if (init.type == CCU_DIV_BUF) {
415+
init.base = info->base;
416+
init.sys_regs = data->sys_regs;
401417
} else {
402418
init.divider = info->divider;
403419
}

0 commit comments

Comments
 (0)