brintos

brintos / linux-shallow public Read only

0
0
Text · 13.8 KiB · 7a32d3b Raw
518 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 int mgag200_g200se_init_pci_options(struct pci_dev *pdev)15{16	struct device *dev = &pdev->dev;17	bool has_sgram;18	u32 option;19	int err;20 21	err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);22	if (err != PCIBIOS_SUCCESSFUL) {23		dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err);24		return pcibios_err_to_errno(err);25	}26 27	has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK);28 29	option = 0x40049120;30	if (has_sgram)31		option |= PCI_MGA_OPTION_HARDPWMSK;32 33	return mgag200_init_pci_options(pdev, option, 0x00008000);34}35 36static void mgag200_g200se_init_registers(struct mgag200_g200se_device *g200se)37{38	static const u8 dacvalue[] = {39		MGAG200_DAC_DEFAULT(0x03,40				    MGA1064_PIX_CLK_CTL_SEL_PLL,41				    MGA1064_MISC_CTL_DAC_EN |42				    MGA1064_MISC_CTL_VGA8 |43				    MGA1064_MISC_CTL_DAC_RAM_CS,44				    0x00, 0x00, 0x00)45	};46 47	struct mga_device *mdev = &g200se->base;48	size_t i;49 50	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {51		if ((i <= 0x17) ||52		    (i == 0x1b) ||53		    (i == 0x1c) ||54		    ((i >= 0x1f) && (i <= 0x29)) ||55		    ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)) ||56		    ((i >= 0x30) && (i <= 0x37)))57			continue;58		WREG_DAC(i, dacvalue[i]);59	}60 61	mgag200_init_registers(mdev);62}63 64static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,65					const struct drm_display_mode *mode,66					const struct drm_format_info *format)67{68	struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base);69	unsigned int hiprilvl;70	u8 crtcext6;71 72	if  (g200se->unique_rev_id >= 0x04) {73		hiprilvl = 0;74	} else if (g200se->unique_rev_id >= 0x02) {75		unsigned int bpp;76		unsigned long mb;77 78		if (format->cpp[0] * 8 > 16)79			bpp = 32;80		else if (format->cpp[0] * 8 > 8)81			bpp = 16;82		else83			bpp = 8;84 85		mb = (mode->clock * bpp) / 1000;86		if (mb > 3100)87			hiprilvl = 0;88		else if (mb > 2600)89			hiprilvl = 1;90		else if (mb > 1900)91			hiprilvl = 2;92		else if (mb > 1160)93			hiprilvl = 3;94		else if (mb > 440)95			hiprilvl = 4;96		else97			hiprilvl = 5;98 99	} else if (g200se->unique_rev_id >= 0x01) {100		hiprilvl = 3;101	} else {102		hiprilvl = 4;103	}104 105	crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */106 107	WREG_ECRT(0x06, crtcext6);108}109 110/*111 * PIXPLLC112 */113 114static int mgag200_g200se_00_pixpllc_atomic_check(struct drm_crtc *crtc,115						  struct drm_atomic_state *new_state)116{117	static const unsigned int vcomax = 320000;118	static const unsigned int vcomin = 160000;119	static const unsigned int pllreffreq = 25000;120 121	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);122	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);123	long clock = new_crtc_state->mode.clock;124	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;125	unsigned int delta, tmpdelta, permitteddelta;126	unsigned int testp, testm, testn;127	unsigned int p, m, n, s;128	unsigned int computed;129 130	m = n = p = s = 0;131	delta = 0xffffffff;132	permitteddelta = clock * 5 / 1000;133 134	for (testp = 8; testp > 0; testp /= 2) {135		if (clock * testp > vcomax)136			continue;137		if (clock * testp < vcomin)138			continue;139 140		for (testn = 17; testn < 256; testn++) {141			for (testm = 1; testm < 32; testm++) {142				computed = (pllreffreq * testn) / (testm * testp);143				if (computed > clock)144					tmpdelta = computed - clock;145				else146					tmpdelta = clock - computed;147				if (tmpdelta < delta) {148					delta = tmpdelta;149					m = testm;150					n = testn;151					p = testp;152				}153			}154		}155	}156 157	if (delta > permitteddelta) {158		pr_warn("PLL delta too large\n");159		return -EINVAL;160	}161 162	pixpllc->m = m;163	pixpllc->n = n;164	pixpllc->p = p;165	pixpllc->s = s;166 167	return 0;168}169 170static void mgag200_g200se_00_pixpllc_atomic_update(struct drm_crtc *crtc,171						    struct drm_atomic_state *old_state)172{173	struct drm_device *dev = crtc->dev;174	struct mga_device *mdev = to_mga_device(dev);175	struct drm_crtc_state *crtc_state = crtc->state;176	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);177	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;178	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;179	u8 xpixpllcm, xpixpllcn, xpixpllcp;180 181	pixpllcm = pixpllc->m - 1;182	pixpllcn = pixpllc->n - 1;183	pixpllcp = pixpllc->p - 1;184	pixpllcs = pixpllc->s;185 186	xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);187	xpixpllcn = pixpllcn;188	xpixpllcp = (pixpllcs << 3) | pixpllcp;189 190	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);191 192	WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);193	WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);194	WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);195}196 197static int mgag200_g200se_04_pixpllc_atomic_check(struct drm_crtc *crtc,198						  struct drm_atomic_state *new_state)199{200	static const unsigned int vcomax = 1600000;201	static const unsigned int vcomin = 800000;202	static const unsigned int pllreffreq = 25000;203	static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};204 205	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);206	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);207	long clock = new_crtc_state->mode.clock;208	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;209	unsigned int delta, tmpdelta, permitteddelta;210	unsigned int testp, testm, testn;211	unsigned int p, m, n, s;212	unsigned int computed;213	unsigned int fvv;214	unsigned int i;215 216	m = n = p = s = 0;217	delta = 0xffffffff;218 219	if (clock < 25000)220		clock = 25000;221	clock = clock * 2;222 223	/* Permited delta is 0.5% as VESA Specification */224	permitteddelta = clock * 5 / 1000;225 226	for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) {227		testp = pvalues_e4[i];228 229		if ((clock * testp) > vcomax)230			continue;231		if ((clock * testp) < vcomin)232			continue;233 234		for (testn = 50; testn <= 256; testn++) {235			for (testm = 1; testm <= 32; testm++) {236				computed = (pllreffreq * testn) / (testm * testp);237				if (computed > clock)238					tmpdelta = computed - clock;239				else240					tmpdelta = clock - computed;241 242				if (tmpdelta < delta) {243					delta = tmpdelta;244					m = testm;245					n = testn;246					p = testp;247				}248			}249		}250	}251 252	fvv = pllreffreq * n / m;253	fvv = (fvv - 800000) / 50000;254	if (fvv > 15)255		fvv = 15;256	s = fvv << 1;257 258	if (delta > permitteddelta) {259		pr_warn("PLL delta too large\n");260		return -EINVAL;261	}262 263	pixpllc->m = m;264	pixpllc->n = n;265	pixpllc->p = p;266	pixpllc->s = s;267 268	return 0;269}270 271static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc,272						    struct drm_atomic_state *old_state)273{274	struct drm_device *dev = crtc->dev;275	struct mga_device *mdev = to_mga_device(dev);276	struct drm_crtc_state *crtc_state = crtc->state;277	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);278	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;279	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;280	u8 xpixpllcm, xpixpllcn, xpixpllcp;281 282	pixpllcm = pixpllc->m - 1;283	pixpllcn = pixpllc->n - 1;284	pixpllcp = pixpllc->p - 1;285	pixpllcs = pixpllc->s;286 287	// For G200SE A, BIT(7) should be set unconditionally.288	xpixpllcm = BIT(7) | pixpllcm;289	xpixpllcn = pixpllcn;290	xpixpllcp = (pixpllcs << 3) | pixpllcp;291 292	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);293 294	WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);295	WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);296	WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);297 298	WREG_DAC(0x1a, 0x09);299	msleep(20);300	WREG_DAC(0x1a, 0x01);301}302 303/*304 * Mode-setting pipeline305 */306 307static const struct drm_plane_helper_funcs mgag200_g200se_primary_plane_helper_funcs = {308	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,309};310 311static const struct drm_plane_funcs mgag200_g200se_primary_plane_funcs = {312	MGAG200_PRIMARY_PLANE_FUNCS,313};314 315static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc,316						     struct drm_atomic_state *old_state)317{318	struct drm_device *dev = crtc->dev;319	struct mga_device *mdev = to_mga_device(dev);320	const struct mgag200_device_funcs *funcs = mdev->funcs;321	struct drm_crtc_state *crtc_state = crtc->state;322	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;323	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);324	const struct drm_format_info *format = mgag200_crtc_state->format;325 326	mgag200_set_format_regs(mdev, format);327	mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);328 329	if (funcs->pixpllc_atomic_update)330		funcs->pixpllc_atomic_update(crtc, old_state);331 332	mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, format);333 334	if (crtc_state->gamma_lut)335		mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);336	else337		mgag200_crtc_set_gamma_linear(mdev, format);338 339	mgag200_enable_display(mdev);340}341 342static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = {343	.mode_valid = mgag200_crtc_helper_mode_valid,344	.atomic_check = mgag200_crtc_helper_atomic_check,345	.atomic_flush = mgag200_crtc_helper_atomic_flush,346	.atomic_enable = mgag200_g200se_crtc_helper_atomic_enable,347	.atomic_disable = mgag200_crtc_helper_atomic_disable348};349 350static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = {351	MGAG200_CRTC_FUNCS,352};353 354static int mgag200_g200se_pipeline_init(struct mga_device *mdev)355{356	struct drm_device *dev = &mdev->base;357	struct drm_plane *primary_plane = &mdev->primary_plane;358	struct drm_crtc *crtc = &mdev->crtc;359	int ret;360 361	ret = drm_universal_plane_init(dev, primary_plane, 0,362				       &mgag200_g200se_primary_plane_funcs,363				       mgag200_primary_plane_formats,364				       mgag200_primary_plane_formats_size,365				       mgag200_primary_plane_fmtmods,366				       DRM_PLANE_TYPE_PRIMARY, NULL);367	if (ret) {368		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);369		return ret;370	}371	drm_plane_helper_add(primary_plane, &mgag200_g200se_primary_plane_helper_funcs);372	drm_plane_enable_fb_damage_clips(primary_plane);373 374	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,375					&mgag200_g200se_crtc_funcs, NULL);376	if (ret) {377		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);378		return ret;379	}380	drm_crtc_helper_add(crtc, &mgag200_g200se_crtc_helper_funcs);381 382	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */383	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);384	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);385 386	ret = mgag200_vga_bmc_output_init(mdev);387	if (ret)388		return ret;389 390	return 0;391}392 393/*394 * DRM device395 */396 397static const struct mgag200_device_info mgag200_g200se_a_01_device_info =398	MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, true);399 400static const struct mgag200_device_info mgag200_g200se_a_02_device_info =401	MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, true);402 403static const struct mgag200_device_info mgag200_g200se_a_03_device_info =404	MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);405 406static const struct mgag200_device_info mgag200_g200se_b_01_device_info =407	MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, false);408 409static const struct mgag200_device_info mgag200_g200se_b_02_device_info =410	MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, false);411 412static const struct mgag200_device_info mgag200_g200se_b_03_device_info =413	MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);414 415static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se)416{417	struct mga_device *mdev = &g200se->base;418	struct drm_device *dev = &mdev->base;419 420	/* stash G200 SE model number for later use */421	g200se->unique_rev_id = RREG32(0x1e24);422	if (!g200se->unique_rev_id)423		return -ENODEV;424 425	drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id);426 427	return 0;428}429 430static const struct mgag200_device_funcs mgag200_g200se_00_device_funcs = {431	.pixpllc_atomic_check = mgag200_g200se_00_pixpllc_atomic_check,432	.pixpllc_atomic_update = mgag200_g200se_00_pixpllc_atomic_update,433};434 435static const struct mgag200_device_funcs mgag200_g200se_04_device_funcs = {436	.pixpllc_atomic_check = mgag200_g200se_04_pixpllc_atomic_check,437	.pixpllc_atomic_update = mgag200_g200se_04_pixpllc_atomic_update,438};439 440struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,441						enum mga_type type)442{443	struct mgag200_g200se_device *g200se;444	const struct mgag200_device_info *info;445	const struct mgag200_device_funcs *funcs;446	struct mga_device *mdev;447	struct drm_device *dev;448	resource_size_t vram_available;449	int ret;450 451	g200se = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200se_device, base.base);452	if (IS_ERR(g200se))453		return ERR_CAST(g200se);454	mdev = &g200se->base;455	dev = &mdev->base;456 457	pci_set_drvdata(pdev, dev);458 459	ret = mgag200_g200se_init_pci_options(pdev);460	if (ret)461		return ERR_PTR(ret);462 463	ret = mgag200_device_preinit(mdev);464	if (ret)465		return ERR_PTR(ret);466 467	ret = mgag200_g200se_init_unique_rev_id(g200se);468	if (ret)469		return ERR_PTR(ret);470 471	switch (type) {472	case G200_SE_A:473		if (g200se->unique_rev_id >= 0x03)474			info = &mgag200_g200se_a_03_device_info;475		else if (g200se->unique_rev_id >= 0x02)476			info = &mgag200_g200se_a_02_device_info;477		else478			info = &mgag200_g200se_a_01_device_info;479		break;480	case G200_SE_B:481		if (g200se->unique_rev_id >= 0x03)482			info = &mgag200_g200se_b_03_device_info;483		else if (g200se->unique_rev_id >= 0x02)484			info = &mgag200_g200se_b_02_device_info;485		else486			info = &mgag200_g200se_b_01_device_info;487		break;488	default:489		return ERR_PTR(-EINVAL);490	}491 492	if (g200se->unique_rev_id >= 0x04)493		funcs = &mgag200_g200se_04_device_funcs;494	else495		funcs = &mgag200_g200se_00_device_funcs;496 497	ret = mgag200_device_init(mdev, info, funcs);498	if (ret)499		return ERR_PTR(ret);500 501	mgag200_g200se_init_registers(g200se);502 503	vram_available = mgag200_device_probe_vram(mdev);504 505	ret = mgag200_mode_config_init(mdev, vram_available);506	if (ret)507		return ERR_PTR(ret);508 509	ret = mgag200_g200se_pipeline_init(mdev);510	if (ret)511		return ERR_PTR(ret);512 513	drm_mode_config_reset(dev);514	drm_kms_helper_poll_init(dev);515 516	return mdev;517}518