185397f6bSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only
285397f6bSThomas Zimmermann
385397f6bSThomas Zimmermann #include <linux/pci.h>
4f17c655cSThomas Zimmermann #include <linux/vmalloc.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_g200_init_pci_options(struct pci_dev * pdev)14ce19021fSThomas Zimmermann static int mgag200_g200_init_pci_options(struct pci_dev *pdev)
15ce19021fSThomas Zimmermann {
16ce19021fSThomas Zimmermann struct device *dev = &pdev->dev;
17ce19021fSThomas Zimmermann bool has_sgram;
18ce19021fSThomas Zimmermann u32 option;
19ce19021fSThomas Zimmermann int err;
20ce19021fSThomas Zimmermann
21ce19021fSThomas Zimmermann err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
22ce19021fSThomas Zimmermann if (err != PCIBIOS_SUCCESSFUL) {
23ce19021fSThomas Zimmermann dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err);
24ce19021fSThomas Zimmermann return pcibios_err_to_errno(err);
25ce19021fSThomas Zimmermann }
26ce19021fSThomas Zimmermann
27ce19021fSThomas Zimmermann has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK);
28ce19021fSThomas Zimmermann
29ce19021fSThomas Zimmermann if (has_sgram)
30ce19021fSThomas Zimmermann option = 0x4049cd21;
31ce19021fSThomas Zimmermann else
32ce19021fSThomas Zimmermann option = 0x40499121;
33ce19021fSThomas Zimmermann
34ce19021fSThomas Zimmermann return mgag200_init_pci_options(pdev, option, 0x00008000);
35ce19021fSThomas Zimmermann }
36ce19021fSThomas Zimmermann
mgag200_g200_init_registers(struct mgag200_g200_device * g200)371ee181feSThomas Zimmermann static void mgag200_g200_init_registers(struct mgag200_g200_device *g200)
381ee181feSThomas Zimmermann {
391ee181feSThomas Zimmermann static const u8 dacvalue[] = {
401ee181feSThomas Zimmermann MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f,
411ee181feSThomas Zimmermann 0x04, 0x2d, 0x19)
421ee181feSThomas Zimmermann };
431ee181feSThomas Zimmermann
441ee181feSThomas Zimmermann struct mga_device *mdev = &g200->base;
451ee181feSThomas Zimmermann size_t i;
461ee181feSThomas Zimmermann
471ee181feSThomas Zimmermann for (i = 0; i < ARRAY_SIZE(dacvalue); ++i) {
481ee181feSThomas Zimmermann if ((i <= 0x17) ||
491ee181feSThomas Zimmermann (i == 0x1b) ||
501ee181feSThomas Zimmermann (i == 0x1c) ||
511ee181feSThomas Zimmermann ((i >= 0x1f) && (i <= 0x29)) ||
521ee181feSThomas Zimmermann ((i >= 0x30) && (i <= 0x37)))
531ee181feSThomas Zimmermann continue;
541ee181feSThomas Zimmermann WREG_DAC(i, dacvalue[i]);
551ee181feSThomas Zimmermann }
561ee181feSThomas Zimmermann
571ee181feSThomas Zimmermann mgag200_init_registers(mdev);
581ee181feSThomas Zimmermann }
591ee181feSThomas Zimmermann
6085397f6bSThomas Zimmermann /*
61877507bbSThomas Zimmermann * PIXPLLC
62877507bbSThomas Zimmermann */
63877507bbSThomas Zimmermann
mgag200_g200_pixpllc_atomic_check(struct drm_crtc * crtc,struct drm_atomic_state * new_state)64877507bbSThomas Zimmermann static int mgag200_g200_pixpllc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
65877507bbSThomas Zimmermann {
66877507bbSThomas Zimmermann static const int post_div_max = 7;
67877507bbSThomas Zimmermann static const int in_div_min = 1;
68877507bbSThomas Zimmermann static const int in_div_max = 6;
69877507bbSThomas Zimmermann static const int feed_div_min = 7;
70877507bbSThomas Zimmermann static const int feed_div_max = 127;
71877507bbSThomas Zimmermann
72877507bbSThomas Zimmermann struct drm_device *dev = crtc->dev;
73877507bbSThomas Zimmermann struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev);
74877507bbSThomas Zimmermann struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
75877507bbSThomas Zimmermann struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
76877507bbSThomas Zimmermann long clock = new_crtc_state->mode.clock;
77877507bbSThomas Zimmermann struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
78877507bbSThomas Zimmermann u8 testp, testm, testn;
79877507bbSThomas Zimmermann u8 n = 0, m = 0, p, s;
80877507bbSThomas Zimmermann long f_vco;
81877507bbSThomas Zimmermann long computed;
82877507bbSThomas Zimmermann long delta, tmp_delta;
83877507bbSThomas Zimmermann long ref_clk = g200->ref_clk;
84877507bbSThomas Zimmermann long p_clk_min = g200->pclk_min;
85877507bbSThomas Zimmermann long p_clk_max = g200->pclk_max;
86877507bbSThomas Zimmermann
87877507bbSThomas Zimmermann if (clock > p_clk_max) {
88877507bbSThomas Zimmermann drm_err(dev, "Pixel Clock %ld too high\n", clock);
89877507bbSThomas Zimmermann return -EINVAL;
90877507bbSThomas Zimmermann }
91877507bbSThomas Zimmermann
92877507bbSThomas Zimmermann if (clock < p_clk_min >> 3)
93877507bbSThomas Zimmermann clock = p_clk_min >> 3;
94877507bbSThomas Zimmermann
95877507bbSThomas Zimmermann f_vco = clock;
96877507bbSThomas Zimmermann for (testp = 0;
97877507bbSThomas Zimmermann testp <= post_div_max && f_vco < p_clk_min;
98877507bbSThomas Zimmermann testp = (testp << 1) + 1, f_vco <<= 1)
99877507bbSThomas Zimmermann ;
100877507bbSThomas Zimmermann p = testp + 1;
101877507bbSThomas Zimmermann
102877507bbSThomas Zimmermann delta = clock;
103877507bbSThomas Zimmermann
104877507bbSThomas Zimmermann for (testm = in_div_min; testm <= in_div_max; testm++) {
105877507bbSThomas Zimmermann for (testn = feed_div_min; testn <= feed_div_max; testn++) {
106877507bbSThomas Zimmermann computed = ref_clk * (testn + 1) / (testm + 1);
107877507bbSThomas Zimmermann if (computed < f_vco)
108877507bbSThomas Zimmermann tmp_delta = f_vco - computed;
109877507bbSThomas Zimmermann else
110877507bbSThomas Zimmermann tmp_delta = computed - f_vco;
111877507bbSThomas Zimmermann if (tmp_delta < delta) {
112877507bbSThomas Zimmermann delta = tmp_delta;
113877507bbSThomas Zimmermann m = testm + 1;
114877507bbSThomas Zimmermann n = testn + 1;
115877507bbSThomas Zimmermann }
116877507bbSThomas Zimmermann }
117877507bbSThomas Zimmermann }
118877507bbSThomas Zimmermann f_vco = ref_clk * n / m;
119877507bbSThomas Zimmermann if (f_vco < 100000)
120877507bbSThomas Zimmermann s = 0;
121877507bbSThomas Zimmermann else if (f_vco < 140000)
122877507bbSThomas Zimmermann s = 1;
123877507bbSThomas Zimmermann else if (f_vco < 180000)
124877507bbSThomas Zimmermann s = 2;
125877507bbSThomas Zimmermann else
126877507bbSThomas Zimmermann s = 3;
127877507bbSThomas Zimmermann
128877507bbSThomas Zimmermann drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
129877507bbSThomas Zimmermann clock, f_vco, m, n, p, s);
130877507bbSThomas Zimmermann
131877507bbSThomas Zimmermann pixpllc->m = m;
132877507bbSThomas Zimmermann pixpllc->n = n;
133877507bbSThomas Zimmermann pixpllc->p = p;
134877507bbSThomas Zimmermann pixpllc->s = s;
135877507bbSThomas Zimmermann
136877507bbSThomas Zimmermann return 0;
137877507bbSThomas Zimmermann }
138877507bbSThomas Zimmermann
mgag200_g200_pixpllc_atomic_update(struct drm_crtc * crtc,struct drm_atomic_state * old_state)139877507bbSThomas Zimmermann static void mgag200_g200_pixpllc_atomic_update(struct drm_crtc *crtc,
140877507bbSThomas Zimmermann struct drm_atomic_state *old_state)
141877507bbSThomas Zimmermann {
142877507bbSThomas Zimmermann struct drm_device *dev = crtc->dev;
143877507bbSThomas Zimmermann struct mga_device *mdev = to_mga_device(dev);
144877507bbSThomas Zimmermann struct drm_crtc_state *crtc_state = crtc->state;
145877507bbSThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
146877507bbSThomas Zimmermann struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
147877507bbSThomas Zimmermann unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
148877507bbSThomas Zimmermann u8 xpixpllcm, xpixpllcn, xpixpllcp;
149877507bbSThomas Zimmermann
150877507bbSThomas Zimmermann pixpllcm = pixpllc->m - 1;
151877507bbSThomas Zimmermann pixpllcn = pixpllc->n - 1;
152877507bbSThomas Zimmermann pixpllcp = pixpllc->p - 1;
153877507bbSThomas Zimmermann pixpllcs = pixpllc->s;
154877507bbSThomas Zimmermann
155877507bbSThomas Zimmermann xpixpllcm = pixpllcm;
156877507bbSThomas Zimmermann xpixpllcn = pixpllcn;
157877507bbSThomas Zimmermann xpixpllcp = (pixpllcs << 3) | pixpllcp;
158877507bbSThomas Zimmermann
159877507bbSThomas Zimmermann WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
160877507bbSThomas Zimmermann
161877507bbSThomas Zimmermann WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
162877507bbSThomas Zimmermann WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
163877507bbSThomas Zimmermann WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
164877507bbSThomas Zimmermann }
165877507bbSThomas Zimmermann
166877507bbSThomas Zimmermann /*
167bc835040SThomas Zimmermann * Mode-setting pipeline
168bc835040SThomas Zimmermann */
169bc835040SThomas Zimmermann
170bc835040SThomas Zimmermann static const struct drm_plane_helper_funcs mgag200_g200_primary_plane_helper_funcs = {
171bc835040SThomas Zimmermann MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
172bc835040SThomas Zimmermann };
173bc835040SThomas Zimmermann
174bc835040SThomas Zimmermann static const struct drm_plane_funcs mgag200_g200_primary_plane_funcs = {
175bc835040SThomas Zimmermann MGAG200_PRIMARY_PLANE_FUNCS,
176bc835040SThomas Zimmermann };
177bc835040SThomas Zimmermann
178bc835040SThomas Zimmermann static const struct drm_crtc_helper_funcs mgag200_g200_crtc_helper_funcs = {
179bc835040SThomas Zimmermann MGAG200_CRTC_HELPER_FUNCS,
180bc835040SThomas Zimmermann };
181bc835040SThomas Zimmermann
182bc835040SThomas Zimmermann static const struct drm_crtc_funcs mgag200_g200_crtc_funcs = {
183bc835040SThomas Zimmermann MGAG200_CRTC_FUNCS,
184bc835040SThomas Zimmermann };
185bc835040SThomas Zimmermann
186bc835040SThomas Zimmermann static const struct drm_encoder_funcs mgag200_g200_dac_encoder_funcs = {
187bc835040SThomas Zimmermann MGAG200_DAC_ENCODER_FUNCS,
188bc835040SThomas Zimmermann };
189bc835040SThomas Zimmermann
190bc835040SThomas Zimmermann static const struct drm_connector_helper_funcs mgag200_g200_vga_connector_helper_funcs = {
191bc835040SThomas Zimmermann MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
192bc835040SThomas Zimmermann };
193bc835040SThomas Zimmermann
194bc835040SThomas Zimmermann static const struct drm_connector_funcs mgag200_g200_vga_connector_funcs = {
195bc835040SThomas Zimmermann MGAG200_VGA_CONNECTOR_FUNCS,
196bc835040SThomas Zimmermann };
197bc835040SThomas Zimmermann
mgag200_g200_pipeline_init(struct mga_device * mdev)198bc835040SThomas Zimmermann static int mgag200_g200_pipeline_init(struct mga_device *mdev)
199bc835040SThomas Zimmermann {
200bc835040SThomas Zimmermann struct drm_device *dev = &mdev->base;
201bc835040SThomas Zimmermann struct drm_plane *primary_plane = &mdev->primary_plane;
202bc835040SThomas Zimmermann struct drm_crtc *crtc = &mdev->crtc;
203bc835040SThomas Zimmermann struct drm_encoder *encoder = &mdev->encoder;
204bc835040SThomas Zimmermann struct mga_i2c_chan *i2c = &mdev->i2c;
205bc835040SThomas Zimmermann struct drm_connector *connector = &mdev->connector;
206bc835040SThomas Zimmermann int ret;
207bc835040SThomas Zimmermann
208bc835040SThomas Zimmermann ret = drm_universal_plane_init(dev, primary_plane, 0,
209bc835040SThomas Zimmermann &mgag200_g200_primary_plane_funcs,
210bc835040SThomas Zimmermann mgag200_primary_plane_formats,
211bc835040SThomas Zimmermann mgag200_primary_plane_formats_size,
212bc835040SThomas Zimmermann mgag200_primary_plane_fmtmods,
213bc835040SThomas Zimmermann DRM_PLANE_TYPE_PRIMARY, NULL);
214bc835040SThomas Zimmermann if (ret) {
215bc835040SThomas Zimmermann drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
216bc835040SThomas Zimmermann return ret;
217bc835040SThomas Zimmermann }
218bc835040SThomas Zimmermann drm_plane_helper_add(primary_plane, &mgag200_g200_primary_plane_helper_funcs);
219bc835040SThomas Zimmermann drm_plane_enable_fb_damage_clips(primary_plane);
220bc835040SThomas Zimmermann
221bc835040SThomas Zimmermann ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
222bc835040SThomas Zimmermann &mgag200_g200_crtc_funcs, NULL);
223bc835040SThomas Zimmermann if (ret) {
224bc835040SThomas Zimmermann drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
225bc835040SThomas Zimmermann return ret;
226bc835040SThomas Zimmermann }
227bc835040SThomas Zimmermann drm_crtc_helper_add(crtc, &mgag200_g200_crtc_helper_funcs);
228bc835040SThomas Zimmermann
229bc835040SThomas Zimmermann /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
230bc835040SThomas Zimmermann drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
231bc835040SThomas Zimmermann drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
232bc835040SThomas Zimmermann
233bc835040SThomas Zimmermann encoder->possible_crtcs = drm_crtc_mask(crtc);
234bc835040SThomas Zimmermann ret = drm_encoder_init(dev, encoder, &mgag200_g200_dac_encoder_funcs,
235bc835040SThomas Zimmermann DRM_MODE_ENCODER_DAC, NULL);
236bc835040SThomas Zimmermann if (ret) {
237bc835040SThomas Zimmermann drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
238bc835040SThomas Zimmermann return ret;
239bc835040SThomas Zimmermann }
240bc835040SThomas Zimmermann
241bc835040SThomas Zimmermann ret = mgag200_i2c_init(mdev, i2c);
242bc835040SThomas Zimmermann if (ret) {
243bc835040SThomas Zimmermann drm_err(dev, "failed to add DDC bus: %d\n", ret);
244bc835040SThomas Zimmermann return ret;
245bc835040SThomas Zimmermann }
246bc835040SThomas Zimmermann
247bc835040SThomas Zimmermann ret = drm_connector_init_with_ddc(dev, connector,
248bc835040SThomas Zimmermann &mgag200_g200_vga_connector_funcs,
249bc835040SThomas Zimmermann DRM_MODE_CONNECTOR_VGA,
250bc835040SThomas Zimmermann &i2c->adapter);
251bc835040SThomas Zimmermann if (ret) {
252bc835040SThomas Zimmermann drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
253bc835040SThomas Zimmermann return ret;
254bc835040SThomas Zimmermann }
255bc835040SThomas Zimmermann drm_connector_helper_add(connector, &mgag200_g200_vga_connector_helper_funcs);
256bc835040SThomas Zimmermann
257bc835040SThomas Zimmermann ret = drm_connector_attach_encoder(connector, encoder);
258bc835040SThomas Zimmermann if (ret) {
259bc835040SThomas Zimmermann drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
260bc835040SThomas Zimmermann return ret;
261bc835040SThomas Zimmermann }
262bc835040SThomas Zimmermann
263bc835040SThomas Zimmermann return 0;
264bc835040SThomas Zimmermann }
265bc835040SThomas Zimmermann
266bc835040SThomas Zimmermann /*
26785397f6bSThomas Zimmermann * DRM Device
26885397f6bSThomas Zimmermann */
26985397f6bSThomas Zimmermann
270b9a577a4SThomas Zimmermann static const struct mgag200_device_info mgag200_g200_device_info =
271da1efdb2SThomas Zimmermann MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 3, false);
272b9a577a4SThomas Zimmermann
mgag200_g200_interpret_bios(struct mgag200_g200_device * g200,const unsigned char * bios,size_t size)27385397f6bSThomas Zimmermann static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200,
27485397f6bSThomas Zimmermann const unsigned char *bios, size_t size)
27585397f6bSThomas Zimmermann {
27685397f6bSThomas Zimmermann static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'};
27785397f6bSThomas Zimmermann static const unsigned int expected_length[6] = {
27885397f6bSThomas Zimmermann 0, 64, 64, 64, 128, 128
27985397f6bSThomas Zimmermann };
28085397f6bSThomas Zimmermann struct mga_device *mdev = &g200->base;
28185397f6bSThomas Zimmermann struct drm_device *dev = &mdev->base;
28285397f6bSThomas Zimmermann const unsigned char *pins;
28385397f6bSThomas Zimmermann unsigned int pins_len, version;
28485397f6bSThomas Zimmermann int offset;
28585397f6bSThomas Zimmermann int tmp;
28685397f6bSThomas Zimmermann
28785397f6bSThomas Zimmermann /* Test for MATROX string. */
28885397f6bSThomas Zimmermann if (size < 45 + sizeof(matrox))
28985397f6bSThomas Zimmermann return;
29085397f6bSThomas Zimmermann if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0)
29185397f6bSThomas Zimmermann return;
29285397f6bSThomas Zimmermann
29385397f6bSThomas Zimmermann /* Get the PInS offset. */
29485397f6bSThomas Zimmermann if (size < MGA_BIOS_OFFSET + 2)
29585397f6bSThomas Zimmermann return;
29685397f6bSThomas Zimmermann offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET];
29785397f6bSThomas Zimmermann
29885397f6bSThomas Zimmermann /* Get PInS data structure. */
29985397f6bSThomas Zimmermann
30085397f6bSThomas Zimmermann if (size < offset + 6)
30185397f6bSThomas Zimmermann return;
30285397f6bSThomas Zimmermann pins = bios + offset;
30385397f6bSThomas Zimmermann if (pins[0] == 0x2e && pins[1] == 0x41) {
30485397f6bSThomas Zimmermann version = pins[5];
30585397f6bSThomas Zimmermann pins_len = pins[2];
30685397f6bSThomas Zimmermann } else {
30785397f6bSThomas Zimmermann version = 1;
30885397f6bSThomas Zimmermann pins_len = pins[0] + (pins[1] << 8);
30985397f6bSThomas Zimmermann }
31085397f6bSThomas Zimmermann
31185397f6bSThomas Zimmermann if (version < 1 || version > 5) {
31285397f6bSThomas Zimmermann drm_warn(dev, "Unknown BIOS PInS version: %d\n", version);
31385397f6bSThomas Zimmermann return;
31485397f6bSThomas Zimmermann }
31585397f6bSThomas Zimmermann if (pins_len != expected_length[version]) {
31685397f6bSThomas Zimmermann drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n",
31785397f6bSThomas Zimmermann pins_len, expected_length[version]);
31885397f6bSThomas Zimmermann return;
31985397f6bSThomas Zimmermann }
32085397f6bSThomas Zimmermann if (size < offset + pins_len)
32185397f6bSThomas Zimmermann return;
32285397f6bSThomas Zimmermann
32385397f6bSThomas Zimmermann drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n", version, pins_len);
32485397f6bSThomas Zimmermann
32585397f6bSThomas Zimmermann /* Extract the clock values */
32685397f6bSThomas Zimmermann
32785397f6bSThomas Zimmermann switch (version) {
32885397f6bSThomas Zimmermann case 1:
32985397f6bSThomas Zimmermann tmp = pins[24] + (pins[25] << 8);
33085397f6bSThomas Zimmermann if (tmp)
33185397f6bSThomas Zimmermann g200->pclk_max = tmp * 10;
33285397f6bSThomas Zimmermann break;
33385397f6bSThomas Zimmermann case 2:
33485397f6bSThomas Zimmermann if (pins[41] != 0xff)
33585397f6bSThomas Zimmermann g200->pclk_max = (pins[41] + 100) * 1000;
33685397f6bSThomas Zimmermann break;
33785397f6bSThomas Zimmermann case 3:
33885397f6bSThomas Zimmermann if (pins[36] != 0xff)
33985397f6bSThomas Zimmermann g200->pclk_max = (pins[36] + 100) * 1000;
34085397f6bSThomas Zimmermann if (pins[52] & 0x20)
34185397f6bSThomas Zimmermann g200->ref_clk = 14318;
34285397f6bSThomas Zimmermann break;
34385397f6bSThomas Zimmermann case 4:
34485397f6bSThomas Zimmermann if (pins[39] != 0xff)
34585397f6bSThomas Zimmermann g200->pclk_max = pins[39] * 4 * 1000;
34685397f6bSThomas Zimmermann if (pins[92] & 0x01)
34785397f6bSThomas Zimmermann g200->ref_clk = 14318;
34885397f6bSThomas Zimmermann break;
34985397f6bSThomas Zimmermann case 5:
35085397f6bSThomas Zimmermann tmp = pins[4] ? 8000 : 6000;
35185397f6bSThomas Zimmermann if (pins[123] != 0xff)
35285397f6bSThomas Zimmermann g200->pclk_min = pins[123] * tmp;
35385397f6bSThomas Zimmermann if (pins[38] != 0xff)
35485397f6bSThomas Zimmermann g200->pclk_max = pins[38] * tmp;
35585397f6bSThomas Zimmermann if (pins[110] & 0x01)
35685397f6bSThomas Zimmermann g200->ref_clk = 14318;
35785397f6bSThomas Zimmermann break;
35885397f6bSThomas Zimmermann default:
35985397f6bSThomas Zimmermann break;
36085397f6bSThomas Zimmermann }
36185397f6bSThomas Zimmermann }
36285397f6bSThomas Zimmermann
mgag200_g200_init_refclk(struct mgag200_g200_device * g200)36385397f6bSThomas Zimmermann static void mgag200_g200_init_refclk(struct mgag200_g200_device *g200)
36485397f6bSThomas Zimmermann {
36585397f6bSThomas Zimmermann struct mga_device *mdev = &g200->base;
36685397f6bSThomas Zimmermann struct drm_device *dev = &mdev->base;
36785397f6bSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev->dev);
36885397f6bSThomas Zimmermann unsigned char __iomem *rom;
36985397f6bSThomas Zimmermann unsigned char *bios;
37085397f6bSThomas Zimmermann size_t size;
37185397f6bSThomas Zimmermann
37285397f6bSThomas Zimmermann g200->pclk_min = 50000;
37385397f6bSThomas Zimmermann g200->pclk_max = 230000;
37485397f6bSThomas Zimmermann g200->ref_clk = 27050;
37585397f6bSThomas Zimmermann
37685397f6bSThomas Zimmermann rom = pci_map_rom(pdev, &size);
37785397f6bSThomas Zimmermann if (!rom)
37885397f6bSThomas Zimmermann return;
37985397f6bSThomas Zimmermann
38085397f6bSThomas Zimmermann bios = vmalloc(size);
38185397f6bSThomas Zimmermann if (!bios)
38285397f6bSThomas Zimmermann goto out;
38385397f6bSThomas Zimmermann memcpy_fromio(bios, rom, size);
38485397f6bSThomas Zimmermann
38585397f6bSThomas Zimmermann if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa)
38685397f6bSThomas Zimmermann mgag200_g200_interpret_bios(g200, bios, size);
38785397f6bSThomas Zimmermann
38885397f6bSThomas Zimmermann drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n",
38985397f6bSThomas Zimmermann g200->pclk_min, g200->pclk_max, g200->ref_clk);
39085397f6bSThomas Zimmermann
39185397f6bSThomas Zimmermann vfree(bios);
39285397f6bSThomas Zimmermann out:
39385397f6bSThomas Zimmermann pci_unmap_rom(pdev, rom);
39485397f6bSThomas Zimmermann }
39585397f6bSThomas Zimmermann
396f639f74aSThomas Zimmermann static const struct mgag200_device_funcs mgag200_g200_device_funcs = {
397877507bbSThomas Zimmermann .pixpllc_atomic_check = mgag200_g200_pixpllc_atomic_check,
398877507bbSThomas Zimmermann .pixpllc_atomic_update = mgag200_g200_pixpllc_atomic_update,
399f639f74aSThomas Zimmermann };
400f639f74aSThomas Zimmermann
mgag200_g200_device_create(struct pci_dev * pdev,const struct drm_driver * drv)401*d4a3e50fSThomas Zimmermann struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
40285397f6bSThomas Zimmermann {
40385397f6bSThomas Zimmermann struct mgag200_g200_device *g200;
40485397f6bSThomas Zimmermann struct mga_device *mdev;
40585397f6bSThomas Zimmermann struct drm_device *dev;
406d45e32c9SThomas Zimmermann resource_size_t vram_available;
40785397f6bSThomas Zimmermann int ret;
40885397f6bSThomas Zimmermann
40985397f6bSThomas Zimmermann g200 = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200_device, base.base);
41085397f6bSThomas Zimmermann if (IS_ERR(g200))
41185397f6bSThomas Zimmermann return ERR_CAST(g200);
41285397f6bSThomas Zimmermann mdev = &g200->base;
41385397f6bSThomas Zimmermann dev = &mdev->base;
41485397f6bSThomas Zimmermann
41585397f6bSThomas Zimmermann pci_set_drvdata(pdev, dev);
41685397f6bSThomas Zimmermann
417ce19021fSThomas Zimmermann ret = mgag200_g200_init_pci_options(pdev);
418ce19021fSThomas Zimmermann if (ret)
419ce19021fSThomas Zimmermann return ERR_PTR(ret);
420ce19021fSThomas Zimmermann
421b62d943eSThomas Zimmermann ret = mgag200_device_preinit(mdev);
42285397f6bSThomas Zimmermann if (ret)
42385397f6bSThomas Zimmermann return ERR_PTR(ret);
42485397f6bSThomas Zimmermann
42585397f6bSThomas Zimmermann mgag200_g200_init_refclk(g200);
42685397f6bSThomas Zimmermann
427*d4a3e50fSThomas Zimmermann ret = mgag200_device_init(mdev, &mgag200_g200_device_info,
428f639f74aSThomas Zimmermann &mgag200_g200_device_funcs);
42985397f6bSThomas Zimmermann if (ret)
43085397f6bSThomas Zimmermann return ERR_PTR(ret);
43185397f6bSThomas Zimmermann
4321ee181feSThomas Zimmermann mgag200_g200_init_registers(g200);
4331ee181feSThomas Zimmermann
434d45e32c9SThomas Zimmermann vram_available = mgag200_device_probe_vram(mdev);
435d45e32c9SThomas Zimmermann
436bc835040SThomas Zimmermann ret = mgag200_mode_config_init(mdev, vram_available);
43785397f6bSThomas Zimmermann if (ret)
43885397f6bSThomas Zimmermann return ERR_PTR(ret);
43985397f6bSThomas Zimmermann
440bc835040SThomas Zimmermann ret = mgag200_g200_pipeline_init(mdev);
441bc835040SThomas Zimmermann if (ret)
442bc835040SThomas Zimmermann return ERR_PTR(ret);
443bc835040SThomas Zimmermann
444bc835040SThomas Zimmermann drm_mode_config_reset(dev);
445bc835040SThomas Zimmermann
44685397f6bSThomas Zimmermann return mdev;
44785397f6bSThomas Zimmermann }
448