185397f6bSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only
285397f6bSThomas Zimmermann 
3*877507bbSThomas Zimmermann #include <linux/delay.h>
485397f6bSThomas Zimmermann #include <linux/pci.h>
585397f6bSThomas Zimmermann 
6*877507bbSThomas Zimmermann #include <drm/drm_atomic.h>
785397f6bSThomas Zimmermann #include <drm/drm_drv.h>
885397f6bSThomas Zimmermann 
985397f6bSThomas Zimmermann #include "mgag200_drv.h"
1085397f6bSThomas Zimmermann 
111ee181feSThomas Zimmermann void mgag200_g200eh_init_registers(struct mga_device *mdev)
121ee181feSThomas Zimmermann {
131ee181feSThomas Zimmermann 	static const u8 dacvalue[] = {
141ee181feSThomas Zimmermann 		MGAG200_DAC_DEFAULT(0x00, 0xc9,
151ee181feSThomas Zimmermann 				    MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS,
161ee181feSThomas Zimmermann 				    0x00, 0x00, 0x00)
171ee181feSThomas Zimmermann 	};
181ee181feSThomas Zimmermann 
191ee181feSThomas Zimmermann 	size_t i;
201ee181feSThomas Zimmermann 
211ee181feSThomas Zimmermann 	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
221ee181feSThomas Zimmermann 		if ((i <= 0x17) ||
231ee181feSThomas Zimmermann 		    (i == 0x1b) ||
241ee181feSThomas Zimmermann 		    (i == 0x1c) ||
251ee181feSThomas Zimmermann 		    ((i >= 0x1f) && (i <= 0x29)) ||
261ee181feSThomas Zimmermann 		    ((i >= 0x30) && (i <= 0x37)) ||
271ee181feSThomas Zimmermann 		    ((i >= 0x44) && (i <= 0x4e)))
281ee181feSThomas Zimmermann 			continue;
291ee181feSThomas Zimmermann 		WREG_DAC(i, dacvalue[i]);
301ee181feSThomas Zimmermann 	}
311ee181feSThomas Zimmermann 
321ee181feSThomas Zimmermann 	mgag200_init_registers(mdev);
331ee181feSThomas Zimmermann }
341ee181feSThomas Zimmermann 
3585397f6bSThomas Zimmermann /*
36*877507bbSThomas Zimmermann  * PIXPLLC
37*877507bbSThomas Zimmermann  */
38*877507bbSThomas Zimmermann 
39*877507bbSThomas Zimmermann static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc,
40*877507bbSThomas Zimmermann 					       struct drm_atomic_state *new_state)
41*877507bbSThomas Zimmermann {
42*877507bbSThomas Zimmermann 	static const unsigned int vcomax = 800000;
43*877507bbSThomas Zimmermann 	static const unsigned int vcomin = 400000;
44*877507bbSThomas Zimmermann 	static const unsigned int pllreffreq = 33333;
45*877507bbSThomas Zimmermann 
46*877507bbSThomas Zimmermann 	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
47*877507bbSThomas Zimmermann 	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
48*877507bbSThomas Zimmermann 	long clock = new_crtc_state->mode.clock;
49*877507bbSThomas Zimmermann 	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
50*877507bbSThomas Zimmermann 	unsigned int delta, tmpdelta;
51*877507bbSThomas Zimmermann 	unsigned int testp, testm, testn;
52*877507bbSThomas Zimmermann 	unsigned int p, m, n, s;
53*877507bbSThomas Zimmermann 	unsigned int computed;
54*877507bbSThomas Zimmermann 
55*877507bbSThomas Zimmermann 	m = n = p = s = 0;
56*877507bbSThomas Zimmermann 	delta = 0xffffffff;
57*877507bbSThomas Zimmermann 
58*877507bbSThomas Zimmermann 	for (testp = 16; testp > 0; testp >>= 1) {
59*877507bbSThomas Zimmermann 		if (clock * testp > vcomax)
60*877507bbSThomas Zimmermann 			continue;
61*877507bbSThomas Zimmermann 		if (clock * testp < vcomin)
62*877507bbSThomas Zimmermann 			continue;
63*877507bbSThomas Zimmermann 
64*877507bbSThomas Zimmermann 		for (testm = 1; testm < 33; testm++) {
65*877507bbSThomas Zimmermann 			for (testn = 17; testn < 257; testn++) {
66*877507bbSThomas Zimmermann 				computed = (pllreffreq * testn) / (testm * testp);
67*877507bbSThomas Zimmermann 				if (computed > clock)
68*877507bbSThomas Zimmermann 					tmpdelta = computed - clock;
69*877507bbSThomas Zimmermann 				else
70*877507bbSThomas Zimmermann 					tmpdelta = clock - computed;
71*877507bbSThomas Zimmermann 				if (tmpdelta < delta) {
72*877507bbSThomas Zimmermann 					delta = tmpdelta;
73*877507bbSThomas Zimmermann 					n = testn;
74*877507bbSThomas Zimmermann 					m = testm;
75*877507bbSThomas Zimmermann 					p = testp;
76*877507bbSThomas Zimmermann 				}
77*877507bbSThomas Zimmermann 			}
78*877507bbSThomas Zimmermann 		}
79*877507bbSThomas Zimmermann 	}
80*877507bbSThomas Zimmermann 
81*877507bbSThomas Zimmermann 	pixpllc->m = m;
82*877507bbSThomas Zimmermann 	pixpllc->n = n;
83*877507bbSThomas Zimmermann 	pixpllc->p = p;
84*877507bbSThomas Zimmermann 	pixpllc->s = s;
85*877507bbSThomas Zimmermann 
86*877507bbSThomas Zimmermann 	return 0;
87*877507bbSThomas Zimmermann }
88*877507bbSThomas Zimmermann 
89*877507bbSThomas Zimmermann void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc,
90*877507bbSThomas Zimmermann 					  struct drm_atomic_state *old_state)
91*877507bbSThomas Zimmermann {
92*877507bbSThomas Zimmermann 	struct drm_device *dev = crtc->dev;
93*877507bbSThomas Zimmermann 	struct mga_device *mdev = to_mga_device(dev);
94*877507bbSThomas Zimmermann 	struct drm_crtc_state *crtc_state = crtc->state;
95*877507bbSThomas Zimmermann 	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
96*877507bbSThomas Zimmermann 	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
97*877507bbSThomas Zimmermann 	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
98*877507bbSThomas Zimmermann 	u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
99*877507bbSThomas Zimmermann 	int i, j, tmpcount, vcount;
100*877507bbSThomas Zimmermann 	bool pll_locked = false;
101*877507bbSThomas Zimmermann 
102*877507bbSThomas Zimmermann 	pixpllcm = pixpllc->m - 1;
103*877507bbSThomas Zimmermann 	pixpllcn = pixpllc->n - 1;
104*877507bbSThomas Zimmermann 	pixpllcp = pixpllc->p - 1;
105*877507bbSThomas Zimmermann 	pixpllcs = pixpllc->s;
106*877507bbSThomas Zimmermann 
107*877507bbSThomas Zimmermann 	xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
108*877507bbSThomas Zimmermann 	xpixpllcn = pixpllcn;
109*877507bbSThomas Zimmermann 	xpixpllcp = (pixpllcs << 3) | pixpllcp;
110*877507bbSThomas Zimmermann 
111*877507bbSThomas Zimmermann 	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
112*877507bbSThomas Zimmermann 
113*877507bbSThomas Zimmermann 	for (i = 0; i <= 32 && pll_locked == false; i++) {
114*877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
115*877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
116*877507bbSThomas Zimmermann 		tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
117*877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
118*877507bbSThomas Zimmermann 
119*877507bbSThomas Zimmermann 		tmp = RREG8(MGAREG_MEM_MISC_READ);
120*877507bbSThomas Zimmermann 		tmp |= 0x3 << 2;
121*877507bbSThomas Zimmermann 		WREG8(MGAREG_MEM_MISC_WRITE, tmp);
122*877507bbSThomas Zimmermann 
123*877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
124*877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
125*877507bbSThomas Zimmermann 		tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
126*877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
127*877507bbSThomas Zimmermann 
128*877507bbSThomas Zimmermann 		udelay(500);
129*877507bbSThomas Zimmermann 
130*877507bbSThomas Zimmermann 		WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
131*877507bbSThomas Zimmermann 		WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
132*877507bbSThomas Zimmermann 		WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
133*877507bbSThomas Zimmermann 
134*877507bbSThomas Zimmermann 		udelay(500);
135*877507bbSThomas Zimmermann 
136*877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
137*877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
138*877507bbSThomas Zimmermann 		tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
139*877507bbSThomas Zimmermann 		tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
140*877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
141*877507bbSThomas Zimmermann 
142*877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
143*877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
144*877507bbSThomas Zimmermann 		tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
145*877507bbSThomas Zimmermann 		tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
146*877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
147*877507bbSThomas Zimmermann 
148*877507bbSThomas Zimmermann 		vcount = RREG8(MGAREG_VCOUNT);
149*877507bbSThomas Zimmermann 
150*877507bbSThomas Zimmermann 		for (j = 0; j < 30 && pll_locked == false; j++) {
151*877507bbSThomas Zimmermann 			tmpcount = RREG8(MGAREG_VCOUNT);
152*877507bbSThomas Zimmermann 			if (tmpcount < vcount)
153*877507bbSThomas Zimmermann 				vcount = 0;
154*877507bbSThomas Zimmermann 			if ((tmpcount - vcount) > 2)
155*877507bbSThomas Zimmermann 				pll_locked = true;
156*877507bbSThomas Zimmermann 			else
157*877507bbSThomas Zimmermann 				udelay(5);
158*877507bbSThomas Zimmermann 		}
159*877507bbSThomas Zimmermann 	}
160*877507bbSThomas Zimmermann }
161*877507bbSThomas Zimmermann 
162*877507bbSThomas Zimmermann /*
16385397f6bSThomas Zimmermann  * DRM device
16485397f6bSThomas Zimmermann  */
16585397f6bSThomas Zimmermann 
166b9a577a4SThomas Zimmermann static const struct mgag200_device_info mgag200_g200eh_device_info =
167da1efdb2SThomas Zimmermann 	MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false);
168b9a577a4SThomas Zimmermann 
169f639f74aSThomas Zimmermann static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = {
170*877507bbSThomas Zimmermann 	.pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check,
171*877507bbSThomas Zimmermann 	.pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update,
172f639f74aSThomas Zimmermann };
173f639f74aSThomas Zimmermann 
17485397f6bSThomas Zimmermann struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
17521e74bf9SThomas Zimmermann 						enum mga_type type)
17685397f6bSThomas Zimmermann {
17785397f6bSThomas Zimmermann 	struct mga_device *mdev;
17885397f6bSThomas Zimmermann 	struct drm_device *dev;
179d45e32c9SThomas Zimmermann 	resource_size_t vram_available;
18085397f6bSThomas Zimmermann 	int ret;
18185397f6bSThomas Zimmermann 
18285397f6bSThomas Zimmermann 	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
18385397f6bSThomas Zimmermann 	if (IS_ERR(mdev))
18485397f6bSThomas Zimmermann 		return mdev;
18585397f6bSThomas Zimmermann 	dev = &mdev->base;
18685397f6bSThomas Zimmermann 
18785397f6bSThomas Zimmermann 	pci_set_drvdata(pdev, dev);
18885397f6bSThomas Zimmermann 
189ce19021fSThomas Zimmermann 	ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000);
190ce19021fSThomas Zimmermann 	if (ret)
191ce19021fSThomas Zimmermann 		return ERR_PTR(ret);
192ce19021fSThomas Zimmermann 
193b62d943eSThomas Zimmermann 	ret = mgag200_device_preinit(mdev);
19485397f6bSThomas Zimmermann 	if (ret)
19585397f6bSThomas Zimmermann 		return ERR_PTR(ret);
19685397f6bSThomas Zimmermann 
197f639f74aSThomas Zimmermann 	ret = mgag200_device_init(mdev, type, &mgag200_g200eh_device_info,
198f639f74aSThomas Zimmermann 				  &mgag200_g200eh_device_funcs);
19985397f6bSThomas Zimmermann 	if (ret)
20085397f6bSThomas Zimmermann 		return ERR_PTR(ret);
20185397f6bSThomas Zimmermann 
2021ee181feSThomas Zimmermann 	mgag200_g200eh_init_registers(mdev);
2031ee181feSThomas Zimmermann 
204d45e32c9SThomas Zimmermann 	vram_available = mgag200_device_probe_vram(mdev);
205d45e32c9SThomas Zimmermann 
206d45e32c9SThomas Zimmermann 	ret = mgag200_modeset_init(mdev, vram_available);
20785397f6bSThomas Zimmermann 	if (ret)
20885397f6bSThomas Zimmermann 		return ERR_PTR(ret);
20985397f6bSThomas Zimmermann 
21085397f6bSThomas Zimmermann 	return mdev;
21185397f6bSThomas Zimmermann }
212