Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/pci.h>
4
5#include <drm/drm_drv.h>
6
7#include "mgag200_drv.h"
8
9static int mgag200_g200se_init_pci_options(struct pci_dev *pdev)
10{
11 struct device *dev = &pdev->dev;
12 bool has_sgram;
13 u32 option;
14 int err;
15
16 err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
17 if (err != PCIBIOS_SUCCESSFUL) {
18 dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err);
19 return pcibios_err_to_errno(err);
20 }
21
22 has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK);
23
24 option = 0x40049120;
25 if (has_sgram)
26 option |= PCI_MGA_OPTION_HARDPWMSK;
27
28 return mgag200_init_pci_options(pdev, option, 0x00008000);
29}
30
31/*
32 * DRM device
33 */
34
35static const struct mgag200_device_info mgag200_g200se_a_01_device_info =
36 MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, true);
37
38static const struct mgag200_device_info mgag200_g200se_a_02_device_info =
39 MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, true);
40
41static const struct mgag200_device_info mgag200_g200se_a_03_device_info =
42 MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);
43
44static const struct mgag200_device_info mgag200_g200se_b_01_device_info =
45 MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, false);
46
47static const struct mgag200_device_info mgag200_g200se_b_02_device_info =
48 MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, false);
49
50static const struct mgag200_device_info mgag200_g200se_b_03_device_info =
51 MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);
52
53static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se)
54{
55 struct mga_device *mdev = &g200se->base;
56 struct drm_device *dev = &mdev->base;
57
58 /* stash G200 SE model number for later use */
59 g200se->unique_rev_id = RREG32(0x1e24);
60 if (!g200se->unique_rev_id)
61 return -ENODEV;
62
63 drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id);
64
65 return 0;
66}
67
68struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
69 enum mga_type type)
70{
71 struct mgag200_g200se_device *g200se;
72 const struct mgag200_device_info *info;
73 struct mga_device *mdev;
74 struct drm_device *dev;
75 resource_size_t vram_available;
76 int ret;
77
78 g200se = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200se_device, base.base);
79 if (IS_ERR(g200se))
80 return ERR_CAST(g200se);
81 mdev = &g200se->base;
82 dev = &mdev->base;
83
84 pci_set_drvdata(pdev, dev);
85
86 ret = mgag200_g200se_init_pci_options(pdev);
87 if (ret)
88 return ERR_PTR(ret);
89
90 ret = mgag200_device_preinit(mdev);
91 if (ret)
92 return ERR_PTR(ret);
93
94 ret = mgag200_g200se_init_unique_rev_id(g200se);
95 if (ret)
96 return ERR_PTR(ret);
97
98 switch (type) {
99 case G200_SE_A:
100 if (g200se->unique_rev_id >= 0x03)
101 info = &mgag200_g200se_a_03_device_info;
102 else if (g200se->unique_rev_id >= 0x02)
103 info = &mgag200_g200se_a_02_device_info;
104 else
105 info = &mgag200_g200se_a_01_device_info;
106 break;
107 case G200_SE_B:
108 if (g200se->unique_rev_id >= 0x03)
109 info = &mgag200_g200se_b_03_device_info;
110 else if (g200se->unique_rev_id >= 0x02)
111 info = &mgag200_g200se_b_02_device_info;
112 else
113 info = &mgag200_g200se_b_01_device_info;
114 break;
115 default:
116 return ERR_PTR(-EINVAL);
117 }
118
119 ret = mgag200_device_init(mdev, type, info);
120 if (ret)
121 return ERR_PTR(ret);
122
123 vram_available = mgag200_device_probe_vram(mdev);
124
125 ret = mgag200_modeset_init(mdev, vram_available);
126 if (ret)
127 return ERR_PTR(ret);
128
129 return mdev;
130}