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