Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Roger Quadros and committed by
Kishon Vijay Abraham I
7e7b8ca6 71e2f5c5

+83 -49
+83 -49
drivers/phy/ti/phy-am654-serdes.c
··· 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 ··· 283 282 .owner = THIS_MODULE, 284 283 }; 285 284 285 + #define SERDES_NUM_MUX_COMBINATIONS 16 286 + 287 + #define LICLK 0 288 + #define EXT_REFCLK 1 289 + #define RICLK 2 290 + 291 + static const int 292 + serdes_am654_mux_table[SERDES_NUM_MUX_COMBINATIONS][SERDES_NUM_CLOCKS] = { 293 + /* 294 + * Each combination maps to one of 295 + * "Figure 12-1986. SerDes Reference Clock Distribution" 296 + * in TRM. 297 + */ 298 + /* Parent of CMU refclk, Left output, Right output 299 + * either of EXT_REFCLK, LICLK, RICLK 300 + */ 301 + { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0000 */ 302 + { RICLK, EXT_REFCLK, EXT_REFCLK }, /* 0001 */ 303 + { EXT_REFCLK, RICLK, LICLK }, /* 0010 */ 304 + { RICLK, RICLK, EXT_REFCLK }, /* 0011 */ 305 + { LICLK, EXT_REFCLK, EXT_REFCLK }, /* 0100 */ 306 + { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0101 */ 307 + { LICLK, RICLK, LICLK }, /* 0110 */ 308 + { EXT_REFCLK, RICLK, LICLK }, /* 0111 */ 309 + { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1000 */ 310 + { RICLK, EXT_REFCLK, LICLK }, /* 1001 */ 311 + { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1010 */ 312 + { RICLK, RICLK, EXT_REFCLK }, /* 1011 */ 313 + { LICLK, EXT_REFCLK, LICLK }, /* 1100 */ 314 + { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1101 */ 315 + { LICLK, RICLK, EXT_REFCLK }, /* 1110 */ 316 + { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1111 */ 317 + }; 318 + 286 319 static u8 serdes_am654_clk_mux_get_parent(struct clk_hw *hw) 287 320 { 288 321 struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw); 289 - unsigned int num_parents = clk_hw_get_num_parents(hw); 290 322 struct regmap *regmap = mux->regmap; 291 323 unsigned int reg = mux->reg; 292 324 unsigned int val; 293 - int i; 294 325 295 326 regmap_read(regmap, reg, &val); 296 - val >>= mux->shift; 297 - val &= mux->mask; 327 + val &= AM654_SERDES_CTRL_CLKSEL_MASK; 328 + val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT; 298 329 299 - for (i = 0; i < num_parents; i++) 300 - if (mux->table[i] == val) 301 - return i; 302 - 303 - /* 304 - * No parent? This should never happen! 305 - * Verify if we set a valid parent in serdes_am654_clk_register() 306 - */ 307 - WARN(1, "Failed to find the parent of %s clock\n", hw->init->name); 308 - 309 - /* Make the parent lookup to fail */ 310 - return num_parents; 330 + return serdes_am654_mux_table[val][mux->clk_id]; 311 331 } 312 332 313 333 static int serdes_am654_clk_mux_set_parent(struct clk_hw *hw, u8 index) ··· 336 314 struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw); 337 315 struct regmap *regmap = mux->regmap; 338 316 unsigned int reg = mux->reg; 339 - int val; 317 + int clk_id = mux->clk_id; 318 + int parents[SERDES_NUM_CLOCKS]; 319 + const int *p; 320 + u32 val; 321 + int found, i; 340 322 int ret; 341 323 342 - val = mux->table[index]; 324 + /* get existing setting */ 325 + regmap_read(regmap, reg, &val); 326 + val &= AM654_SERDES_CTRL_CLKSEL_MASK; 327 + val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT; 343 328 344 - if (val == -1) 329 + for (i = 0; i < SERDES_NUM_CLOCKS; i++) 330 + parents[i] = serdes_am654_mux_table[val][i]; 331 + 332 + /* change parent of this clock. others left intact */ 333 + parents[clk_id] = index; 334 + 335 + /* Find the match */ 336 + for (val = 0; val < SERDES_NUM_MUX_COMBINATIONS; val++) { 337 + p = serdes_am654_mux_table[val]; 338 + found = 1; 339 + for (i = 0; i < SERDES_NUM_CLOCKS; i++) { 340 + if (parents[i] != p[i]) { 341 + found = 0; 342 + break; 343 + } 344 + } 345 + 346 + if (found) 347 + break; 348 + } 349 + 350 + if (!found) { 351 + /* 352 + * This can never happen, unless we missed 353 + * a valid combination in serdes_am654_mux_table. 354 + */ 355 + WARN(1, "Failed to find the parent of %s clock\n", 356 + hw->init->name); 345 357 return -EINVAL; 358 + } 346 359 347 - val <<= mux->shift; 348 - ret = regmap_update_bits(regmap, reg, mux->mask << mux->shift, val); 360 + val <<= AM654_SERDES_CTRL_CLKSEL_SHIFT; 361 + ret = regmap_update_bits(regmap, reg, AM654_SERDES_CTRL_CLKSEL_MASK, 362 + val); 349 363 350 364 return ret; 351 365 } ··· 390 332 .set_parent = serdes_am654_clk_mux_set_parent, 391 333 .get_parent = serdes_am654_clk_mux_get_parent, 392 334 }; 393 - 394 - static int mux_table[SERDES_NUM_CLOCKS][3] = { 395 - /* 396 - * The entries represent values for selecting between 397 - * {left input, external reference clock, right input} 398 - * Only one of Left Output or Right Output should be used since 399 - * both left and right output clock uses the same bits and modifying 400 - * one clock will impact the other. 401 - */ 402 - { BIT(2), 0, BIT(0) }, /* Mux of CMU refclk */ 403 - { -1, BIT(3), BIT(1) }, /* Mux of Left Output */ 404 - { BIT(1), BIT(3) | BIT(1), -1 }, /* Mux of Right Output */ 405 - }; 406 - 407 - static int mux_mask[SERDES_NUM_CLOCKS] = { 0x5, 0xa, 0xa }; 408 335 409 336 static int serdes_am654_clk_register(struct serdes_am654 *am654_phy, 410 337 const char *clock_name, int clock_num) ··· 450 407 init->num_parents = num_parents; 451 408 init->name = clock_name; 452 409 453 - mux->table = mux_table[clock_num]; 454 410 mux->regmap = regmap; 455 411 mux->reg = reg; 456 - mux->shift = 4; 457 - mux->mask = mux_mask[clock_num]; 412 + mux->clk_id = clock_num; 458 413 mux->hw.init = init; 459 414 460 - /* 461 - * setup a sane default so get_parent() call evaluates 462 - * to a valid parent. Index 1 is the safest choice as 463 - * the default as it is valid value for all of serdes's 464 - * output clocks. 465 - */ 466 - serdes_am654_clk_mux_set_parent(&mux->hw, 1); 467 415 clk = devm_clk_register(dev, &mux->hw); 468 416 if (IS_ERR(clk)) 469 417 return PTR_ERR(clk);