brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · c20ed0a Raw
313 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 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_probe_helper.h>11 12#include "mgag200_drv.h"13 14static void mgag200_g200er_init_registers(struct mga_device *mdev)15{16	static const u8 dacvalue[] = {17		MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f, 0x00, 0x00, 0x00)18	};19 20	size_t i;21 22	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {23		if ((i <= 0x17) ||24		    (i == 0x1b) ||25		    (i == 0x1c) ||26		    ((i >= 0x1f) && (i <= 0x29)) ||27		    ((i >= 0x30) && (i <= 0x37)))28			continue;29		WREG_DAC(i, dacvalue[i]);30	}31 32	WREG_DAC(0x90, 0); /* G200ER specific */33 34	mgag200_init_registers(mdev);35 36	WREG_ECRT(0x24, 0x5); /* G200ER specific */37}38 39static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)40{41	static const uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */42	u32 memctl;43 44	memctl = RREG32(MGAREG_MEMCTL);45 46	memctl |= RESET_FLAG;47	WREG32(MGAREG_MEMCTL, memctl);48 49	udelay(1000);50 51	memctl &= ~RESET_FLAG;52	WREG32(MGAREG_MEMCTL, memctl);53}54 55/*56 * PIXPLLC57 */58 59static int mgag200_g200er_pixpllc_atomic_check(struct drm_crtc *crtc,60					       struct drm_atomic_state *new_state)61{62	static const unsigned int vcomax = 1488000;63	static const unsigned int vcomin = 1056000;64	static const unsigned int pllreffreq = 48000;65	static const unsigned int m_div_val[] = { 1, 2, 4, 8 };66 67	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);68	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);69	long clock = new_crtc_state->mode.clock;70	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;71	unsigned int delta, tmpdelta;72	int testr, testn, testm, testo;73	unsigned int p, m, n, s;74	unsigned int computed, vco;75 76	m = n = p = s = 0;77	delta = 0xffffffff;78 79	for (testr = 0; testr < 4; testr++) {80		if (delta == 0)81			break;82		for (testn = 5; testn < 129; testn++) {83			if (delta == 0)84				break;85			for (testm = 3; testm >= 0; testm--) {86				if (delta == 0)87					break;88				for (testo = 5; testo < 33; testo++) {89					vco = pllreffreq * (testn + 1) /90						(testr + 1);91					if (vco < vcomin)92						continue;93					if (vco > vcomax)94						continue;95					computed = vco / (m_div_val[testm] * (testo + 1));96					if (computed > clock)97						tmpdelta = computed - clock;98					else99						tmpdelta = clock - computed;100					if (tmpdelta < delta) {101						delta = tmpdelta;102						m = (testm | (testo << 3)) + 1;103						n = testn + 1;104						p = testr + 1;105						s = testr;106					}107				}108			}109		}110	}111 112	pixpllc->m = m;113	pixpllc->n = n;114	pixpllc->p = p;115	pixpllc->s = s;116 117	return 0;118}119 120static void mgag200_g200er_pixpllc_atomic_update(struct drm_crtc *crtc,121						 struct drm_atomic_state *old_state)122{123	struct drm_device *dev = crtc->dev;124	struct mga_device *mdev = to_mga_device(dev);125	struct drm_crtc_state *crtc_state = crtc->state;126	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);127	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;128	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;129	u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;130 131	pixpllcm = pixpllc->m - 1;132	pixpllcn = pixpllc->n - 1;133	pixpllcp = pixpllc->p - 1;134	pixpllcs = pixpllc->s;135 136	xpixpllcm = pixpllcm;137	xpixpllcn = pixpllcn;138	xpixpllcp = (pixpllcs << 3) | pixpllcp;139 140	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);141 142	WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);143	tmp = RREG8(DAC_DATA);144	tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;145	WREG8(DAC_DATA, tmp);146 147	WREG8(DAC_INDEX, MGA1064_REMHEADCTL);148	tmp = RREG8(DAC_DATA);149	tmp |= MGA1064_REMHEADCTL_CLKDIS;150	WREG8(DAC_DATA, tmp);151 152	tmp = RREG8(MGAREG_MEM_MISC_READ);153	tmp |= (0x3<<2) | 0xc0;154	WREG8(MGAREG_MEM_MISC_WRITE, tmp);155 156	WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);157	tmp = RREG8(DAC_DATA);158	tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;159	tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;160	WREG8(DAC_DATA, tmp);161 162	udelay(500);163 164	WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);165	WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);166	WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);167 168	udelay(50);169}170 171/*172 * Mode-setting pipeline173 */174 175static const struct drm_plane_helper_funcs mgag200_g200er_primary_plane_helper_funcs = {176	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,177};178 179static const struct drm_plane_funcs mgag200_g200er_primary_plane_funcs = {180	MGAG200_PRIMARY_PLANE_FUNCS,181};182 183static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc,184						     struct drm_atomic_state *old_state)185{186	struct drm_device *dev = crtc->dev;187	struct mga_device *mdev = to_mga_device(dev);188	const struct mgag200_device_funcs *funcs = mdev->funcs;189	struct drm_crtc_state *crtc_state = crtc->state;190	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;191	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);192	const struct drm_format_info *format = mgag200_crtc_state->format;193 194	mgag200_set_format_regs(mdev, format);195	mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);196 197	if (funcs->pixpllc_atomic_update)198		funcs->pixpllc_atomic_update(crtc, old_state);199 200	mgag200_g200er_reset_tagfifo(mdev);201 202	if (crtc_state->gamma_lut)203		mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);204	else205		mgag200_crtc_set_gamma_linear(mdev, format);206 207	mgag200_enable_display(mdev);208}209 210static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = {211	.mode_valid = mgag200_crtc_helper_mode_valid,212	.atomic_check = mgag200_crtc_helper_atomic_check,213	.atomic_flush = mgag200_crtc_helper_atomic_flush,214	.atomic_enable = mgag200_g200er_crtc_helper_atomic_enable,215	.atomic_disable = mgag200_crtc_helper_atomic_disable216};217 218static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = {219	MGAG200_CRTC_FUNCS,220};221 222static int mgag200_g200er_pipeline_init(struct mga_device *mdev)223{224	struct drm_device *dev = &mdev->base;225	struct drm_plane *primary_plane = &mdev->primary_plane;226	struct drm_crtc *crtc = &mdev->crtc;227	int ret;228 229	ret = drm_universal_plane_init(dev, primary_plane, 0,230				       &mgag200_g200er_primary_plane_funcs,231				       mgag200_primary_plane_formats,232				       mgag200_primary_plane_formats_size,233				       mgag200_primary_plane_fmtmods,234				       DRM_PLANE_TYPE_PRIMARY, NULL);235	if (ret) {236		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);237		return ret;238	}239	drm_plane_helper_add(primary_plane, &mgag200_g200er_primary_plane_helper_funcs);240	drm_plane_enable_fb_damage_clips(primary_plane);241 242	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,243					&mgag200_g200er_crtc_funcs, NULL);244	if (ret) {245		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);246		return ret;247	}248	drm_crtc_helper_add(crtc, &mgag200_g200er_crtc_helper_funcs);249 250	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */251	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);252	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);253 254	ret = mgag200_vga_bmc_output_init(mdev);255	if (ret)256		return ret;257 258	return 0;259}260 261/*262 * DRM device263 */264 265static const struct mgag200_device_info mgag200_g200er_device_info =266	MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false);267 268static const struct mgag200_device_funcs mgag200_g200er_device_funcs = {269	.pixpllc_atomic_check = mgag200_g200er_pixpllc_atomic_check,270	.pixpllc_atomic_update = mgag200_g200er_pixpllc_atomic_update,271};272 273struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv)274{275	struct mga_device *mdev;276	struct drm_device *dev;277	resource_size_t vram_available;278	int ret;279 280	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);281	if (IS_ERR(mdev))282		return mdev;283	dev = &mdev->base;284 285	pci_set_drvdata(pdev, dev);286 287	ret = mgag200_device_preinit(mdev);288	if (ret)289		return ERR_PTR(ret);290 291	ret = mgag200_device_init(mdev, &mgag200_g200er_device_info,292				  &mgag200_g200er_device_funcs);293	if (ret)294		return ERR_PTR(ret);295 296	mgag200_g200er_init_registers(mdev);297 298	vram_available = mgag200_device_probe_vram(mdev);299 300	ret = mgag200_mode_config_init(mdev, vram_available);301	if (ret)302		return ERR_PTR(ret);303 304	ret = mgag200_g200er_pipeline_init(mdev);305	if (ret)306		return ERR_PTR(ret);307 308	drm_mode_config_reset(dev);309	drm_kms_helper_poll_init(dev);310 311	return mdev;312}313