1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2023 Loongson Technology Corporation Limited
4 */
5
6 #include <linux/delay.h>
7
8 #include <drm/drm_managed.h>
9 #include <drm/drm_print.h>
10
11 #include "lsdc_drv.h"
12
13 /*
14 * The structure of the pixel PLL registers is evolved with times,
15 * it can be different across different chip also.
16 */
17
18 /* size is u64, note that all loongson's cpu is little endian.
19 * This structure is same for ls7a2000, ls7a1000 and ls2k2000.
20 */
21 struct lsdc_pixpll_reg {
22 /* Byte 0 ~ Byte 3 */
23 unsigned div_out : 7; /* 6 : 0 Output clock divider */
24 unsigned _reserved_1_ : 14; /* 20 : 7 */
25 unsigned loopc : 9; /* 29 : 21 Clock multiplier */
26 unsigned _reserved_2_ : 2; /* 31 : 30 */
27
28 /* Byte 4 ~ Byte 7 */
29 unsigned div_ref : 7; /* 38 : 32 Input clock divider */
30 unsigned locked : 1; /* 39 PLL locked indicator */
31 unsigned sel_out : 1; /* 40 output clk selector */
32 unsigned _reserved_3_ : 2; /* 42 : 41 */
33 unsigned set_param : 1; /* 43 Trigger the update */
34 unsigned bypass : 1; /* 44 */
35 unsigned powerdown : 1; /* 45 */
36 unsigned _reserved_4_ : 18; /* 46 : 63 no use */
37 };
38
39 union lsdc_pixpll_reg_bitmap {
40 struct lsdc_pixpll_reg bitmap;
41 u32 w[2];
42 u64 d;
43 };
44
45 struct clk_to_pixpll_parms_lookup_t {
46 unsigned int clock; /* kHz */
47
48 unsigned short width;
49 unsigned short height;
50 unsigned short vrefresh;
51
52 /* Stores parameters for programming the Hardware PLLs */
53 unsigned short div_out;
54 unsigned short loopc;
55 unsigned short div_ref;
56 };
57
58 static const struct clk_to_pixpll_parms_lookup_t pixpll_parms_table[] = {
59 {148500, 1920, 1080, 60, 11, 49, 3}, /* 1920x1080@60Hz */
60 {141750, 1920, 1080, 60, 11, 78, 5}, /* 1920x1080@60Hz */
61 /* 1920x1080@50Hz */
62 {174500, 1920, 1080, 75, 17, 89, 3}, /* 1920x1080@75Hz */
63 {181250, 2560, 1080, 75, 8, 58, 4}, /* 2560x1080@75Hz */
64 {297000, 2560, 1080, 30, 8, 95, 4}, /* 3840x2160@30Hz */
65 {301992, 1920, 1080, 100, 10, 151, 5}, /* 1920x1080@100Hz */
66 {146250, 1680, 1050, 60, 16, 117, 5}, /* 1680x1050@60Hz */
67 {135000, 1280, 1024, 75, 10, 54, 4}, /* 1280x1024@75Hz */
68 {119000, 1680, 1050, 60, 20, 119, 5}, /* 1680x1050@60Hz */
69 {108000, 1600, 900, 60, 15, 81, 5}, /* 1600x900@60Hz */
70 /* 1280x1024@60Hz */
71 /* 1280x960@60Hz */
72 /* 1152x864@75Hz */
73
74 {106500, 1440, 900, 60, 19, 81, 4}, /* 1440x900@60Hz */
75 {88750, 1440, 900, 60, 16, 71, 5}, /* 1440x900@60Hz */
76 {83500, 1280, 800, 60, 17, 71, 5}, /* 1280x800@60Hz */
77 {71000, 1280, 800, 60, 20, 71, 5}, /* 1280x800@60Hz */
78
79 {74250, 1280, 720, 60, 22, 49, 3}, /* 1280x720@60Hz */
80 /* 1280x720@50Hz */
81
82 {78750, 1024, 768, 75, 16, 63, 5}, /* 1024x768@75Hz */
83 {75000, 1024, 768, 70, 29, 87, 4}, /* 1024x768@70Hz */
84 {65000, 1024, 768, 60, 20, 39, 3}, /* 1024x768@60Hz */
85
86 {51200, 1024, 600, 60, 25, 64, 5}, /* 1024x600@60Hz */
87
88 {57284, 832, 624, 75, 24, 55, 4}, /* 832x624@75Hz */
89 {49500, 800, 600, 75, 40, 99, 5}, /* 800x600@75Hz */
90 {50000, 800, 600, 72, 44, 88, 4}, /* 800x600@72Hz */
91 {40000, 800, 600, 60, 30, 36, 3}, /* 800x600@60Hz */
92 {36000, 800, 600, 56, 50, 72, 4}, /* 800x600@56Hz */
93 {31500, 640, 480, 75, 40, 63, 5}, /* 640x480@75Hz */
94 /* 640x480@73Hz */
95
96 {30240, 640, 480, 67, 62, 75, 4}, /* 640x480@67Hz */
97 {27000, 720, 576, 50, 50, 54, 4}, /* 720x576@60Hz */
98 {25175, 640, 480, 60, 85, 107, 5}, /* 640x480@60Hz */
99 {25200, 640, 480, 60, 50, 63, 5}, /* 640x480@60Hz */
100 /* 720x480@60Hz */
101 };
102
lsdc_pixel_pll_free(struct drm_device * ddev,void * data)103 static void lsdc_pixel_pll_free(struct drm_device *ddev, void *data)
104 {
105 struct lsdc_pixpll *this = (struct lsdc_pixpll *)data;
106
107 iounmap(this->mmio);
108
109 kfree(this->priv);
110
111 drm_dbg(ddev, "pixpll private data freed\n");
112 }
113
114 /*
115 * ioremap the device dependent PLL registers
116 *
117 * @this: point to the object where this function is called from
118 */
lsdc_pixel_pll_setup(struct lsdc_pixpll * const this)119 static int lsdc_pixel_pll_setup(struct lsdc_pixpll * const this)
120 {
121 struct lsdc_pixpll_parms *pparms;
122
123 this->mmio = ioremap(this->reg_base, this->reg_size);
124 if (!this->mmio)
125 return -ENOMEM;
126
127 pparms = kzalloc_obj(*pparms);
128 if (!pparms) {
129 iounmap(this->mmio);
130 return -ENOMEM;
131 }
132
133 pparms->ref_clock = LSDC_PLL_REF_CLK_KHZ;
134
135 this->priv = pparms;
136
137 return drmm_add_action_or_reset(this->ddev, lsdc_pixel_pll_free, this);
138 }
139
140 /*
141 * Find a set of pll parameters from a static local table which avoid
142 * computing the pll parameter eachtime a modeset is triggered.
143 *
144 * @this: point to the object where this function is called from
145 * @clock: the desired output pixel clock, the unit is kHz
146 * @pout: point to where the parameters to store if found
147 *
148 * Return 0 if success, return -1 if not found.
149 */
lsdc_pixpll_find(struct lsdc_pixpll * const this,unsigned int clock,struct lsdc_pixpll_parms * pout)150 static int lsdc_pixpll_find(struct lsdc_pixpll * const this,
151 unsigned int clock,
152 struct lsdc_pixpll_parms *pout)
153 {
154 unsigned int num = ARRAY_SIZE(pixpll_parms_table);
155 const struct clk_to_pixpll_parms_lookup_t *pt;
156 unsigned int i;
157
158 for (i = 0; i < num; ++i) {
159 pt = &pixpll_parms_table[i];
160
161 if (clock == pt->clock) {
162 pout->div_ref = pt->div_ref;
163 pout->loopc = pt->loopc;
164 pout->div_out = pt->div_out;
165
166 return 0;
167 }
168 }
169
170 drm_dbg_kms(this->ddev, "pixel clock %u: miss\n", clock);
171
172 return -1;
173 }
174
175 /*
176 * Find a set of pll parameters which have minimal difference with the
177 * desired pixel clock frequency. It does that by computing all of the
178 * possible combination. Compute the diff and find the combination with
179 * minimal diff.
180 *
181 * clock_out = refclk / div_ref * loopc / div_out
182 *
183 * refclk is determined by the oscillator mounted on motherboard(100MHz
184 * in almost all board)
185 *
186 * @this: point to the object from where this function is called
187 * @clock: the desired output pixel clock, the unit is kHz
188 * @pout: point to the out struct of lsdc_pixpll_parms
189 *
190 * Return 0 if a set of parameter is found, otherwise return the error
191 * between clock_kHz we wanted and the most closest candidate with it.
192 */
lsdc_pixel_pll_compute(struct lsdc_pixpll * const this,unsigned int clock,struct lsdc_pixpll_parms * pout)193 static int lsdc_pixel_pll_compute(struct lsdc_pixpll * const this,
194 unsigned int clock,
195 struct lsdc_pixpll_parms *pout)
196 {
197 struct lsdc_pixpll_parms *pparms = this->priv;
198 unsigned int refclk = pparms->ref_clock;
199 const unsigned int tolerance = 1000;
200 unsigned int min = tolerance;
201 unsigned int div_out, loopc, div_ref;
202 unsigned int computed;
203
204 if (!lsdc_pixpll_find(this, clock, pout))
205 return 0;
206
207 for (div_out = 6; div_out < 64; div_out++) {
208 for (div_ref = 3; div_ref < 6; div_ref++) {
209 for (loopc = 6; loopc < 161; loopc++) {
210 unsigned int diff = 0;
211
212 if (loopc < 12 * div_ref)
213 continue;
214 if (loopc > 32 * div_ref)
215 continue;
216
217 computed = refclk / div_ref * loopc / div_out;
218
219 if (clock >= computed)
220 diff = clock - computed;
221 else
222 diff = computed - clock;
223
224 if (diff < min) {
225 min = diff;
226 pparms->div_ref = div_ref;
227 pparms->div_out = div_out;
228 pparms->loopc = loopc;
229
230 if (diff == 0) {
231 *pout = *pparms;
232 return 0;
233 }
234 }
235 }
236 }
237 }
238
239 /* still acceptable */
240 if (min < tolerance) {
241 *pout = *pparms;
242 return 0;
243 }
244
245 drm_dbg(this->ddev, "can't find suitable params for %u khz\n", clock);
246
247 return min;
248 }
249
250 /* Pixel pll hardware related ops, per display pipe */
251
__pixpll_rreg(struct lsdc_pixpll * this,union lsdc_pixpll_reg_bitmap * dst)252 static void __pixpll_rreg(struct lsdc_pixpll *this,
253 union lsdc_pixpll_reg_bitmap *dst)
254 {
255 #if defined(CONFIG_64BIT)
256 dst->d = readq(this->mmio);
257 #else
258 dst->w[0] = readl(this->mmio);
259 dst->w[1] = readl(this->mmio + 4);
260 #endif
261 }
262
__pixpll_wreg(struct lsdc_pixpll * this,union lsdc_pixpll_reg_bitmap * src)263 static void __pixpll_wreg(struct lsdc_pixpll *this,
264 union lsdc_pixpll_reg_bitmap *src)
265 {
266 #if defined(CONFIG_64BIT)
267 writeq(src->d, this->mmio);
268 #else
269 writel(src->w[0], this->mmio);
270 writel(src->w[1], this->mmio + 4);
271 #endif
272 }
273
__pixpll_ops_powerup(struct lsdc_pixpll * const this)274 static void __pixpll_ops_powerup(struct lsdc_pixpll * const this)
275 {
276 union lsdc_pixpll_reg_bitmap pixpll_reg;
277
278 __pixpll_rreg(this, &pixpll_reg);
279
280 pixpll_reg.bitmap.powerdown = 0;
281
282 __pixpll_wreg(this, &pixpll_reg);
283 }
284
__pixpll_ops_powerdown(struct lsdc_pixpll * const this)285 static void __pixpll_ops_powerdown(struct lsdc_pixpll * const this)
286 {
287 union lsdc_pixpll_reg_bitmap pixpll_reg;
288
289 __pixpll_rreg(this, &pixpll_reg);
290
291 pixpll_reg.bitmap.powerdown = 1;
292
293 __pixpll_wreg(this, &pixpll_reg);
294 }
295
__pixpll_ops_on(struct lsdc_pixpll * const this)296 static void __pixpll_ops_on(struct lsdc_pixpll * const this)
297 {
298 union lsdc_pixpll_reg_bitmap pixpll_reg;
299
300 __pixpll_rreg(this, &pixpll_reg);
301
302 pixpll_reg.bitmap.sel_out = 1;
303
304 __pixpll_wreg(this, &pixpll_reg);
305 }
306
__pixpll_ops_off(struct lsdc_pixpll * const this)307 static void __pixpll_ops_off(struct lsdc_pixpll * const this)
308 {
309 union lsdc_pixpll_reg_bitmap pixpll_reg;
310
311 __pixpll_rreg(this, &pixpll_reg);
312
313 pixpll_reg.bitmap.sel_out = 0;
314
315 __pixpll_wreg(this, &pixpll_reg);
316 }
317
__pixpll_ops_bypass(struct lsdc_pixpll * const this)318 static void __pixpll_ops_bypass(struct lsdc_pixpll * const this)
319 {
320 union lsdc_pixpll_reg_bitmap pixpll_reg;
321
322 __pixpll_rreg(this, &pixpll_reg);
323
324 pixpll_reg.bitmap.bypass = 1;
325
326 __pixpll_wreg(this, &pixpll_reg);
327 }
328
__pixpll_ops_unbypass(struct lsdc_pixpll * const this)329 static void __pixpll_ops_unbypass(struct lsdc_pixpll * const this)
330 {
331 union lsdc_pixpll_reg_bitmap pixpll_reg;
332
333 __pixpll_rreg(this, &pixpll_reg);
334
335 pixpll_reg.bitmap.bypass = 0;
336
337 __pixpll_wreg(this, &pixpll_reg);
338 }
339
__pixpll_ops_untoggle_param(struct lsdc_pixpll * const this)340 static void __pixpll_ops_untoggle_param(struct lsdc_pixpll * const this)
341 {
342 union lsdc_pixpll_reg_bitmap pixpll_reg;
343
344 __pixpll_rreg(this, &pixpll_reg);
345
346 pixpll_reg.bitmap.set_param = 0;
347
348 __pixpll_wreg(this, &pixpll_reg);
349 }
350
__pixpll_ops_set_param(struct lsdc_pixpll * const this,struct lsdc_pixpll_parms const * p)351 static void __pixpll_ops_set_param(struct lsdc_pixpll * const this,
352 struct lsdc_pixpll_parms const *p)
353 {
354 union lsdc_pixpll_reg_bitmap pixpll_reg;
355
356 __pixpll_rreg(this, &pixpll_reg);
357
358 pixpll_reg.bitmap.div_ref = p->div_ref;
359 pixpll_reg.bitmap.loopc = p->loopc;
360 pixpll_reg.bitmap.div_out = p->div_out;
361
362 __pixpll_wreg(this, &pixpll_reg);
363 }
364
__pixpll_ops_toggle_param(struct lsdc_pixpll * const this)365 static void __pixpll_ops_toggle_param(struct lsdc_pixpll * const this)
366 {
367 union lsdc_pixpll_reg_bitmap pixpll_reg;
368
369 __pixpll_rreg(this, &pixpll_reg);
370
371 pixpll_reg.bitmap.set_param = 1;
372
373 __pixpll_wreg(this, &pixpll_reg);
374 }
375
__pixpll_ops_wait_locked(struct lsdc_pixpll * const this)376 static void __pixpll_ops_wait_locked(struct lsdc_pixpll * const this)
377 {
378 union lsdc_pixpll_reg_bitmap pixpll_reg;
379 unsigned int counter = 0;
380
381 do {
382 __pixpll_rreg(this, &pixpll_reg);
383
384 if (pixpll_reg.bitmap.locked)
385 break;
386
387 ++counter;
388 } while (counter < 2000);
389
390 drm_dbg(this->ddev, "%u loop waited\n", counter);
391 }
392
393 /*
394 * Update the PLL parameters to the PLL hardware
395 *
396 * @this: point to the object from which this function is called
397 * @pin: point to the struct of lsdc_pixpll_parms passed in
398 *
399 * return 0 if successful.
400 */
lsdc_pixpll_update(struct lsdc_pixpll * const this,struct lsdc_pixpll_parms const * pin)401 static int lsdc_pixpll_update(struct lsdc_pixpll * const this,
402 struct lsdc_pixpll_parms const *pin)
403 {
404 __pixpll_ops_bypass(this);
405
406 __pixpll_ops_off(this);
407
408 __pixpll_ops_powerdown(this);
409
410 __pixpll_ops_toggle_param(this);
411
412 __pixpll_ops_set_param(this, pin);
413
414 __pixpll_ops_untoggle_param(this);
415
416 __pixpll_ops_powerup(this);
417
418 udelay(2);
419
420 __pixpll_ops_wait_locked(this);
421
422 __pixpll_ops_on(this);
423
424 __pixpll_ops_unbypass(this);
425
426 return 0;
427 }
428
lsdc_pixpll_get_freq(struct lsdc_pixpll * const this)429 static unsigned int lsdc_pixpll_get_freq(struct lsdc_pixpll * const this)
430 {
431 struct lsdc_pixpll_parms *ppar = this->priv;
432 union lsdc_pixpll_reg_bitmap pix_pll_reg;
433 unsigned int freq;
434
435 __pixpll_rreg(this, &pix_pll_reg);
436
437 ppar->div_ref = pix_pll_reg.bitmap.div_ref;
438 ppar->loopc = pix_pll_reg.bitmap.loopc;
439 ppar->div_out = pix_pll_reg.bitmap.div_out;
440
441 freq = ppar->ref_clock / ppar->div_ref * ppar->loopc / ppar->div_out;
442
443 return freq;
444 }
445
lsdc_pixpll_print(struct lsdc_pixpll * const this,struct drm_printer * p)446 static void lsdc_pixpll_print(struct lsdc_pixpll * const this,
447 struct drm_printer *p)
448 {
449 struct lsdc_pixpll_parms *parms = this->priv;
450
451 drm_printf(p, "div_ref: %u, loopc: %u, div_out: %u\n",
452 parms->div_ref, parms->loopc, parms->div_out);
453 }
454
455 /*
456 * LS7A1000, LS7A2000 and ls2k2000's pixel pll setting register is same,
457 * we take this as default, create a new instance if a different model is
458 * introduced.
459 */
460 static const struct lsdc_pixpll_funcs __pixpll_default_funcs = {
461 .setup = lsdc_pixel_pll_setup,
462 .compute = lsdc_pixel_pll_compute,
463 .update = lsdc_pixpll_update,
464 .get_rate = lsdc_pixpll_get_freq,
465 .print = lsdc_pixpll_print,
466 };
467
468 /* pixel pll initialization */
469
lsdc_pixpll_init(struct lsdc_pixpll * const this,struct drm_device * ddev,unsigned int index)470 int lsdc_pixpll_init(struct lsdc_pixpll * const this,
471 struct drm_device *ddev,
472 unsigned int index)
473 {
474 struct lsdc_device *ldev = to_lsdc(ddev);
475 const struct lsdc_desc *descp = ldev->descp;
476 const struct loongson_gfx_desc *gfx = to_loongson_gfx(descp);
477
478 this->ddev = ddev;
479 this->reg_size = 8;
480 this->reg_base = gfx->conf_reg_base + gfx->pixpll[index].reg_offset;
481 this->funcs = &__pixpll_default_funcs;
482
483 return this->funcs->setup(this);
484 }
485