Commit fc336ae6 authored by Luca Ceresoli's avatar Luca Ceresoli Committed by Stephen Boyd

clk: vc5: fix output disabling when enabling a FOD

On 5P49V6965, when an output is enabled we enable the corresponding
FOD. When this happens for the first time, and specifically when writing
register VC5_OUT_DIV_CONTROL in vc5_clk_out_prepare(), all other outputs
are stopped for a short time and then restarted.

According to Renesas support this is intended: "The reason for that is VC6E
has synced up all output function".

This behaviour can be disabled at least on VersaClock 6E devices, of which
only the 5P49V6965 is currently implemented by this driver. This requires
writing bit 7 (bypass_sync{1..4}) in register 0x20..0x50.  Those registers
are named "Unused Factory Reserved Register", and the bits are documented
as "Skip VDDO<N> verification", which does not clearly explain the relation
to FOD sync. However according to Renesas support as well as my testing
setting this bit does prevent disabling of all clock outputs when enabling
a FOD.

See "VersaClock ® 6E Family Register Descriptions and Programming Guide"
(August 30, 2018), Table 116 "Power Up VDD check", page 58:
https://www.renesas.com/us/en/document/mau/versaclock-6e-family-register-descriptions-and-programming-guideSigned-off-by: default avatarLuca Ceresoli <luca@lucaceresoli.net>
Reviewed-by: default avatarAdam Ford <aford173@gmail.com>
Link: https://lore.kernel.org/r/20210527211647.1520720-1-luca@lucaceresoli.net
Fixes: 2bda748e ("clk: vc5: Add support for IDT VersaClock 5P49V6965")
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 6efb943b
...@@ -69,7 +69,10 @@ ...@@ -69,7 +69,10 @@
#define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n)) #define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n))
#define VC5_RC_CONTROL0 0x1e #define VC5_RC_CONTROL0 0x1e
#define VC5_RC_CONTROL1 0x1f #define VC5_RC_CONTROL1 0x1f
/* Register 0x20 is factory reserved */
/* These registers are named "Unused Factory Reserved Registers" */
#define VC5_RESERVED_X0(idx) (0x20 + ((idx) * 0x10))
#define VC5_RESERVED_X0_BYPASS_SYNC BIT(7) /* bypass_sync<idx> bit */
/* Output divider control for divider 1,2,3,4 */ /* Output divider control for divider 1,2,3,4 */
#define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10)) #define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10))
...@@ -87,7 +90,6 @@ ...@@ -87,7 +90,6 @@
#define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n)) #define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n))
#define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n)) #define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n))
#define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10)) #define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10))
/* Registers 0x30, 0x40, 0x50 are factory reserved */
/* Clock control register for clock 1,2 */ /* Clock control register for clock 1,2 */
#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n)) #define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
...@@ -140,6 +142,8 @@ ...@@ -140,6 +142,8 @@
#define VC5_HAS_INTERNAL_XTAL BIT(0) #define VC5_HAS_INTERNAL_XTAL BIT(0)
/* chip has PFD requency doubler */ /* chip has PFD requency doubler */
#define VC5_HAS_PFD_FREQ_DBL BIT(1) #define VC5_HAS_PFD_FREQ_DBL BIT(1)
/* chip has bits to disable FOD sync */
#define VC5_HAS_BYPASS_SYNC_BIT BIT(2)
/* Supported IDT VC5 models. */ /* Supported IDT VC5 models. */
enum vc5_model { enum vc5_model {
...@@ -581,6 +585,23 @@ static int vc5_clk_out_prepare(struct clk_hw *hw) ...@@ -581,6 +585,23 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
unsigned int src; unsigned int src;
int ret; int ret;
/*
* When enabling a FOD, all currently enabled FODs are briefly
* stopped in order to synchronize all of them. This causes a clock
* disruption to any unrelated chips that might be already using
* other clock outputs. Bypass the sync feature to avoid the issue,
* which is possible on the VersaClock 6E family via reserved
* registers.
*/
if (vc5->chip_info->flags & VC5_HAS_BYPASS_SYNC_BIT) {
ret = regmap_update_bits(vc5->regmap,
VC5_RESERVED_X0(hwdata->num),
VC5_RESERVED_X0_BYPASS_SYNC,
VC5_RESERVED_X0_BYPASS_SYNC);
if (ret)
return ret;
}
/* /*
* If the input mux is disabled, enable it first and * If the input mux is disabled, enable it first and
* select source from matching FOD. * select source from matching FOD.
...@@ -1166,7 +1187,7 @@ static const struct vc5_chip_info idt_5p49v6965_info = { ...@@ -1166,7 +1187,7 @@ static const struct vc5_chip_info idt_5p49v6965_info = {
.model = IDT_VC6_5P49V6965, .model = IDT_VC6_5P49V6965,
.clk_fod_cnt = 4, .clk_fod_cnt = 4,
.clk_out_cnt = 5, .clk_out_cnt = 5,
.flags = 0, .flags = VC5_HAS_BYPASS_SYNC_BIT,
}; };
static const struct i2c_device_id vc5_id[] = { static const struct i2c_device_id vc5_id[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment