summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mgag200/mgag200_g200se.c
blob: bd8fc7a177c2216afb3ac02bba30d9e8dbdcdf21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/pci.h>

#include <drm/drm_drv.h>

#include "mgag200_drv.h"

static int mgag200_g200se_init_pci_options(struct pci_dev *pdev)
{
	struct device *dev = &pdev->dev;
	bool has_sgram;
	u32 option;
	int err;

	err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
	if (err != PCIBIOS_SUCCESSFUL) {
		dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err);
		return pcibios_err_to_errno(err);
	}

	has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK);

	option = 0x40049120;
	if (has_sgram)
		option |= PCI_MGA_OPTION_HARDPWMSK;

	return mgag200_init_pci_options(pdev, option, 0x00008000);
}

static void mgag200_g200se_init_registers(struct mgag200_g200se_device *g200se)
{
	static const u8 dacvalue[] = {
		MGAG200_DAC_DEFAULT(0x03,
				    MGA1064_PIX_CLK_CTL_SEL_PLL,
				    MGA1064_MISC_CTL_DAC_EN |
				    MGA1064_MISC_CTL_VGA8 |
				    MGA1064_MISC_CTL_DAC_RAM_CS,
				    0x00, 0x00, 0x00)
	};

	struct mga_device *mdev = &g200se->base;
	size_t i;

	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
		if ((i <= 0x17) ||
		    (i == 0x1b) ||
		    (i == 0x1c) ||
		    ((i >= 0x1f) && (i <= 0x29)) ||
		    ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)) ||
		    ((i >= 0x30) && (i <= 0x37)))
			continue;
		WREG_DAC(i, dacvalue[i]);
	}

	mgag200_init_registers(mdev);
}

/*
 * DRM device
 */

static const struct mgag200_device_info mgag200_g200se_a_01_device_info =
	MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, true);

static const struct mgag200_device_info mgag200_g200se_a_02_device_info =
	MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, true);

static const struct mgag200_device_info mgag200_g200se_a_03_device_info =
	MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);

static const struct mgag200_device_info mgag200_g200se_b_01_device_info =
	MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, false);

static const struct mgag200_device_info mgag200_g200se_b_02_device_info =
	MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, false);

static const struct mgag200_device_info mgag200_g200se_b_03_device_info =
	MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);

static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se)
{
	struct mga_device *mdev = &g200se->base;
	struct drm_device *dev = &mdev->base;

	/* stash G200 SE model number for later use */
	g200se->unique_rev_id = RREG32(0x1e24);
	if (!g200se->unique_rev_id)
		return -ENODEV;

	drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id);

	return 0;
}

struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
						enum mga_type type)
{
	struct mgag200_g200se_device *g200se;
	const struct mgag200_device_info *info;
	struct mga_device *mdev;
	struct drm_device *dev;
	resource_size_t vram_available;
	int ret;

	g200se = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200se_device, base.base);
	if (IS_ERR(g200se))
		return ERR_CAST(g200se);
	mdev = &g200se->base;
	dev = &mdev->base;

	pci_set_drvdata(pdev, dev);

	ret = mgag200_g200se_init_pci_options(pdev);
	if (ret)
		return ERR_PTR(ret);

	ret = mgag200_device_preinit(mdev);
	if (ret)
		return ERR_PTR(ret);

	ret = mgag200_g200se_init_unique_rev_id(g200se);
	if (ret)
		return ERR_PTR(ret);

	switch (type) {
	case G200_SE_A:
		if (g200se->unique_rev_id >= 0x03)
			info = &mgag200_g200se_a_03_device_info;
		else if (g200se->unique_rev_id >= 0x02)
			info = &mgag200_g200se_a_02_device_info;
		else
			info = &mgag200_g200se_a_01_device_info;
		break;
	case G200_SE_B:
		if (g200se->unique_rev_id >= 0x03)
			info = &mgag200_g200se_b_03_device_info;
		else if (g200se->unique_rev_id >= 0x02)
			info = &mgag200_g200se_b_02_device_info;
		else
			info = &mgag200_g200se_b_01_device_info;
		break;
	default:
		return ERR_PTR(-EINVAL);
	}

	ret = mgag200_device_init(mdev, type, info);
	if (ret)
		return ERR_PTR(ret);

	mgag200_g200se_init_registers(g200se);

	vram_available = mgag200_device_probe_vram(mdev);

	ret = mgag200_modeset_init(mdev, vram_available);
	if (ret)
		return ERR_PTR(ret);

	return mdev;
}