File Index
Files and directories
Sign in
FILE

mgag200_g200eh.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/mgag200/mgag200_g200eh.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include <linux/delay.h>
  4#include <linux/pci.h>
  5
  6#include <drm/drm_atomic.h>
  7#include <drm/drm_atomic_helper.h>
  8#include <drm/drm_drv.h>
  9#include <drm/drm_gem_atomic_helper.h>
 10#include <drm/drm_print.h>
 11#include <drm/drm_probe_helper.h>
 12
 13#include "mgag200_drv.h"
 14
 15void mgag200_g200eh_init_registers(struct mga_device *mdev)
 16{
 17	static const u8 dacvalue[] = {
 18		MGAG200_DAC_DEFAULT(0x00, 0xc9,
 19				    MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS,
 20				    0x00, 0x00, 0x00)
 21	};
 22
 23	size_t i;
 24
 25	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
 26		if ((i <= 0x17) ||
 27		    (i == 0x1b) ||
 28		    (i == 0x1c) ||
 29		    ((i >= 0x1f) && (i <= 0x29)) ||
 30		    ((i >= 0x30) && (i <= 0x37)) ||
 31		    ((i >= 0x44) && (i <= 0x4e)))
 32			continue;
 33		WREG_DAC(i, dacvalue[i]);
 34	}
 35
 36	mgag200_init_registers(mdev);
 37}
 38
 39/*
 40 * PIXPLLC
 41 */
 42
 43static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc,
 44					       struct drm_atomic_state *new_state)
 45{
 46	static const unsigned int vcomax = 800000;
 47	static const unsigned int vcomin = 400000;
 48	static const unsigned int pllreffreq = 33333;
 49
 50	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
 51	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
 52	long clock = new_crtc_state->mode.clock;
 53	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
 54	unsigned int delta, tmpdelta;
 55	unsigned int testp, testm, testn;
 56	unsigned int p, m, n, s;
 57	unsigned int computed;
 58
 59	m = n = p = s = 0;
 60	delta = 0xffffffff;
 61
 62	for (testp = 16; testp > 0; testp >>= 1) {
 63		if (clock * testp > vcomax)
 64			continue;
 65		if (clock * testp < vcomin)
 66			continue;
 67
 68		for (testm = 1; testm < 33; testm++) {
 69			for (testn = 17; testn < 257; testn++) {
 70				computed = (pllreffreq * testn) / (testm * testp);
 71				if (computed > clock)
 72					tmpdelta = computed - clock;
 73				else
 74					tmpdelta = clock - computed;
 75				if (tmpdelta < delta) {
 76					delta = tmpdelta;
 77					n = testn;
 78					m = testm;
 79					p = testp;
 80				}
 81			}
 82		}
 83	}
 84
 85	pixpllc->m = m;
 86	pixpllc->n = n;
 87	pixpllc->p = p;
 88	pixpllc->s = s;
 89
 90	return 0;
 91}
 92
 93void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc,
 94					  struct drm_atomic_state *old_state)
 95{
 96	struct drm_device *dev = crtc->dev;
 97	struct mga_device *mdev = to_mga_device(dev);
 98	struct drm_crtc_state *crtc_state = crtc->state;
 99	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
100	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
101	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
102	u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
103	int i, j, tmpcount, vcount;
104	bool pll_locked = false;
105
106	pixpllcm = pixpllc->m - 1;
107	pixpllcn = pixpllc->n - 1;
108	pixpllcp = pixpllc->p - 1;
109	pixpllcs = pixpllc->s;
110
111	xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
112	xpixpllcn = pixpllcn;
113	xpixpllcp = (pixpllcs << 3) | pixpllcp;
114
115	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
116
117	for (i = 0; i <= 32 && pll_locked == false; i++) {
118		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
119		tmp = RREG8(DAC_DATA);
120		tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
121		WREG8(DAC_DATA, tmp);
122
123		tmp = RREG8(MGAREG_MEM_MISC_READ);
124		tmp |= 0x3 << 2;
125		WREG8(MGAREG_MEM_MISC_WRITE, tmp);
126
127		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
128		tmp = RREG8(DAC_DATA);
129		tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
130		WREG8(DAC_DATA, tmp);
131
132		udelay(500);
133
134		WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
135		WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
136		WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
137
138		udelay(500);
139
140		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
141		tmp = RREG8(DAC_DATA);
142		tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
143		tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
144		WREG8(DAC_DATA, tmp);
145
146		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
147		tmp = RREG8(DAC_DATA);
148		tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
149		tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
150		WREG8(DAC_DATA, tmp);
151
152		vcount = RREG8(MGAREG_VCOUNT);
153
154		for (j = 0; j < 30 && pll_locked == false; j++) {
155			tmpcount = RREG8(MGAREG_VCOUNT);
156			if (tmpcount < vcount)
157				vcount = 0;
158			if ((tmpcount - vcount) > 2)
159				pll_locked = true;
160			else
161				udelay(5);
162		}
163	}
164}
165
166/*
167 * Mode-setting pipeline
168 */
169
170static const struct drm_plane_helper_funcs mgag200_g200eh_primary_plane_helper_funcs = {
171	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
172};
173
174static const struct drm_plane_funcs mgag200_g200eh_primary_plane_funcs = {
175	MGAG200_PRIMARY_PLANE_FUNCS,
176};
177
178static const struct drm_crtc_helper_funcs mgag200_g200eh_crtc_helper_funcs = {
179	MGAG200_CRTC_HELPER_FUNCS,
180};
181
182static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = {
183	MGAG200_CRTC_FUNCS,
184};
185
186static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
187{
188	struct drm_device *dev = &mdev->base;
189	struct drm_plane *primary_plane = &mdev->primary_plane;
190	struct drm_crtc *crtc = &mdev->crtc;
191	int ret;
192
193	ret = drm_universal_plane_init(dev, primary_plane, 0,
194				       &mgag200_g200eh_primary_plane_funcs,
195				       mgag200_primary_plane_formats,
196				       mgag200_primary_plane_formats_size,
197				       mgag200_primary_plane_fmtmods,
198				       DRM_PLANE_TYPE_PRIMARY, NULL);
199	if (ret) {
200		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
201		return ret;
202	}
203	drm_plane_helper_add(primary_plane, &mgag200_g200eh_primary_plane_helper_funcs);
204	drm_plane_enable_fb_damage_clips(primary_plane);
205
206	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
207					&mgag200_g200eh_crtc_funcs, NULL);
208	if (ret) {
209		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
210		return ret;
211	}
212	drm_crtc_helper_add(crtc, &mgag200_g200eh_crtc_helper_funcs);
213
214	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
215	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
216	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
217
218	ret = mgag200_vga_bmc_output_init(mdev);
219	if (ret)
220		return ret;
221
222	return 0;
223}
224
225/*
226 * DRM device
227 */
228
229static const struct mgag200_device_info mgag200_g200eh_device_info =
230	MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false);
231
232static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = {
233	.pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check,
234	.pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update,
235};
236
237struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
238{
239	struct mga_device *mdev;
240	struct drm_device *dev;
241	resource_size_t vram_available;
242	int ret;
243
244	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
245	if (IS_ERR(mdev))
246		return mdev;
247	dev = &mdev->base;
248
249	pci_set_drvdata(pdev, dev);
250
251	ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000);
252	if (ret)
253		return ERR_PTR(ret);
254
255	ret = mgag200_device_preinit(mdev);
256	if (ret)
257		return ERR_PTR(ret);
258
259	ret = mgag200_device_init(mdev, &mgag200_g200eh_device_info,
260				  &mgag200_g200eh_device_funcs);
261	if (ret)
262		return ERR_PTR(ret);
263
264	mgag200_g200eh_init_registers(mdev);
265
266	vram_available = mgag200_device_probe_vram(mdev);
267
268	ret = mgag200_mode_config_init(mdev, vram_available);
269	if (ret)
270		return ERR_PTR(ret);
271
272	ret = mgag200_g200eh_pipeline_init(mdev);
273	if (ret)
274		return ERR_PTR(ret);
275
276	drm_mode_config_reset(dev);
277	drm_kms_helper_poll_init(dev);
278
279	return mdev;
280}
~/ Read-only file preview.