185397f6bSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only
285397f6bSThomas Zimmermann 
3877507bbSThomas Zimmermann #include <linux/delay.h>
485397f6bSThomas Zimmermann #include <linux/pci.h>
585397f6bSThomas Zimmermann 
6877507bbSThomas Zimmermann #include <drm/drm_atomic.h>
7bc835040SThomas Zimmermann #include <drm/drm_atomic_helper.h>
885397f6bSThomas Zimmermann #include <drm/drm_drv.h>
9bc835040SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
10bc835040SThomas Zimmermann #include <drm/drm_probe_helper.h>
1185397f6bSThomas Zimmermann 
1285397f6bSThomas Zimmermann #include "mgag200_drv.h"
1385397f6bSThomas Zimmermann 
mgag200_g200wb_init_registers(struct mga_device * mdev)141ee181feSThomas Zimmermann void mgag200_g200wb_init_registers(struct mga_device *mdev)
151ee181feSThomas Zimmermann {
161ee181feSThomas Zimmermann 	static const u8 dacvalue[] = {
171ee181feSThomas Zimmermann 		MGAG200_DAC_DEFAULT(0x07, 0xc9, 0x1f, 0x00, 0x00, 0x00)
181ee181feSThomas Zimmermann 	};
191ee181feSThomas Zimmermann 
201ee181feSThomas Zimmermann 	size_t i;
211ee181feSThomas Zimmermann 
221ee181feSThomas Zimmermann 	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
231ee181feSThomas Zimmermann 		if ((i <= 0x17) ||
241ee181feSThomas Zimmermann 		    (i == 0x1b) ||
251ee181feSThomas Zimmermann 		    (i == 0x1c) ||
261ee181feSThomas Zimmermann 		    ((i >= 0x1f) && (i <= 0x29)) ||
271ee181feSThomas Zimmermann 		    ((i >= 0x30) && (i <= 0x37)) ||
281ee181feSThomas Zimmermann 		    ((i >= 0x44) && (i <= 0x4e)))
291ee181feSThomas Zimmermann 			continue;
301ee181feSThomas Zimmermann 		WREG_DAC(i, dacvalue[i]);
311ee181feSThomas Zimmermann 	}
321ee181feSThomas Zimmermann 
331ee181feSThomas Zimmermann 	mgag200_init_registers(mdev);
341ee181feSThomas Zimmermann }
351ee181feSThomas Zimmermann 
3685397f6bSThomas Zimmermann /*
37877507bbSThomas Zimmermann  * PIXPLLC
38877507bbSThomas Zimmermann  */
39877507bbSThomas Zimmermann 
mgag200_g200wb_pixpllc_atomic_check(struct drm_crtc * crtc,struct drm_atomic_state * new_state)40877507bbSThomas Zimmermann static int mgag200_g200wb_pixpllc_atomic_check(struct drm_crtc *crtc,
41877507bbSThomas Zimmermann 					       struct drm_atomic_state *new_state)
42877507bbSThomas Zimmermann {
43877507bbSThomas Zimmermann 	static const unsigned int vcomax = 550000;
44877507bbSThomas Zimmermann 	static const unsigned int vcomin = 150000;
45877507bbSThomas Zimmermann 	static const unsigned int pllreffreq = 48000;
46877507bbSThomas Zimmermann 
47877507bbSThomas Zimmermann 	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
48877507bbSThomas Zimmermann 	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
49877507bbSThomas Zimmermann 	long clock = new_crtc_state->mode.clock;
50877507bbSThomas Zimmermann 	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
51877507bbSThomas Zimmermann 	unsigned int delta, tmpdelta;
52877507bbSThomas Zimmermann 	unsigned int testp, testm, testn;
53877507bbSThomas Zimmermann 	unsigned int p, m, n, s;
54877507bbSThomas Zimmermann 	unsigned int computed;
55877507bbSThomas Zimmermann 
56877507bbSThomas Zimmermann 	m = n = p = s = 0;
57877507bbSThomas Zimmermann 	delta = 0xffffffff;
58877507bbSThomas Zimmermann 
59877507bbSThomas Zimmermann 	for (testp = 1; testp < 9; testp++) {
60877507bbSThomas Zimmermann 		if (clock * testp > vcomax)
61877507bbSThomas Zimmermann 			continue;
62877507bbSThomas Zimmermann 		if (clock * testp < vcomin)
63877507bbSThomas Zimmermann 			continue;
64877507bbSThomas Zimmermann 
65877507bbSThomas Zimmermann 		for (testm = 1; testm < 17; testm++) {
66877507bbSThomas Zimmermann 			for (testn = 1; testn < 151; testn++) {
67877507bbSThomas Zimmermann 				computed = (pllreffreq * testn) / (testm * testp);
68877507bbSThomas Zimmermann 				if (computed > clock)
69877507bbSThomas Zimmermann 					tmpdelta = computed - clock;
70877507bbSThomas Zimmermann 				else
71877507bbSThomas Zimmermann 					tmpdelta = clock - computed;
72877507bbSThomas Zimmermann 				if (tmpdelta < delta) {
73877507bbSThomas Zimmermann 					delta = tmpdelta;
74877507bbSThomas Zimmermann 					n = testn;
75877507bbSThomas Zimmermann 					m = testm;
76877507bbSThomas Zimmermann 					p = testp;
77877507bbSThomas Zimmermann 					s = 0;
78877507bbSThomas Zimmermann 				}
79877507bbSThomas Zimmermann 			}
80877507bbSThomas Zimmermann 		}
81877507bbSThomas Zimmermann 	}
82877507bbSThomas Zimmermann 
83877507bbSThomas Zimmermann 	pixpllc->m = m;
84877507bbSThomas Zimmermann 	pixpllc->n = n;
85877507bbSThomas Zimmermann 	pixpllc->p = p;
86877507bbSThomas Zimmermann 	pixpllc->s = s;
87877507bbSThomas Zimmermann 
88877507bbSThomas Zimmermann 	return 0;
89877507bbSThomas Zimmermann }
90877507bbSThomas Zimmermann 
mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc * crtc,struct drm_atomic_state * old_state)91877507bbSThomas Zimmermann void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc,
92877507bbSThomas Zimmermann 					  struct drm_atomic_state *old_state)
93877507bbSThomas Zimmermann {
94877507bbSThomas Zimmermann 	struct drm_device *dev = crtc->dev;
95877507bbSThomas Zimmermann 	struct mga_device *mdev = to_mga_device(dev);
96877507bbSThomas Zimmermann 	struct drm_crtc_state *crtc_state = crtc->state;
97877507bbSThomas Zimmermann 	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
98877507bbSThomas Zimmermann 	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
99877507bbSThomas Zimmermann 	bool pll_locked = false;
100877507bbSThomas Zimmermann 	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
101877507bbSThomas Zimmermann 	u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
102877507bbSThomas Zimmermann 	int i, j, tmpcount, vcount;
103877507bbSThomas Zimmermann 
104877507bbSThomas Zimmermann 	pixpllcm = pixpllc->m - 1;
105877507bbSThomas Zimmermann 	pixpllcn = pixpllc->n - 1;
106877507bbSThomas Zimmermann 	pixpllcp = pixpllc->p - 1;
107877507bbSThomas Zimmermann 	pixpllcs = pixpllc->s;
108877507bbSThomas Zimmermann 
109877507bbSThomas Zimmermann 	xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
110877507bbSThomas Zimmermann 	xpixpllcn = pixpllcn;
111877507bbSThomas Zimmermann 	xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
112877507bbSThomas Zimmermann 
113877507bbSThomas Zimmermann 	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
114877507bbSThomas Zimmermann 
115877507bbSThomas Zimmermann 	for (i = 0; i <= 32 && pll_locked == false; i++) {
116877507bbSThomas Zimmermann 		if (i > 0) {
117877507bbSThomas Zimmermann 			WREG8(MGAREG_CRTC_INDEX, 0x1e);
118877507bbSThomas Zimmermann 			tmp = RREG8(MGAREG_CRTC_DATA);
119877507bbSThomas Zimmermann 			if (tmp < 0xff)
120877507bbSThomas Zimmermann 				WREG8(MGAREG_CRTC_DATA, tmp+1);
121877507bbSThomas Zimmermann 		}
122877507bbSThomas Zimmermann 
123877507bbSThomas Zimmermann 		/* set pixclkdis to 1 */
124877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
125877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
126877507bbSThomas Zimmermann 		tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
127877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
128877507bbSThomas Zimmermann 
129877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
130877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
131877507bbSThomas Zimmermann 		tmp |= MGA1064_REMHEADCTL_CLKDIS;
132877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
133877507bbSThomas Zimmermann 
134877507bbSThomas Zimmermann 		/* select PLL Set C */
135877507bbSThomas Zimmermann 		tmp = RREG8(MGAREG_MEM_MISC_READ);
136877507bbSThomas Zimmermann 		tmp |= 0x3 << 2;
137877507bbSThomas Zimmermann 		WREG8(MGAREG_MEM_MISC_WRITE, tmp);
138877507bbSThomas Zimmermann 
139877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
140877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
141877507bbSThomas Zimmermann 		tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
142877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
143877507bbSThomas Zimmermann 
144877507bbSThomas Zimmermann 		udelay(500);
145877507bbSThomas Zimmermann 
146877507bbSThomas Zimmermann 		/* reset the PLL */
147877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_VREF_CTL);
148877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
149877507bbSThomas Zimmermann 		tmp &= ~0x04;
150877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
151877507bbSThomas Zimmermann 
152877507bbSThomas Zimmermann 		udelay(50);
153877507bbSThomas Zimmermann 
154877507bbSThomas Zimmermann 		/* program pixel pll register */
155877507bbSThomas Zimmermann 		WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
156877507bbSThomas Zimmermann 		WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
157877507bbSThomas Zimmermann 		WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
158877507bbSThomas Zimmermann 
159877507bbSThomas Zimmermann 		udelay(50);
160877507bbSThomas Zimmermann 
161877507bbSThomas Zimmermann 		/* turn pll on */
162877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_VREF_CTL);
163877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
164877507bbSThomas Zimmermann 		tmp |= 0x04;
165877507bbSThomas Zimmermann 		WREG_DAC(MGA1064_VREF_CTL, tmp);
166877507bbSThomas Zimmermann 
167877507bbSThomas Zimmermann 		udelay(500);
168877507bbSThomas Zimmermann 
169877507bbSThomas Zimmermann 		/* select the pixel pll */
170877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
171877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
172877507bbSThomas Zimmermann 		tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
173877507bbSThomas Zimmermann 		tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
174877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
175877507bbSThomas Zimmermann 
176877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
177877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
178877507bbSThomas Zimmermann 		tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
179877507bbSThomas Zimmermann 		tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
180877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
181877507bbSThomas Zimmermann 
182877507bbSThomas Zimmermann 		/* reset dotclock rate bit */
183877507bbSThomas Zimmermann 		WREG8(MGAREG_SEQ_INDEX, 1);
184877507bbSThomas Zimmermann 		tmp = RREG8(MGAREG_SEQ_DATA);
185877507bbSThomas Zimmermann 		tmp &= ~0x8;
186877507bbSThomas Zimmermann 		WREG8(MGAREG_SEQ_DATA, tmp);
187877507bbSThomas Zimmermann 
188877507bbSThomas Zimmermann 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
189877507bbSThomas Zimmermann 		tmp = RREG8(DAC_DATA);
190877507bbSThomas Zimmermann 		tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
191877507bbSThomas Zimmermann 		WREG8(DAC_DATA, tmp);
192877507bbSThomas Zimmermann 
193877507bbSThomas Zimmermann 		vcount = RREG8(MGAREG_VCOUNT);
194877507bbSThomas Zimmermann 
195877507bbSThomas Zimmermann 		for (j = 0; j < 30 && pll_locked == false; j++) {
196877507bbSThomas Zimmermann 			tmpcount = RREG8(MGAREG_VCOUNT);
197877507bbSThomas Zimmermann 			if (tmpcount < vcount)
198877507bbSThomas Zimmermann 				vcount = 0;
199877507bbSThomas Zimmermann 			if ((tmpcount - vcount) > 2)
200877507bbSThomas Zimmermann 				pll_locked = true;
201877507bbSThomas Zimmermann 			else
202877507bbSThomas Zimmermann 				udelay(5);
203877507bbSThomas Zimmermann 		}
204877507bbSThomas Zimmermann 	}
205877507bbSThomas Zimmermann 
206877507bbSThomas Zimmermann 	WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
207877507bbSThomas Zimmermann 	tmp = RREG8(DAC_DATA);
208877507bbSThomas Zimmermann 	tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
209877507bbSThomas Zimmermann 	WREG_DAC(MGA1064_REMHEADCTL, tmp);
210877507bbSThomas Zimmermann }
211877507bbSThomas Zimmermann 
212877507bbSThomas Zimmermann /*
213bc835040SThomas Zimmermann  * Mode-setting pipeline
214bc835040SThomas Zimmermann  */
215bc835040SThomas Zimmermann 
216bc835040SThomas Zimmermann static const struct drm_plane_helper_funcs mgag200_g200wb_primary_plane_helper_funcs = {
217bc835040SThomas Zimmermann 	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
218bc835040SThomas Zimmermann };
219bc835040SThomas Zimmermann 
220bc835040SThomas Zimmermann static const struct drm_plane_funcs mgag200_g200wb_primary_plane_funcs = {
221bc835040SThomas Zimmermann 	MGAG200_PRIMARY_PLANE_FUNCS,
222bc835040SThomas Zimmermann };
223bc835040SThomas Zimmermann 
224bc835040SThomas Zimmermann static const struct drm_crtc_helper_funcs mgag200_g200wb_crtc_helper_funcs = {
225bc835040SThomas Zimmermann 	MGAG200_CRTC_HELPER_FUNCS,
226bc835040SThomas Zimmermann };
227bc835040SThomas Zimmermann 
228bc835040SThomas Zimmermann static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = {
229bc835040SThomas Zimmermann 	MGAG200_CRTC_FUNCS,
230bc835040SThomas Zimmermann };
231bc835040SThomas Zimmermann 
232bc835040SThomas Zimmermann static const struct drm_encoder_funcs mgag200_g200wb_dac_encoder_funcs = {
233bc835040SThomas Zimmermann 	MGAG200_DAC_ENCODER_FUNCS,
234bc835040SThomas Zimmermann };
235bc835040SThomas Zimmermann 
236bc835040SThomas Zimmermann static const struct drm_connector_helper_funcs mgag200_g200wb_vga_connector_helper_funcs = {
237bc835040SThomas Zimmermann 	MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
238bc835040SThomas Zimmermann };
239bc835040SThomas Zimmermann 
240bc835040SThomas Zimmermann static const struct drm_connector_funcs mgag200_g200wb_vga_connector_funcs = {
241bc835040SThomas Zimmermann 	MGAG200_VGA_CONNECTOR_FUNCS,
242bc835040SThomas Zimmermann };
243bc835040SThomas Zimmermann 
mgag200_g200wb_pipeline_init(struct mga_device * mdev)244bc835040SThomas Zimmermann static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
245bc835040SThomas Zimmermann {
246bc835040SThomas Zimmermann 	struct drm_device *dev = &mdev->base;
247bc835040SThomas Zimmermann 	struct drm_plane *primary_plane = &mdev->primary_plane;
248bc835040SThomas Zimmermann 	struct drm_crtc *crtc = &mdev->crtc;
249bc835040SThomas Zimmermann 	struct drm_encoder *encoder = &mdev->encoder;
250bc835040SThomas Zimmermann 	struct mga_i2c_chan *i2c = &mdev->i2c;
251bc835040SThomas Zimmermann 	struct drm_connector *connector = &mdev->connector;
252bc835040SThomas Zimmermann 	int ret;
253bc835040SThomas Zimmermann 
254bc835040SThomas Zimmermann 	ret = drm_universal_plane_init(dev, primary_plane, 0,
255bc835040SThomas Zimmermann 				       &mgag200_g200wb_primary_plane_funcs,
256bc835040SThomas Zimmermann 				       mgag200_primary_plane_formats,
257bc835040SThomas Zimmermann 				       mgag200_primary_plane_formats_size,
258bc835040SThomas Zimmermann 				       mgag200_primary_plane_fmtmods,
259bc835040SThomas Zimmermann 				       DRM_PLANE_TYPE_PRIMARY, NULL);
260bc835040SThomas Zimmermann 	if (ret) {
261bc835040SThomas Zimmermann 		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
262bc835040SThomas Zimmermann 		return ret;
263bc835040SThomas Zimmermann 	}
264bc835040SThomas Zimmermann 	drm_plane_helper_add(primary_plane, &mgag200_g200wb_primary_plane_helper_funcs);
265bc835040SThomas Zimmermann 	drm_plane_enable_fb_damage_clips(primary_plane);
266bc835040SThomas Zimmermann 
267bc835040SThomas Zimmermann 	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
268bc835040SThomas Zimmermann 					&mgag200_g200wb_crtc_funcs, NULL);
269bc835040SThomas Zimmermann 	if (ret) {
270bc835040SThomas Zimmermann 		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
271bc835040SThomas Zimmermann 		return ret;
272bc835040SThomas Zimmermann 	}
273bc835040SThomas Zimmermann 	drm_crtc_helper_add(crtc, &mgag200_g200wb_crtc_helper_funcs);
274bc835040SThomas Zimmermann 
275bc835040SThomas Zimmermann 	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
276bc835040SThomas Zimmermann 	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
277bc835040SThomas Zimmermann 	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
278bc835040SThomas Zimmermann 
279bc835040SThomas Zimmermann 	encoder->possible_crtcs = drm_crtc_mask(crtc);
280bc835040SThomas Zimmermann 	ret = drm_encoder_init(dev, encoder, &mgag200_g200wb_dac_encoder_funcs,
281bc835040SThomas Zimmermann 			       DRM_MODE_ENCODER_DAC, NULL);
282bc835040SThomas Zimmermann 	if (ret) {
283bc835040SThomas Zimmermann 		drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
284bc835040SThomas Zimmermann 		return ret;
285bc835040SThomas Zimmermann 	}
286bc835040SThomas Zimmermann 
287bc835040SThomas Zimmermann 	ret = mgag200_i2c_init(mdev, i2c);
288bc835040SThomas Zimmermann 	if (ret) {
289bc835040SThomas Zimmermann 		drm_err(dev, "failed to add DDC bus: %d\n", ret);
290bc835040SThomas Zimmermann 		return ret;
291bc835040SThomas Zimmermann 	}
292bc835040SThomas Zimmermann 
293bc835040SThomas Zimmermann 	ret = drm_connector_init_with_ddc(dev, connector,
294bc835040SThomas Zimmermann 					  &mgag200_g200wb_vga_connector_funcs,
295bc835040SThomas Zimmermann 					  DRM_MODE_CONNECTOR_VGA,
296bc835040SThomas Zimmermann 					  &i2c->adapter);
297bc835040SThomas Zimmermann 	if (ret) {
298bc835040SThomas Zimmermann 		drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
299bc835040SThomas Zimmermann 		return ret;
300bc835040SThomas Zimmermann 	}
301bc835040SThomas Zimmermann 	drm_connector_helper_add(connector, &mgag200_g200wb_vga_connector_helper_funcs);
302bc835040SThomas Zimmermann 
303bc835040SThomas Zimmermann 	ret = drm_connector_attach_encoder(connector, encoder);
304bc835040SThomas Zimmermann 	if (ret) {
305bc835040SThomas Zimmermann 		drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
306bc835040SThomas Zimmermann 		return ret;
307bc835040SThomas Zimmermann 	}
308bc835040SThomas Zimmermann 
309bc835040SThomas Zimmermann 	return 0;
310bc835040SThomas Zimmermann }
311bc835040SThomas Zimmermann 
312bc835040SThomas Zimmermann /*
31385397f6bSThomas Zimmermann  * DRM device
31485397f6bSThomas Zimmermann  */
31585397f6bSThomas Zimmermann 
316b9a577a4SThomas Zimmermann static const struct mgag200_device_info mgag200_g200wb_device_info =
317da1efdb2SThomas Zimmermann 	MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false);
318b9a577a4SThomas Zimmermann 
319f639f74aSThomas Zimmermann static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
3208aeeb314SThomas Zimmermann 	.disable_vidrst = mgag200_bmc_disable_vidrst,
3218aeeb314SThomas Zimmermann 	.enable_vidrst = mgag200_bmc_enable_vidrst,
322877507bbSThomas Zimmermann 	.pixpllc_atomic_check = mgag200_g200wb_pixpllc_atomic_check,
323877507bbSThomas Zimmermann 	.pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update,
324f639f74aSThomas Zimmermann };
325f639f74aSThomas Zimmermann 
mgag200_g200wb_device_create(struct pci_dev * pdev,const struct drm_driver * drv)326*d4a3e50fSThomas Zimmermann struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
32785397f6bSThomas Zimmermann {
32885397f6bSThomas Zimmermann 	struct mga_device *mdev;
32985397f6bSThomas Zimmermann 	struct drm_device *dev;
330d45e32c9SThomas Zimmermann 	resource_size_t vram_available;
33185397f6bSThomas Zimmermann 	int ret;
33285397f6bSThomas Zimmermann 
33385397f6bSThomas Zimmermann 	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
33485397f6bSThomas Zimmermann 	if (IS_ERR(mdev))
33585397f6bSThomas Zimmermann 		return mdev;
33685397f6bSThomas Zimmermann 	dev = &mdev->base;
33785397f6bSThomas Zimmermann 
33885397f6bSThomas Zimmermann 	pci_set_drvdata(pdev, dev);
33985397f6bSThomas Zimmermann 
340ce19021fSThomas Zimmermann 	ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000);
341ce19021fSThomas Zimmermann 	if (ret)
342ce19021fSThomas Zimmermann 		return ERR_PTR(ret);
343ce19021fSThomas Zimmermann 
344b62d943eSThomas Zimmermann 	ret = mgag200_device_preinit(mdev);
34585397f6bSThomas Zimmermann 	if (ret)
34685397f6bSThomas Zimmermann 		return ERR_PTR(ret);
34785397f6bSThomas Zimmermann 
348*d4a3e50fSThomas Zimmermann 	ret = mgag200_device_init(mdev, &mgag200_g200wb_device_info,
349f639f74aSThomas Zimmermann 				  &mgag200_g200wb_device_funcs);
35085397f6bSThomas Zimmermann 	if (ret)
35185397f6bSThomas Zimmermann 		return ERR_PTR(ret);
35285397f6bSThomas Zimmermann 
3531ee181feSThomas Zimmermann 	mgag200_g200wb_init_registers(mdev);
3541ee181feSThomas Zimmermann 
355d45e32c9SThomas Zimmermann 	vram_available = mgag200_device_probe_vram(mdev);
356d45e32c9SThomas Zimmermann 
357bc835040SThomas Zimmermann 	ret = mgag200_mode_config_init(mdev, vram_available);
35885397f6bSThomas Zimmermann 	if (ret)
35985397f6bSThomas Zimmermann 		return ERR_PTR(ret);
36085397f6bSThomas Zimmermann 
361bc835040SThomas Zimmermann 	ret = mgag200_g200wb_pipeline_init(mdev);
362bc835040SThomas Zimmermann 	if (ret)
363bc835040SThomas Zimmermann 		return ERR_PTR(ret);
364bc835040SThomas Zimmermann 
365bc835040SThomas Zimmermann 	drm_mode_config_reset(dev);
366bc835040SThomas Zimmermann 
36785397f6bSThomas Zimmermann 	return mdev;
36885397f6bSThomas Zimmermann }
369