Commit 7e7b8ca66191c5dde9f6521ff8a0180834efa628

Authored by Roger Quadros
Committed by Kishon Vijay Abraham I
1 parent 71e2f5c5c2

phy: ti: am654-serdes: Support all clksel values

Add support to select all 16 CLKSEL combinations that are shown in
"SerDes Reference Clock Distribution" in AM65 TRM.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

Showing 1 changed file with 83 additions and 49 deletions Side-by-side Diff

drivers/phy/ti/phy-am654-serdes.c
... ... @@ -58,13 +58,14 @@
58 58  
59 59 #define SERDES_NUM_CLOCKS 3
60 60  
  61 +#define AM654_SERDES_CTRL_CLKSEL_MASK GENMASK(7, 4)
  62 +#define AM654_SERDES_CTRL_CLKSEL_SHIFT 4
  63 +
61 64 struct serdes_am654_clk_mux {
62 65 struct clk_hw hw;
63 66 struct regmap *regmap;
64 67 unsigned int reg;
65   - int *table;
66   - u32 mask;
67   - u8 shift;
  68 + int clk_id;
68 69 struct clk_init_data clk_data;
69 70 };
70 71  
71 72  
72 73  
73 74  
74 75  
... ... @@ -282,31 +283,52 @@
282 283 .owner = THIS_MODULE,
283 284 };
284 285  
  286 +#define SERDES_NUM_MUX_COMBINATIONS 16
  287 +
  288 +#define LICLK 0
  289 +#define EXT_REFCLK 1
  290 +#define RICLK 2
  291 +
  292 +static const int
  293 +serdes_am654_mux_table[SERDES_NUM_MUX_COMBINATIONS][SERDES_NUM_CLOCKS] = {
  294 + /*
  295 + * Each combination maps to one of
  296 + * "Figure 12-1986. SerDes Reference Clock Distribution"
  297 + * in TRM.
  298 + */
  299 + /* Parent of CMU refclk, Left output, Right output
  300 + * either of EXT_REFCLK, LICLK, RICLK
  301 + */
  302 + { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0000 */
  303 + { RICLK, EXT_REFCLK, EXT_REFCLK }, /* 0001 */
  304 + { EXT_REFCLK, RICLK, LICLK }, /* 0010 */
  305 + { RICLK, RICLK, EXT_REFCLK }, /* 0011 */
  306 + { LICLK, EXT_REFCLK, EXT_REFCLK }, /* 0100 */
  307 + { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0101 */
  308 + { LICLK, RICLK, LICLK }, /* 0110 */
  309 + { EXT_REFCLK, RICLK, LICLK }, /* 0111 */
  310 + { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1000 */
  311 + { RICLK, EXT_REFCLK, LICLK }, /* 1001 */
  312 + { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1010 */
  313 + { RICLK, RICLK, EXT_REFCLK }, /* 1011 */
  314 + { LICLK, EXT_REFCLK, LICLK }, /* 1100 */
  315 + { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1101 */
  316 + { LICLK, RICLK, EXT_REFCLK }, /* 1110 */
  317 + { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1111 */
  318 +};
  319 +
285 320 static u8 serdes_am654_clk_mux_get_parent(struct clk_hw *hw)
286 321 {
287 322 struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw);
288   - unsigned int num_parents = clk_hw_get_num_parents(hw);
289 323 struct regmap *regmap = mux->regmap;
290 324 unsigned int reg = mux->reg;
291 325 unsigned int val;
292   - int i;
293 326  
294 327 regmap_read(regmap, reg, &val);
295   - val >>= mux->shift;
296   - val &= mux->mask;
  328 + val &= AM654_SERDES_CTRL_CLKSEL_MASK;
  329 + val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT;
297 330  
298   - for (i = 0; i < num_parents; i++)
299   - if (mux->table[i] == val)
300   - return i;
301   -
302   - /*
303   - * No parent? This should never happen!
304   - * Verify if we set a valid parent in serdes_am654_clk_register()
305   - */
306   - WARN(1, "Failed to find the parent of %s clock\n", hw->init->name);
307   -
308   - /* Make the parent lookup to fail */
309   - return num_parents;
  331 + return serdes_am654_mux_table[val][mux->clk_id];
310 332 }
311 333  
312 334 static int serdes_am654_clk_mux_set_parent(struct clk_hw *hw, u8 index)
313 335  
314 336  
315 337  
316 338  
... ... @@ -314,16 +336,52 @@
314 336 struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw);
315 337 struct regmap *regmap = mux->regmap;
316 338 unsigned int reg = mux->reg;
317   - int val;
  339 + int clk_id = mux->clk_id;
  340 + int parents[SERDES_NUM_CLOCKS];
  341 + const int *p;
  342 + u32 val;
  343 + int found, i;
318 344 int ret;
319 345  
320   - val = mux->table[index];
  346 + /* get existing setting */
  347 + regmap_read(regmap, reg, &val);
  348 + val &= AM654_SERDES_CTRL_CLKSEL_MASK;
  349 + val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT;
321 350  
322   - if (val == -1)
  351 + for (i = 0; i < SERDES_NUM_CLOCKS; i++)
  352 + parents[i] = serdes_am654_mux_table[val][i];
  353 +
  354 + /* change parent of this clock. others left intact */
  355 + parents[clk_id] = index;
  356 +
  357 + /* Find the match */
  358 + for (val = 0; val < SERDES_NUM_MUX_COMBINATIONS; val++) {
  359 + p = serdes_am654_mux_table[val];
  360 + found = 1;
  361 + for (i = 0; i < SERDES_NUM_CLOCKS; i++) {
  362 + if (parents[i] != p[i]) {
  363 + found = 0;
  364 + break;
  365 + }
  366 + }
  367 +
  368 + if (found)
  369 + break;
  370 + }
  371 +
  372 + if (!found) {
  373 + /*
  374 + * This can never happen, unless we missed
  375 + * a valid combination in serdes_am654_mux_table.
  376 + */
  377 + WARN(1, "Failed to find the parent of %s clock\n",
  378 + hw->init->name);
323 379 return -EINVAL;
  380 + }
324 381  
325   - val <<= mux->shift;
326   - ret = regmap_update_bits(regmap, reg, mux->mask << mux->shift, val);
  382 + val <<= AM654_SERDES_CTRL_CLKSEL_SHIFT;
  383 + ret = regmap_update_bits(regmap, reg, AM654_SERDES_CTRL_CLKSEL_MASK,
  384 + val);
327 385  
328 386 return ret;
329 387 }
... ... @@ -333,21 +391,6 @@
333 391 .get_parent = serdes_am654_clk_mux_get_parent,
334 392 };
335 393  
336   -static int mux_table[SERDES_NUM_CLOCKS][3] = {
337   - /*
338   - * The entries represent values for selecting between
339   - * {left input, external reference clock, right input}
340   - * Only one of Left Output or Right Output should be used since
341   - * both left and right output clock uses the same bits and modifying
342   - * one clock will impact the other.
343   - */
344   - { BIT(2), 0, BIT(0) }, /* Mux of CMU refclk */
345   - { -1, BIT(3), BIT(1) }, /* Mux of Left Output */
346   - { BIT(1), BIT(3) | BIT(1), -1 }, /* Mux of Right Output */
347   -};
348   -
349   -static int mux_mask[SERDES_NUM_CLOCKS] = { 0x5, 0xa, 0xa };
350   -
351 394 static int serdes_am654_clk_register(struct serdes_am654 *am654_phy,
352 395 const char *clock_name, int clock_num)
353 396 {
354 397  
355 398  
... ... @@ -407,20 +450,11 @@
407 450 init->num_parents = num_parents;
408 451 init->name = clock_name;
409 452  
410   - mux->table = mux_table[clock_num];
411 453 mux->regmap = regmap;
412 454 mux->reg = reg;
413   - mux->shift = 4;
414   - mux->mask = mux_mask[clock_num];
  455 + mux->clk_id = clock_num;
415 456 mux->hw.init = init;
416 457  
417   - /*
418   - * setup a sane default so get_parent() call evaluates
419   - * to a valid parent. Index 1 is the safest choice as
420   - * the default as it is valid value for all of serdes's
421   - * output clocks.
422   - */
423   - serdes_am654_clk_mux_set_parent(&mux->hw, 1);
424 458 clk = devm_clk_register(dev, &mux->hw);
425 459 if (IS_ERR(clk))
426 460 return PTR_ERR(clk);