diff options
-rw-r--r-- | drivers/gpu/drm/Kconfig | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/Kconfig | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/Makefile | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_dram_tables.h | 144 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_drv.c | 242 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_drv.h | 356 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_fb.c | 341 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_main.c | 527 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_mode.c | 1160 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_post.c | 1780 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_tables.h | 265 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_ttm.c | 453 |
13 files changed, 5296 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index e354bc0b052a..9c6244c1fff6 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -186,3 +186,6 @@ source "drivers/gpu/drm/vmwgfx/Kconfig" | |||
186 | source "drivers/gpu/drm/gma500/Kconfig" | 186 | source "drivers/gpu/drm/gma500/Kconfig" |
187 | 187 | ||
188 | source "drivers/gpu/drm/udl/Kconfig" | 188 | source "drivers/gpu/drm/udl/Kconfig" |
189 | |||
190 | source "drivers/gpu/drm/ast/Kconfig" | ||
191 | |||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index c20da5bda355..fb3eac8402fe 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -42,4 +42,5 @@ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ | |||
42 | obj-$(CONFIG_DRM_EXYNOS) +=exynos/ | 42 | obj-$(CONFIG_DRM_EXYNOS) +=exynos/ |
43 | obj-$(CONFIG_DRM_GMA500) += gma500/ | 43 | obj-$(CONFIG_DRM_GMA500) += gma500/ |
44 | obj-$(CONFIG_DRM_UDL) += udl/ | 44 | obj-$(CONFIG_DRM_UDL) += udl/ |
45 | obj-$(CONFIG_DRM_AST) += ast/ | ||
45 | obj-y += i2c/ | 46 | obj-y += i2c/ |
diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig new file mode 100644 index 000000000000..e43ff8dc0320 --- /dev/null +++ b/drivers/gpu/drm/ast/Kconfig | |||
@@ -0,0 +1,15 @@ | |||
1 | config DRM_AST | ||
2 | tristate "AST server chips" | ||
3 | depends on DRM && PCI && EXPERIMENTAL | ||
4 | select DRM_TTM | ||
5 | select FB_SYS_COPYAREA | ||
6 | select FB_SYS_FILLRECT | ||
7 | select FB_SYS_IMAGEBLIT | ||
8 | select DRM_KMS_HELPER | ||
9 | help | ||
10 | Say yes for experimental AST GPU driver. Do not enable | ||
11 | this driver without having a working -modesetting, | ||
12 | and a version of AST that knows to fail if KMS | ||
13 | is bound to the driver. These GPUs are commonly found | ||
14 | in server chipsets. | ||
15 | |||
diff --git a/drivers/gpu/drm/ast/Makefile b/drivers/gpu/drm/ast/Makefile new file mode 100644 index 000000000000..8df4f284ee24 --- /dev/null +++ b/drivers/gpu/drm/ast/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for the drm device driver. This driver provides support for the | ||
3 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. | ||
4 | |||
5 | ccflags-y := -Iinclude/drm | ||
6 | |||
7 | ast-y := ast_drv.o ast_main.o ast_mode.o ast_fb.o ast_ttm.o ast_post.o | ||
8 | |||
9 | obj-$(CONFIG_DRM_AST) := ast.o \ No newline at end of file | ||
diff --git a/drivers/gpu/drm/ast/ast_dram_tables.h b/drivers/gpu/drm/ast/ast_dram_tables.h new file mode 100644 index 000000000000..cc04539c0ff3 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_dram_tables.h | |||
@@ -0,0 +1,144 @@ | |||
1 | #ifndef AST_DRAM_TABLES_H | ||
2 | #define AST_DRAM_TABLES_H | ||
3 | |||
4 | /* DRAM timing tables */ | ||
5 | struct ast_dramstruct { | ||
6 | u16 index; | ||
7 | u32 data; | ||
8 | }; | ||
9 | |||
10 | static const struct ast_dramstruct ast2000_dram_table_data[] = { | ||
11 | { 0x0108, 0x00000000 }, | ||
12 | { 0x0120, 0x00004a21 }, | ||
13 | { 0xFF00, 0x00000043 }, | ||
14 | { 0x0000, 0xFFFFFFFF }, | ||
15 | { 0x0004, 0x00000089 }, | ||
16 | { 0x0008, 0x22331353 }, | ||
17 | { 0x000C, 0x0d07000b }, | ||
18 | { 0x0010, 0x11113333 }, | ||
19 | { 0x0020, 0x00110350 }, | ||
20 | { 0x0028, 0x1e0828f0 }, | ||
21 | { 0x0024, 0x00000001 }, | ||
22 | { 0x001C, 0x00000000 }, | ||
23 | { 0x0014, 0x00000003 }, | ||
24 | { 0xFF00, 0x00000043 }, | ||
25 | { 0x0018, 0x00000131 }, | ||
26 | { 0x0014, 0x00000001 }, | ||
27 | { 0xFF00, 0x00000043 }, | ||
28 | { 0x0018, 0x00000031 }, | ||
29 | { 0x0014, 0x00000001 }, | ||
30 | { 0xFF00, 0x00000043 }, | ||
31 | { 0x0028, 0x1e0828f1 }, | ||
32 | { 0x0024, 0x00000003 }, | ||
33 | { 0x002C, 0x1f0f28fb }, | ||
34 | { 0x0030, 0xFFFFFE01 }, | ||
35 | { 0xFFFF, 0xFFFFFFFF } | ||
36 | }; | ||
37 | |||
38 | static const struct ast_dramstruct ast1100_dram_table_data[] = { | ||
39 | { 0x2000, 0x1688a8a8 }, | ||
40 | { 0x2020, 0x000041f0 }, | ||
41 | { 0xFF00, 0x00000043 }, | ||
42 | { 0x0000, 0xfc600309 }, | ||
43 | { 0x006C, 0x00909090 }, | ||
44 | { 0x0064, 0x00050000 }, | ||
45 | { 0x0004, 0x00000585 }, | ||
46 | { 0x0008, 0x0011030f }, | ||
47 | { 0x0010, 0x22201724 }, | ||
48 | { 0x0018, 0x1e29011a }, | ||
49 | { 0x0020, 0x00c82222 }, | ||
50 | { 0x0014, 0x01001523 }, | ||
51 | { 0x001C, 0x1024010d }, | ||
52 | { 0x0024, 0x00cb2522 }, | ||
53 | { 0x0038, 0xffffff82 }, | ||
54 | { 0x003C, 0x00000000 }, | ||
55 | { 0x0040, 0x00000000 }, | ||
56 | { 0x0044, 0x00000000 }, | ||
57 | { 0x0048, 0x00000000 }, | ||
58 | { 0x004C, 0x00000000 }, | ||
59 | { 0x0050, 0x00000000 }, | ||
60 | { 0x0054, 0x00000000 }, | ||
61 | { 0x0058, 0x00000000 }, | ||
62 | { 0x005C, 0x00000000 }, | ||
63 | { 0x0060, 0x032aa02a }, | ||
64 | { 0x0064, 0x002d3000 }, | ||
65 | { 0x0068, 0x00000000 }, | ||
66 | { 0x0070, 0x00000000 }, | ||
67 | { 0x0074, 0x00000000 }, | ||
68 | { 0x0078, 0x00000000 }, | ||
69 | { 0x007C, 0x00000000 }, | ||
70 | { 0x0034, 0x00000001 }, | ||
71 | { 0xFF00, 0x00000043 }, | ||
72 | { 0x002C, 0x00000732 }, | ||
73 | { 0x0030, 0x00000040 }, | ||
74 | { 0x0028, 0x00000005 }, | ||
75 | { 0x0028, 0x00000007 }, | ||
76 | { 0x0028, 0x00000003 }, | ||
77 | { 0x0028, 0x00000001 }, | ||
78 | { 0x000C, 0x00005a08 }, | ||
79 | { 0x002C, 0x00000632 }, | ||
80 | { 0x0028, 0x00000001 }, | ||
81 | { 0x0030, 0x000003c0 }, | ||
82 | { 0x0028, 0x00000003 }, | ||
83 | { 0x0030, 0x00000040 }, | ||
84 | { 0x0028, 0x00000003 }, | ||
85 | { 0x000C, 0x00005a21 }, | ||
86 | { 0x0034, 0x00007c03 }, | ||
87 | { 0x0120, 0x00004c41 }, | ||
88 | { 0xffff, 0xffffffff }, | ||
89 | }; | ||
90 | |||
91 | static const struct ast_dramstruct ast2100_dram_table_data[] = { | ||
92 | { 0x2000, 0x1688a8a8 }, | ||
93 | { 0x2020, 0x00004120 }, | ||
94 | { 0xFF00, 0x00000043 }, | ||
95 | { 0x0000, 0xfc600309 }, | ||
96 | { 0x006C, 0x00909090 }, | ||
97 | { 0x0064, 0x00070000 }, | ||
98 | { 0x0004, 0x00000489 }, | ||
99 | { 0x0008, 0x0011030f }, | ||
100 | { 0x0010, 0x32302926 }, | ||
101 | { 0x0018, 0x274c0122 }, | ||
102 | { 0x0020, 0x00ce2222 }, | ||
103 | { 0x0014, 0x01001523 }, | ||
104 | { 0x001C, 0x1024010d }, | ||
105 | { 0x0024, 0x00cb2522 }, | ||
106 | { 0x0038, 0xffffff82 }, | ||
107 | { 0x003C, 0x00000000 }, | ||
108 | { 0x0040, 0x00000000 }, | ||
109 | { 0x0044, 0x00000000 }, | ||
110 | { 0x0048, 0x00000000 }, | ||
111 | { 0x004C, 0x00000000 }, | ||
112 | { 0x0050, 0x00000000 }, | ||
113 | { 0x0054, 0x00000000 }, | ||
114 | { 0x0058, 0x00000000 }, | ||
115 | { 0x005C, 0x00000000 }, | ||
116 | { 0x0060, 0x0f2aa02a }, | ||
117 | { 0x0064, 0x003f3005 }, | ||
118 | { 0x0068, 0x02020202 }, | ||
119 | { 0x0070, 0x00000000 }, | ||
120 | { 0x0074, 0x00000000 }, | ||
121 | { 0x0078, 0x00000000 }, | ||
122 | { 0x007C, 0x00000000 }, | ||
123 | { 0x0034, 0x00000001 }, | ||
124 | { 0xFF00, 0x00000043 }, | ||
125 | { 0x002C, 0x00000942 }, | ||
126 | { 0x0030, 0x00000040 }, | ||
127 | { 0x0028, 0x00000005 }, | ||
128 | { 0x0028, 0x00000007 }, | ||
129 | { 0x0028, 0x00000003 }, | ||
130 | { 0x0028, 0x00000001 }, | ||
131 | { 0x000C, 0x00005a08 }, | ||
132 | { 0x002C, 0x00000842 }, | ||
133 | { 0x0028, 0x00000001 }, | ||
134 | { 0x0030, 0x000003c0 }, | ||
135 | { 0x0028, 0x00000003 }, | ||
136 | { 0x0030, 0x00000040 }, | ||
137 | { 0x0028, 0x00000003 }, | ||
138 | { 0x000C, 0x00005a21 }, | ||
139 | { 0x0034, 0x00007c03 }, | ||
140 | { 0x0120, 0x00005061 }, | ||
141 | { 0xffff, 0xffffffff }, | ||
142 | }; | ||
143 | |||
144 | #endif | ||
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c new file mode 100644 index 000000000000..b56eac6b155f --- /dev/null +++ b/drivers/gpu/drm/ast/ast_drv.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the | ||
6 | * "Software"), to deal in the Software without restriction, including | ||
7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
9 | * permit persons to whom the Software is furnished to do so, subject to | ||
10 | * the following conditions: | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * The above copyright notice and this permission notice (including the | ||
21 | * next paragraph) shall be included in all copies or substantial portions | ||
22 | * of the Software. | ||
23 | * | ||
24 | */ | ||
25 | /* | ||
26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
27 | */ | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/console.h> | ||
30 | |||
31 | #include "drmP.h" | ||
32 | #include "drm.h" | ||
33 | #include "drm_crtc_helper.h" | ||
34 | |||
35 | #include "ast_drv.h" | ||
36 | |||
37 | int ast_modeset = -1; | ||
38 | |||
39 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); | ||
40 | module_param_named(modeset, ast_modeset, int, 0400); | ||
41 | |||
42 | #define PCI_VENDOR_ASPEED 0x1a03 | ||
43 | |||
44 | static struct drm_driver driver; | ||
45 | |||
46 | #define AST_VGA_DEVICE(id, info) { \ | ||
47 | .class = PCI_BASE_CLASS_DISPLAY << 16, \ | ||
48 | .class_mask = 0xff0000, \ | ||
49 | .vendor = PCI_VENDOR_ASPEED, \ | ||
50 | .device = id, \ | ||
51 | .subvendor = PCI_ANY_ID, \ | ||
52 | .subdevice = PCI_ANY_ID, \ | ||
53 | .driver_data = (unsigned long) info } | ||
54 | |||
55 | static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { | ||
56 | AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL), | ||
57 | AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL), | ||
58 | /* AST_VGA_DEVICE(PCI_CHIP_AST1180, NULL), - don't bind to 1180 for now */ | ||
59 | {0, 0, 0}, | ||
60 | }; | ||
61 | |||
62 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
63 | |||
64 | static int __devinit | ||
65 | ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
66 | { | ||
67 | return drm_get_pci_dev(pdev, ent, &driver); | ||
68 | } | ||
69 | |||
70 | static void | ||
71 | ast_pci_remove(struct pci_dev *pdev) | ||
72 | { | ||
73 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
74 | |||
75 | drm_put_dev(dev); | ||
76 | } | ||
77 | |||
78 | |||
79 | |||
80 | static int ast_drm_freeze(struct drm_device *dev) | ||
81 | { | ||
82 | drm_kms_helper_poll_disable(dev); | ||
83 | |||
84 | pci_save_state(dev->pdev); | ||
85 | |||
86 | console_lock(); | ||
87 | ast_fbdev_set_suspend(dev, 1); | ||
88 | console_unlock(); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int ast_drm_thaw(struct drm_device *dev) | ||
93 | { | ||
94 | int error = 0; | ||
95 | |||
96 | ast_post_gpu(dev); | ||
97 | |||
98 | drm_mode_config_reset(dev); | ||
99 | mutex_lock(&dev->mode_config.mutex); | ||
100 | drm_helper_resume_force_mode(dev); | ||
101 | mutex_unlock(&dev->mode_config.mutex); | ||
102 | |||
103 | console_lock(); | ||
104 | ast_fbdev_set_suspend(dev, 0); | ||
105 | console_unlock(); | ||
106 | return error; | ||
107 | } | ||
108 | |||
109 | static int ast_drm_resume(struct drm_device *dev) | ||
110 | { | ||
111 | int ret; | ||
112 | |||
113 | if (pci_enable_device(dev->pdev)) | ||
114 | return -EIO; | ||
115 | |||
116 | ret = ast_drm_thaw(dev); | ||
117 | if (ret) | ||
118 | return ret; | ||
119 | |||
120 | drm_kms_helper_poll_enable(dev); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int ast_pm_suspend(struct device *dev) | ||
125 | { | ||
126 | struct pci_dev *pdev = to_pci_dev(dev); | ||
127 | struct drm_device *ddev = pci_get_drvdata(pdev); | ||
128 | int error; | ||
129 | |||
130 | error = ast_drm_freeze(ddev); | ||
131 | if (error) | ||
132 | return error; | ||
133 | |||
134 | pci_disable_device(pdev); | ||
135 | pci_set_power_state(pdev, PCI_D3hot); | ||
136 | return 0; | ||
137 | } | ||
138 | static int ast_pm_resume(struct device *dev) | ||
139 | { | ||
140 | struct pci_dev *pdev = to_pci_dev(dev); | ||
141 | struct drm_device *ddev = pci_get_drvdata(pdev); | ||
142 | return ast_drm_resume(ddev); | ||
143 | } | ||
144 | |||
145 | static int ast_pm_freeze(struct device *dev) | ||
146 | { | ||
147 | struct pci_dev *pdev = to_pci_dev(dev); | ||
148 | struct drm_device *ddev = pci_get_drvdata(pdev); | ||
149 | |||
150 | if (!ddev || !ddev->dev_private) | ||
151 | return -ENODEV; | ||
152 | return ast_drm_freeze(ddev); | ||
153 | |||
154 | } | ||
155 | |||
156 | static int ast_pm_thaw(struct device *dev) | ||
157 | { | ||
158 | struct pci_dev *pdev = to_pci_dev(dev); | ||
159 | struct drm_device *ddev = pci_get_drvdata(pdev); | ||
160 | return ast_drm_thaw(ddev); | ||
161 | } | ||
162 | |||
163 | static int ast_pm_poweroff(struct device *dev) | ||
164 | { | ||
165 | struct pci_dev *pdev = to_pci_dev(dev); | ||
166 | struct drm_device *ddev = pci_get_drvdata(pdev); | ||
167 | |||
168 | return ast_drm_freeze(ddev); | ||
169 | } | ||
170 | |||
171 | static const struct dev_pm_ops ast_pm_ops = { | ||
172 | .suspend = ast_pm_suspend, | ||
173 | .resume = ast_pm_resume, | ||
174 | .freeze = ast_pm_freeze, | ||
175 | .thaw = ast_pm_thaw, | ||
176 | .poweroff = ast_pm_poweroff, | ||
177 | .restore = ast_pm_resume, | ||
178 | }; | ||
179 | |||
180 | static struct pci_driver ast_pci_driver = { | ||
181 | .name = DRIVER_NAME, | ||
182 | .id_table = pciidlist, | ||
183 | .probe = ast_pci_probe, | ||
184 | .remove = ast_pci_remove, | ||
185 | .driver.pm = &ast_pm_ops, | ||
186 | }; | ||
187 | |||
188 | static const struct file_operations ast_fops = { | ||
189 | .owner = THIS_MODULE, | ||
190 | .open = drm_open, | ||
191 | .release = drm_release, | ||
192 | .unlocked_ioctl = drm_ioctl, | ||
193 | .mmap = ast_mmap, | ||
194 | .poll = drm_poll, | ||
195 | .fasync = drm_fasync, | ||
196 | .read = drm_read, | ||
197 | }; | ||
198 | |||
199 | static struct drm_driver driver = { | ||
200 | .driver_features = DRIVER_USE_MTRR | DRIVER_MODESET | DRIVER_GEM, | ||
201 | .dev_priv_size = 0, | ||
202 | |||
203 | .load = ast_driver_load, | ||
204 | .unload = ast_driver_unload, | ||
205 | |||
206 | .fops = &ast_fops, | ||
207 | .name = DRIVER_NAME, | ||
208 | .desc = DRIVER_DESC, | ||
209 | .date = DRIVER_DATE, | ||
210 | .major = DRIVER_MAJOR, | ||
211 | .minor = DRIVER_MINOR, | ||
212 | .patchlevel = DRIVER_PATCHLEVEL, | ||
213 | |||
214 | .gem_init_object = ast_gem_init_object, | ||
215 | .gem_free_object = ast_gem_free_object, | ||
216 | .dumb_create = ast_dumb_create, | ||
217 | .dumb_map_offset = ast_dumb_mmap_offset, | ||
218 | .dumb_destroy = ast_dumb_destroy, | ||
219 | |||
220 | }; | ||
221 | |||
222 | static int __init ast_init(void) | ||
223 | { | ||
224 | if (vgacon_text_force() && ast_modeset == -1) | ||
225 | return -EINVAL; | ||
226 | |||
227 | if (ast_modeset == 0) | ||
228 | return -EINVAL; | ||
229 | return drm_pci_init(&driver, &ast_pci_driver); | ||
230 | } | ||
231 | static void __exit ast_exit(void) | ||
232 | { | ||
233 | drm_pci_exit(&driver, &ast_pci_driver); | ||
234 | } | ||
235 | |||
236 | module_init(ast_init); | ||
237 | module_exit(ast_exit); | ||
238 | |||
239 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
240 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
241 | MODULE_LICENSE("GPL and additional rights"); | ||
242 | |||
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h new file mode 100644 index 000000000000..d4af9edcbb97 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_drv.h | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the | ||
6 | * "Software"), to deal in the Software without restriction, including | ||
7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
9 | * permit persons to whom the Software is furnished to do so, subject to | ||
10 | * the following conditions: | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * The above copyright notice and this permission notice (including the | ||
21 | * next paragraph) shall be included in all copies or substantial portions | ||
22 | * of the Software. | ||
23 | * | ||
24 | */ | ||
25 | /* | ||
26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
27 | */ | ||
28 | #ifndef __AST_DRV_H__ | ||
29 | #define __AST_DRV_H__ | ||
30 | |||
31 | #include "drm_fb_helper.h" | ||
32 | |||
33 | #include "ttm/ttm_bo_api.h" | ||
34 | #include "ttm/ttm_bo_driver.h" | ||
35 | #include "ttm/ttm_placement.h" | ||
36 | #include "ttm/ttm_memory.h" | ||
37 | #include "ttm/ttm_module.h" | ||
38 | |||
39 | #include <linux/i2c.h> | ||
40 | #include <linux/i2c-algo-bit.h> | ||
41 | |||
42 | #define DRIVER_AUTHOR "Dave Airlie" | ||
43 | |||
44 | #define DRIVER_NAME "ast" | ||
45 | #define DRIVER_DESC "AST" | ||
46 | #define DRIVER_DATE "20120228" | ||
47 | |||
48 | #define DRIVER_MAJOR 0 | ||
49 | #define DRIVER_MINOR 1 | ||
50 | #define DRIVER_PATCHLEVEL 0 | ||
51 | |||
52 | #define PCI_CHIP_AST2000 0x2000 | ||
53 | #define PCI_CHIP_AST2100 0x2010 | ||
54 | #define PCI_CHIP_AST1180 0x1180 | ||
55 | |||
56 | |||
57 | enum ast_chip { | ||
58 | AST2000, | ||
59 | AST2100, | ||
60 | AST1100, | ||
61 | AST2200, | ||
62 | AST2150, | ||
63 | AST2300, | ||
64 | AST1180, | ||
65 | }; | ||
66 | |||
67 | #define AST_DRAM_512Mx16 0 | ||
68 | #define AST_DRAM_1Gx16 1 | ||
69 | #define AST_DRAM_512Mx32 2 | ||
70 | #define AST_DRAM_1Gx32 3 | ||
71 | #define AST_DRAM_2Gx16 6 | ||
72 | #define AST_DRAM_4Gx16 7 | ||
73 | |||
74 | struct ast_fbdev; | ||
75 | |||
76 | struct ast_private { | ||
77 | struct drm_device *dev; | ||
78 | |||
79 | void __iomem *regs; | ||
80 | void __iomem *ioregs; | ||
81 | |||
82 | enum ast_chip chip; | ||
83 | bool vga2_clone; | ||
84 | uint32_t dram_bus_width; | ||
85 | uint32_t dram_type; | ||
86 | uint32_t mclk; | ||
87 | uint32_t vram_size; | ||
88 | |||
89 | struct ast_fbdev *fbdev; | ||
90 | |||
91 | int fb_mtrr; | ||
92 | |||
93 | struct { | ||
94 | struct drm_global_reference mem_global_ref; | ||
95 | struct ttm_bo_global_ref bo_global_ref; | ||
96 | struct ttm_bo_device bdev; | ||
97 | atomic_t validate_sequence; | ||
98 | } ttm; | ||
99 | |||
100 | struct drm_gem_object *cursor_cache; | ||
101 | uint64_t cursor_cache_gpu_addr; | ||
102 | struct ttm_bo_kmap_obj cache_kmap; | ||
103 | int next_cursor; | ||
104 | }; | ||
105 | |||
106 | int ast_driver_load(struct drm_device *dev, unsigned long flags); | ||
107 | int ast_driver_unload(struct drm_device *dev); | ||
108 | |||
109 | struct ast_gem_object; | ||
110 | |||
111 | #define AST_IO_AR_PORT_WRITE (0x40) | ||
112 | #define AST_IO_MISC_PORT_WRITE (0x42) | ||
113 | #define AST_IO_SEQ_PORT (0x44) | ||
114 | #define AST_DAC_INDEX_READ (0x3c7) | ||
115 | #define AST_IO_DAC_INDEX_WRITE (0x48) | ||
116 | #define AST_IO_DAC_DATA (0x49) | ||
117 | #define AST_IO_GR_PORT (0x4E) | ||
118 | #define AST_IO_CRTC_PORT (0x54) | ||
119 | #define AST_IO_INPUT_STATUS1_READ (0x5A) | ||
120 | #define AST_IO_MISC_PORT_READ (0x4C) | ||
121 | |||
122 | #define __ast_read(x) \ | ||
123 | static inline u##x ast_read##x(struct ast_private *ast, u32 reg) { \ | ||
124 | u##x val = 0;\ | ||
125 | val = ioread##x(ast->regs + reg); \ | ||
126 | return val;\ | ||
127 | } | ||
128 | |||
129 | __ast_read(8); | ||
130 | __ast_read(16); | ||
131 | __ast_read(32) | ||
132 | |||
133 | #define __ast_io_read(x) \ | ||
134 | static inline u##x ast_io_read##x(struct ast_private *ast, u32 reg) { \ | ||
135 | u##x val = 0;\ | ||
136 | val = ioread##x(ast->ioregs + reg); \ | ||
137 | return val;\ | ||
138 | } | ||
139 | |||
140 | __ast_io_read(8); | ||
141 | __ast_io_read(16); | ||
142 | __ast_io_read(32); | ||
143 | |||
144 | #define __ast_write(x) \ | ||
145 | static inline void ast_write##x(struct ast_private *ast, u32 reg, u##x val) {\ | ||
146 | iowrite##x(val, ast->regs + reg);\ | ||
147 | } | ||
148 | |||
149 | __ast_write(8); | ||
150 | __ast_write(16); | ||
151 | __ast_write(32); | ||
152 | |||
153 | #define __ast_io_write(x) \ | ||
154 | static inline void ast_io_write##x(struct ast_private *ast, u32 reg, u##x val) {\ | ||
155 | iowrite##x(val, ast->ioregs + reg);\ | ||
156 | } | ||
157 | |||
158 | __ast_io_write(8); | ||
159 | __ast_io_write(16); | ||
160 | #undef __ast_io_write | ||
161 | |||
162 | static inline void ast_set_index_reg(struct ast_private *ast, | ||
163 | uint32_t base, uint8_t index, | ||
164 | uint8_t val) | ||
165 | { | ||
166 | ast_io_write16(ast, base, ((u16)val << 8) | index); | ||
167 | } | ||
168 | |||
169 | void ast_set_index_reg_mask(struct ast_private *ast, | ||
170 | uint32_t base, uint8_t index, | ||
171 | uint8_t mask, uint8_t val); | ||
172 | uint8_t ast_get_index_reg(struct ast_private *ast, | ||
173 | uint32_t base, uint8_t index); | ||
174 | uint8_t ast_get_index_reg_mask(struct ast_private *ast, | ||
175 | uint32_t base, uint8_t index, uint8_t mask); | ||
176 | |||
177 | static inline void ast_open_key(struct ast_private *ast) | ||
178 | { | ||
179 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xA1, 0xFF, 0x04); | ||
180 | } | ||
181 | |||
182 | #define AST_VIDMEM_SIZE_8M 0x00800000 | ||
183 | #define AST_VIDMEM_SIZE_16M 0x01000000 | ||
184 | #define AST_VIDMEM_SIZE_32M 0x02000000 | ||
185 | #define AST_VIDMEM_SIZE_64M 0x04000000 | ||
186 | #define AST_VIDMEM_SIZE_128M 0x08000000 | ||
187 | |||
188 | #define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M | ||
189 | |||
190 | #define AST_MAX_HWC_WIDTH 64 | ||
191 | #define AST_MAX_HWC_HEIGHT 64 | ||
192 | |||
193 | #define AST_HWC_SIZE (AST_MAX_HWC_WIDTH*AST_MAX_HWC_HEIGHT*2) | ||
194 | #define AST_HWC_SIGNATURE_SIZE 32 | ||
195 | |||
196 | #define AST_DEFAULT_HWC_NUM 2 | ||
197 | /* define for signature structure */ | ||
198 | #define AST_HWC_SIGNATURE_CHECKSUM 0x00 | ||
199 | #define AST_HWC_SIGNATURE_SizeX 0x04 | ||
200 | #define AST_HWC_SIGNATURE_SizeY 0x08 | ||
201 | #define AST_HWC_SIGNATURE_X 0x0C | ||
202 | #define AST_HWC_SIGNATURE_Y 0x10 | ||
203 | #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 | ||
204 | #define AST_HWC_SIGNATURE_HOTSPOTY 0x18 | ||
205 | |||
206 | |||
207 | struct ast_i2c_chan { | ||
208 | struct i2c_adapter adapter; | ||
209 | struct drm_device *dev; | ||
210 | struct i2c_algo_bit_data bit; | ||
211 | }; | ||
212 | |||
213 | struct ast_connector { | ||
214 | struct drm_connector base; | ||
215 | struct ast_i2c_chan *i2c; | ||
216 | }; | ||
217 | |||
218 | struct ast_crtc { | ||
219 | struct drm_crtc base; | ||
220 | u8 lut_r[256], lut_g[256], lut_b[256]; | ||
221 | struct drm_gem_object *cursor_bo; | ||
222 | uint64_t cursor_addr; | ||
223 | int cursor_width, cursor_height; | ||
224 | u8 offset_x, offset_y; | ||
225 | }; | ||
226 | |||
227 | struct ast_encoder { | ||
228 | struct drm_encoder base; | ||
229 | }; | ||
230 | |||
231 | struct ast_framebuffer { | ||
232 | struct drm_framebuffer base; | ||
233 | struct drm_gem_object *obj; | ||
234 | }; | ||
235 | |||
236 | struct ast_fbdev { | ||
237 | struct drm_fb_helper helper; | ||
238 | struct ast_framebuffer afb; | ||
239 | struct list_head fbdev_list; | ||
240 | void *sysram; | ||
241 | int size; | ||
242 | struct ttm_bo_kmap_obj mapping; | ||
243 | }; | ||
244 | |||
245 | #define to_ast_crtc(x) container_of(x, struct ast_crtc, base) | ||
246 | #define to_ast_connector(x) container_of(x, struct ast_connector, base) | ||
247 | #define to_ast_encoder(x) container_of(x, struct ast_encoder, base) | ||
248 | #define to_ast_framebuffer(x) container_of(x, struct ast_framebuffer, base) | ||
249 | |||
250 | struct ast_vbios_stdtable { | ||
251 | u8 misc; | ||
252 | u8 seq[4]; | ||
253 | u8 crtc[25]; | ||
254 | u8 ar[20]; | ||
255 | u8 gr[9]; | ||
256 | }; | ||
257 | |||
258 | struct ast_vbios_enhtable { | ||
259 | u32 ht; | ||
260 | u32 hde; | ||
261 | u32 hfp; | ||
262 | u32 hsync; | ||
263 | u32 vt; | ||
264 | u32 vde; | ||
265 | u32 vfp; | ||
266 | u32 vsync; | ||
267 | u32 dclk_index; | ||
268 | u32 flags; | ||
269 | u32 refresh_rate; | ||
270 | u32 refresh_rate_index; | ||
271 | u32 mode_id; | ||
272 | }; | ||
273 | |||
274 | struct ast_vbios_dclk_info { | ||
275 | u8 param1; | ||
276 | u8 param2; | ||
277 | u8 param3; | ||
278 | }; | ||
279 | |||
280 | struct ast_vbios_mode_info { | ||
281 | struct ast_vbios_stdtable *std_table; | ||
282 | struct ast_vbios_enhtable *enh_table; | ||
283 | }; | ||
284 | |||
285 | extern int ast_mode_init(struct drm_device *dev); | ||
286 | extern void ast_mode_fini(struct drm_device *dev); | ||
287 | |||
288 | int ast_framebuffer_init(struct drm_device *dev, | ||
289 | struct ast_framebuffer *ast_fb, | ||
290 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
291 | struct drm_gem_object *obj); | ||
292 | |||
293 | int ast_fbdev_init(struct drm_device *dev); | ||
294 | void ast_fbdev_fini(struct drm_device *dev); | ||
295 | void ast_fbdev_set_suspend(struct drm_device *dev, int state); | ||
296 | |||
297 | struct ast_bo { | ||
298 | struct ttm_buffer_object bo; | ||
299 | struct ttm_placement placement; | ||
300 | struct ttm_bo_kmap_obj kmap; | ||
301 | struct drm_gem_object gem; | ||
302 | u32 placements[3]; | ||
303 | int pin_count; | ||
304 | }; | ||
305 | #define gem_to_ast_bo(gobj) container_of((gobj), struct ast_bo, gem) | ||
306 | |||
307 | static inline struct ast_bo * | ||
308 | ast_bo(struct ttm_buffer_object *bo) | ||
309 | { | ||
310 | return container_of(bo, struct ast_bo, bo); | ||
311 | } | ||
312 | |||
313 | |||
314 | #define to_ast_obj(x) container_of(x, struct ast_gem_object, base) | ||
315 | |||
316 | #define AST_MM_ALIGN_SHIFT 4 | ||
317 | #define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1) | ||
318 | |||
319 | extern int ast_dumb_create(struct drm_file *file, | ||
320 | struct drm_device *dev, | ||
321 | struct drm_mode_create_dumb *args); | ||
322 | extern int ast_dumb_destroy(struct drm_file *file, | ||
323 | struct drm_device *dev, | ||
324 | uint32_t handle); | ||
325 | |||
326 | extern int ast_gem_init_object(struct drm_gem_object *obj); | ||
327 | extern void ast_gem_free_object(struct drm_gem_object *obj); | ||
328 | extern int ast_dumb_mmap_offset(struct drm_file *file, | ||
329 | struct drm_device *dev, | ||
330 | uint32_t handle, | ||
331 | uint64_t *offset); | ||
332 | |||
333 | #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) | ||
334 | |||
335 | int ast_mm_init(struct ast_private *ast); | ||
336 | void ast_mm_fini(struct ast_private *ast); | ||
337 | |||
338 | int ast_bo_create(struct drm_device *dev, int size, int align, | ||
339 | uint32_t flags, struct ast_bo **pastbo); | ||
340 | |||
341 | int ast_gem_create(struct drm_device *dev, | ||
342 | u32 size, bool iskernel, | ||
343 | struct drm_gem_object **obj); | ||
344 | |||
345 | int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr); | ||
346 | int ast_bo_unpin(struct ast_bo *bo); | ||
347 | |||
348 | int ast_bo_reserve(struct ast_bo *bo, bool no_wait); | ||
349 | void ast_bo_unreserve(struct ast_bo *bo); | ||
350 | void ast_ttm_placement(struct ast_bo *bo, int domain); | ||
351 | int ast_bo_push_sysram(struct ast_bo *bo); | ||
352 | int ast_mmap(struct file *filp, struct vm_area_struct *vma); | ||
353 | |||
354 | /* ast post */ | ||
355 | void ast_post_gpu(struct drm_device *dev); | ||
356 | #endif | ||
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c new file mode 100644 index 000000000000..2fc8e9e860b1 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_fb.c | |||
@@ -0,0 +1,341 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the | ||
6 | * "Software"), to deal in the Software without restriction, including | ||
7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
9 | * permit persons to whom the Software is furnished to do so, subject to | ||
10 | * the following conditions: | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * The above copyright notice and this permission notice (including the | ||
21 | * next paragraph) shall be included in all copies or substantial portions | ||
22 | * of the Software. | ||
23 | * | ||
24 | */ | ||
25 | /* | ||
26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
27 | */ | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/tty.h> | ||
34 | #include <linux/sysrq.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/fb.h> | ||
37 | #include <linux/init.h> | ||
38 | |||
39 | |||
40 | #include "drmP.h" | ||
41 | #include "drm.h" | ||
42 | #include "drm_crtc.h" | ||
43 | #include "drm_fb_helper.h" | ||
44 | #include "ast_drv.h" | ||
45 | |||
46 | static void ast_dirty_update(struct ast_fbdev *afbdev, | ||
47 | int x, int y, int width, int height) | ||
48 | { | ||
49 | int i; | ||
50 | struct drm_gem_object *obj; | ||
51 | struct ast_bo *bo; | ||
52 | int src_offset, dst_offset; | ||
53 | int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8; | ||
54 | int ret; | ||
55 | bool unmap = false; | ||
56 | |||
57 | obj = afbdev->afb.obj; | ||
58 | bo = gem_to_ast_bo(obj); | ||
59 | |||
60 | ret = ast_bo_reserve(bo, true); | ||
61 | if (ret) { | ||
62 | DRM_ERROR("failed to reserve fb bo\n"); | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | if (!bo->kmap.virtual) { | ||
67 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
68 | if (ret) { | ||
69 | DRM_ERROR("failed to kmap fb updates\n"); | ||
70 | ast_bo_unreserve(bo); | ||
71 | return; | ||
72 | } | ||
73 | unmap = true; | ||
74 | } | ||
75 | for (i = y; i < y + height; i++) { | ||
76 | /* assume equal stride for now */ | ||
77 | src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp); | ||
78 | memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); | ||
79 | |||
80 | } | ||
81 | if (unmap) | ||
82 | ttm_bo_kunmap(&bo->kmap); | ||
83 | |||
84 | ast_bo_unreserve(bo); | ||
85 | } | ||
86 | |||
87 | static void ast_fillrect(struct fb_info *info, | ||
88 | const struct fb_fillrect *rect) | ||
89 | { | ||
90 | struct ast_fbdev *afbdev = info->par; | ||
91 | sys_fillrect(info, rect); | ||
92 | ast_dirty_update(afbdev, rect->dx, rect->dy, rect->width, | ||
93 | rect->height); | ||
94 | } | ||
95 | |||
96 | static void ast_copyarea(struct fb_info *info, | ||
97 | const struct fb_copyarea *area) | ||
98 | { | ||
99 | struct ast_fbdev *afbdev = info->par; | ||
100 | sys_copyarea(info, area); | ||
101 | ast_dirty_update(afbdev, area->dx, area->dy, area->width, | ||
102 | area->height); | ||
103 | } | ||
104 | |||
105 | static void ast_imageblit(struct fb_info *info, | ||
106 | const struct fb_image *image) | ||
107 | { | ||
108 | struct ast_fbdev *afbdev = info->par; | ||
109 | sys_imageblit(info, image); | ||
110 | ast_dirty_update(afbdev, image->dx, image->dy, image->width, | ||
111 | image->height); | ||
112 | } | ||
113 | |||
114 | static struct fb_ops astfb_ops = { | ||
115 | .owner = THIS_MODULE, | ||
116 | .fb_check_var = drm_fb_helper_check_var, | ||
117 | .fb_set_par = drm_fb_helper_set_par, | ||
118 | .fb_fillrect = ast_fillrect, | ||
119 | .fb_copyarea = ast_copyarea, | ||
120 | .fb_imageblit = ast_imageblit, | ||
121 | .fb_pan_display = drm_fb_helper_pan_display, | ||
122 | .fb_blank = drm_fb_helper_blank, | ||
123 | .fb_setcmap = drm_fb_helper_setcmap, | ||
124 | .fb_debug_enter = drm_fb_helper_debug_enter, | ||
125 | .fb_debug_leave = drm_fb_helper_debug_leave, | ||
126 | }; | ||
127 | |||
128 | static int astfb_create_object(struct ast_fbdev *afbdev, | ||
129 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
130 | struct drm_gem_object **gobj_p) | ||
131 | { | ||
132 | struct drm_device *dev = afbdev->helper.dev; | ||
133 | u32 bpp, depth; | ||
134 | u32 size; | ||
135 | struct drm_gem_object *gobj; | ||
136 | |||
137 | int ret = 0; | ||
138 | drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); | ||
139 | |||
140 | size = mode_cmd->pitches[0] * mode_cmd->height; | ||
141 | ret = ast_gem_create(dev, size, true, &gobj); | ||
142 | if (ret) | ||
143 | return ret; | ||
144 | |||
145 | *gobj_p = gobj; | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static int astfb_create(struct ast_fbdev *afbdev, | ||
150 | struct drm_fb_helper_surface_size *sizes) | ||
151 | { | ||
152 | struct drm_device *dev = afbdev->helper.dev; | ||
153 | struct drm_mode_fb_cmd2 mode_cmd; | ||
154 | struct drm_framebuffer *fb; | ||
155 | struct fb_info *info; | ||
156 | int size, ret; | ||
157 | struct device *device = &dev->pdev->dev; | ||
158 | void *sysram; | ||
159 | struct drm_gem_object *gobj = NULL; | ||
160 | struct ast_bo *bo = NULL; | ||
161 | mode_cmd.width = sizes->surface_width; | ||
162 | mode_cmd.height = sizes->surface_height; | ||
163 | mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7)/8); | ||
164 | |||
165 | mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, | ||
166 | sizes->surface_depth); | ||
167 | |||
168 | size = mode_cmd.pitches[0] * mode_cmd.height; | ||
169 | |||
170 | ret = astfb_create_object(afbdev, &mode_cmd, &gobj); | ||
171 | if (ret) { | ||
172 | DRM_ERROR("failed to create fbcon backing object %d\n", ret); | ||
173 | return ret; | ||
174 | } | ||
175 | bo = gem_to_ast_bo(gobj); | ||
176 | |||
177 | sysram = vmalloc(size); | ||
178 | if (!sysram) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | info = framebuffer_alloc(0, device); | ||
182 | if (!info) { | ||
183 | ret = -ENOMEM; | ||
184 | goto out; | ||
185 | } | ||
186 | info->par = afbdev; | ||
187 | |||
188 | ret = ast_framebuffer_init(dev, &afbdev->afb, &mode_cmd, gobj); | ||
189 | if (ret) | ||
190 | goto out; | ||
191 | |||
192 | afbdev->sysram = sysram; | ||
193 | afbdev->size = size; | ||
194 | |||
195 | fb = &afbdev->afb.base; | ||
196 | afbdev->helper.fb = fb; | ||
197 | afbdev->helper.fbdev = info; | ||
198 | |||
199 | strcpy(info->fix.id, "astdrmfb"); | ||
200 | |||
201 | info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; | ||
202 | info->fbops = &astfb_ops; | ||
203 | |||
204 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
205 | if (ret) { | ||
206 | ret = -ENOMEM; | ||
207 | goto out; | ||
208 | } | ||
209 | |||
210 | info->apertures = alloc_apertures(1); | ||
211 | if (!info->apertures) { | ||
212 | ret = -ENOMEM; | ||
213 | goto out; | ||
214 | } | ||
215 | info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0); | ||
216 | info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); | ||
217 | |||
218 | drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||
219 | drm_fb_helper_fill_var(info, &afbdev->helper, sizes->fb_width, sizes->fb_height); | ||
220 | |||
221 | info->screen_base = sysram; | ||
222 | info->screen_size = size; | ||
223 | |||
224 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
225 | |||
226 | DRM_DEBUG_KMS("allocated %dx%d\n", | ||
227 | fb->width, fb->height); | ||
228 | |||
229 | return 0; | ||
230 | out: | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static void ast_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
235 | u16 blue, int regno) | ||
236 | { | ||
237 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); | ||
238 | ast_crtc->lut_r[regno] = red >> 8; | ||
239 | ast_crtc->lut_g[regno] = green >> 8; | ||
240 | ast_crtc->lut_b[regno] = blue >> 8; | ||
241 | } | ||
242 | |||
243 | static void ast_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
244 | u16 *blue, int regno) | ||
245 | { | ||
246 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); | ||
247 | *red = ast_crtc->lut_r[regno] << 8; | ||
248 | *green = ast_crtc->lut_g[regno] << 8; | ||
249 | *blue = ast_crtc->lut_b[regno] << 8; | ||
250 | } | ||
251 | |||
252 | static int ast_find_or_create_single(struct drm_fb_helper *helper, | ||
253 | struct drm_fb_helper_surface_size *sizes) | ||
254 | { | ||
255 | struct ast_fbdev *afbdev = (struct ast_fbdev *)helper; | ||
256 | int new_fb = 0; | ||
257 | int ret; | ||
258 | |||
259 | if (!helper->fb) { | ||
260 | ret = astfb_create(afbdev, sizes); | ||
261 | if (ret) | ||
262 | return ret; | ||
263 | new_fb = 1; | ||
264 | } | ||
265 | return new_fb; | ||
266 | } | ||
267 | |||
268 | static struct drm_fb_helper_funcs ast_fb_helper_funcs = { | ||
269 | .gamma_set = ast_fb_gamma_set, | ||
270 | .gamma_get = ast_fb_gamma_get, | ||
271 | .fb_probe = ast_find_or_create_single, | ||
272 | }; | ||
273 | |||
274 | static void ast_fbdev_destroy(struct drm_device *dev, | ||
275 | struct ast_fbdev *afbdev) | ||
276 | { | ||
277 | struct fb_info *info; | ||
278 | struct ast_framebuffer *afb = &afbdev->afb; | ||
279 | if (afbdev->helper.fbdev) { | ||
280 | info = afbdev->helper.fbdev; | ||
281 | unregister_framebuffer(info); | ||
282 | if (info->cmap.len) | ||
283 | fb_dealloc_cmap(&info->cmap); | ||
284 | framebuffer_release(info); | ||
285 | } | ||
286 | |||
287 | if (afb->obj) { | ||
288 | drm_gem_object_unreference_unlocked(afb->obj); | ||
289 | afb->obj = NULL; | ||
290 | } | ||
291 | drm_fb_helper_fini(&afbdev->helper); | ||
292 | |||
293 | vfree(afbdev->sysram); | ||
294 | drm_framebuffer_cleanup(&afb->base); | ||
295 | } | ||
296 | |||
297 | int ast_fbdev_init(struct drm_device *dev) | ||
298 | { | ||
299 | struct ast_private *ast = dev->dev_private; | ||
300 | struct ast_fbdev *afbdev; | ||
301 | int ret; | ||
302 | |||
303 | afbdev = kzalloc(sizeof(struct ast_fbdev), GFP_KERNEL); | ||
304 | if (!afbdev) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | ast->fbdev = afbdev; | ||
308 | afbdev->helper.funcs = &ast_fb_helper_funcs; | ||
309 | ret = drm_fb_helper_init(dev, &afbdev->helper, | ||
310 | 1, 1); | ||
311 | if (ret) { | ||
312 | kfree(afbdev); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | drm_fb_helper_single_add_all_connectors(&afbdev->helper); | ||
317 | drm_fb_helper_initial_config(&afbdev->helper, 32); | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | void ast_fbdev_fini(struct drm_device *dev) | ||
322 | { | ||
323 | struct ast_private *ast = dev->dev_private; | ||
324 | |||
325 | if (!ast->fbdev) | ||
326 | return; | ||
327 | |||
328 | ast_fbdev_destroy(dev, ast->fbdev); | ||
329 | kfree(ast->fbdev); | ||
330 | ast->fbdev = NULL; | ||
331 | } | ||
332 | |||
333 | void ast_fbdev_set_suspend(struct drm_device *dev, int state) | ||
334 | { | ||
335 | struct ast_private *ast = dev->dev_private; | ||
336 | |||
337 | if (!ast->fbdev) | ||
338 | return; | ||
339 | |||
340 | fb_set_suspend(ast->fbdev->helper.fbdev, state); | ||
341 | } | ||
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c new file mode 100644 index 000000000000..95ae55b8214b --- /dev/null +++ b/drivers/gpu/drm/ast/ast_main.c | |||
@@ -0,0 +1,527 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the | ||
6 | * "Software"), to deal in the Software without restriction, including | ||
7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
9 | * permit persons to whom the Software is furnished to do so, subject to | ||
10 | * the following conditions: | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * The above copyright notice and this permission notice (including the | ||
21 | * next paragraph) shall be included in all copies or substantial portions | ||
22 | * of the Software. | ||
23 | * | ||
24 | */ | ||
25 | /* | ||
26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
27 | */ | ||
28 | #include "drmP.h" | ||
29 | #include "ast_drv.h" | ||
30 | |||
31 | |||
32 | #include "drm_fb_helper.h" | ||
33 | #include "drm_crtc_helper.h" | ||
34 | |||
35 | #include "ast_dram_tables.h" | ||
36 | |||
37 | void ast_set_index_reg_mask(struct ast_private *ast, | ||
38 | uint32_t base, uint8_t index, | ||
39 | uint8_t mask, uint8_t val) | ||
40 | { | ||
41 | u8 tmp; | ||
42 | ast_io_write8(ast, base, index); | ||
43 | tmp = (ast_io_read8(ast, base + 1) & mask) | val; | ||
44 | ast_set_index_reg(ast, base, index, tmp); | ||
45 | } | ||
46 | |||
47 | uint8_t ast_get_index_reg(struct ast_private *ast, | ||
48 | uint32_t base, uint8_t index) | ||
49 | { | ||
50 | uint8_t ret; | ||
51 | ast_io_write8(ast, base, index); | ||
52 | ret = ast_io_read8(ast, base + 1); | ||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | uint8_t ast_get_index_reg_mask(struct ast_private *ast, | ||
57 | uint32_t base, uint8_t index, uint8_t mask) | ||
58 | { | ||
59 | uint8_t ret; | ||
60 | ast_io_write8(ast, base, index); | ||
61 | ret = ast_io_read8(ast, base + 1) & mask; | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | |||
66 | static int ast_detect_chip(struct drm_device *dev) | ||
67 | { | ||
68 | struct ast_private *ast = dev->dev_private; | ||
69 | |||
70 | if (dev->pdev->device == PCI_CHIP_AST1180) { | ||
71 | ast->chip = AST1100; | ||
72 | DRM_INFO("AST 1180 detected\n"); | ||
73 | } else { | ||
74 | if (dev->pdev->revision >= 0x20) { | ||
75 | ast->chip = AST2300; | ||
76 | DRM_INFO("AST 2300 detected\n"); | ||
77 | } else if (dev->pdev->revision >= 0x10) { | ||
78 | uint32_t data; | ||
79 | ast_write32(ast, 0xf004, 0x1e6e0000); | ||
80 | ast_write32(ast, 0xf000, 0x1); | ||
81 | |||
82 | data = ast_read32(ast, 0x1207c); | ||
83 | switch (data & 0x0300) { | ||
84 | case 0x0200: | ||
85 | ast->chip = AST1100; | ||
86 | DRM_INFO("AST 1100 detected\n"); | ||
87 | break; | ||
88 | case 0x0100: | ||
89 | ast->chip = AST2200; | ||
90 | DRM_INFO("AST 2200 detected\n"); | ||
91 | break; | ||
92 | case 0x0000: | ||
93 | ast->chip = AST2150; | ||
94 | DRM_INFO("AST 2150 detected\n"); | ||
95 | break; | ||
96 | default: | ||
97 | ast->chip = AST2100; | ||
98 | DRM_INFO("AST 2100 detected\n"); | ||
99 | break; | ||
100 | } | ||
101 | ast->vga2_clone = false; | ||
102 | } else { | ||
103 | ast->chip = 2000; | ||
104 | DRM_INFO("AST 2000 detected\n"); | ||
105 | } | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int ast_get_dram_info(struct drm_device *dev) | ||
111 | { | ||
112 | struct ast_private *ast = dev->dev_private; | ||
113 | uint32_t data, data2; | ||
114 | uint32_t denum, num, div, ref_pll; | ||
115 | |||
116 | ast_write32(ast, 0xf004, 0x1e6e0000); | ||
117 | ast_write32(ast, 0xf000, 0x1); | ||
118 | |||
119 | |||
120 | ast_write32(ast, 0x10000, 0xfc600309); | ||
121 | |||
122 | do { | ||
123 | ; | ||
124 | } while (ast_read32(ast, 0x10000) != 0x01); | ||
125 | data = ast_read32(ast, 0x10004); | ||
126 | |||
127 | if (data & 0x400) | ||
128 | ast->dram_bus_width = 16; | ||
129 | else | ||
130 | ast->dram_bus_width = 32; | ||
131 | |||
132 | if (ast->chip == AST2300) { | ||
133 | switch (data & 0x03) { | ||
134 | case 0: | ||
135 | ast->dram_type = AST_DRAM_512Mx16; | ||
136 | break; | ||
137 | default: | ||
138 | case 1: | ||
139 | ast->dram_type = AST_DRAM_1Gx16; | ||
140 | break; | ||
141 | case 2: | ||
142 | ast->dram_type = AST_DRAM_2Gx16; | ||
143 | break; | ||
144 | case 3: | ||
145 | ast->dram_type = AST_DRAM_4Gx16; | ||
146 | break; | ||
147 | } | ||
148 | } else { | ||
149 | switch (data & 0x0c) { | ||
150 | case 0: | ||
151 | case 4: | ||
152 | ast->dram_type = AST_DRAM_512Mx16; | ||
153 | break; | ||
154 | case 8: | ||
155 | if (data & 0x40) | ||
156 | ast->dram_type = AST_DRAM_1Gx16; | ||
157 | else | ||
158 | ast->dram_type = AST_DRAM_512Mx32; | ||
159 | break; | ||
160 | case 0xc: | ||
161 | ast->dram_type = AST_DRAM_1Gx32; | ||
162 | break; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | data = ast_read32(ast, 0x10120); | ||
167 | data2 = ast_read32(ast, 0x10170); | ||
168 | if (data2 & 0x2000) | ||
169 | ref_pll = 14318; | ||
170 | else | ||
171 | ref_pll = 12000; | ||
172 | |||
173 | denum = data & 0x1f; | ||
174 | num = (data & 0x3fe0) >> 5; | ||
175 | data = (data & 0xc000) >> 14; | ||
176 | switch (data) { | ||
177 | case 3: | ||
178 | div = 0x4; | ||
179 | break; | ||
180 | case 2: | ||
181 | case 1: | ||
182 | div = 0x2; | ||
183 | break; | ||
184 | default: | ||
185 | div = 0x1; | ||
186 | break; | ||
187 | } | ||
188 | ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | uint32_t ast_get_max_dclk(struct drm_device *dev, int bpp) | ||
193 | { | ||
194 | struct ast_private *ast = dev->dev_private; | ||
195 | uint32_t dclk, jreg; | ||
196 | uint32_t dram_bus_width, mclk, dram_bandwidth, actual_dram_bandwidth, dram_efficency = 500; | ||
197 | |||
198 | dram_bus_width = ast->dram_bus_width; | ||
199 | mclk = ast->mclk; | ||
200 | |||
201 | if (ast->chip == AST2100 || | ||
202 | ast->chip == AST1100 || | ||
203 | ast->chip == AST2200 || | ||
204 | ast->chip == AST2150 || | ||
205 | ast->dram_bus_width == 16) | ||
206 | dram_efficency = 600; | ||
207 | else if (ast->chip == AST2300) | ||
208 | dram_efficency = 400; | ||
209 | |||
210 | dram_bandwidth = mclk * dram_bus_width * 2 / 8; | ||
211 | actual_dram_bandwidth = dram_bandwidth * dram_efficency / 1000; | ||
212 | |||
213 | if (ast->chip == AST1180) | ||
214 | dclk = actual_dram_bandwidth / ((bpp + 1) / 8); | ||
215 | else { | ||
216 | jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); | ||
217 | if ((jreg & 0x08) && (ast->chip == AST2000)) | ||
218 | dclk = actual_dram_bandwidth / ((bpp + 1 + 16) / 8); | ||
219 | else if ((jreg & 0x08) && (bpp == 8)) | ||
220 | dclk = actual_dram_bandwidth / ((bpp + 1 + 24) / 8); | ||
221 | else | ||
222 | dclk = actual_dram_bandwidth / ((bpp + 1) / 8); | ||
223 | } | ||
224 | |||
225 | if (ast->chip == AST2100 || | ||
226 | ast->chip == AST2200 || | ||
227 | ast->chip == AST2300 || | ||
228 | ast->chip == AST1180) { | ||
229 | if (dclk > 200) | ||
230 | dclk = 200; | ||
231 | } else { | ||
232 | if (dclk > 165) | ||
233 | dclk = 165; | ||
234 | } | ||
235 | |||
236 | return dclk; | ||
237 | } | ||
238 | |||
239 | static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb) | ||
240 | { | ||
241 | struct ast_framebuffer *ast_fb = to_ast_framebuffer(fb); | ||
242 | if (ast_fb->obj) | ||
243 | drm_gem_object_unreference_unlocked(ast_fb->obj); | ||
244 | |||
245 | drm_framebuffer_cleanup(fb); | ||
246 | kfree(fb); | ||
247 | } | ||
248 | |||
249 | static int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
250 | struct drm_file *file, | ||
251 | unsigned int *handle) | ||
252 | { | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | static const struct drm_framebuffer_funcs ast_fb_funcs = { | ||
257 | .destroy = ast_user_framebuffer_destroy, | ||
258 | .create_handle = ast_user_framebuffer_create_handle, | ||
259 | }; | ||
260 | |||
261 | |||
262 | int ast_framebuffer_init(struct drm_device *dev, | ||
263 | struct ast_framebuffer *ast_fb, | ||
264 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
265 | struct drm_gem_object *obj) | ||
266 | { | ||
267 | int ret; | ||
268 | |||
269 | ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs); | ||
270 | if (ret) { | ||
271 | DRM_ERROR("framebuffer init failed %d\n", ret); | ||
272 | return ret; | ||
273 | } | ||
274 | drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd); | ||
275 | ast_fb->obj = obj; | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static struct drm_framebuffer * | ||
280 | ast_user_framebuffer_create(struct drm_device *dev, | ||
281 | struct drm_file *filp, | ||
282 | struct drm_mode_fb_cmd2 *mode_cmd) | ||
283 | { | ||
284 | struct drm_gem_object *obj; | ||
285 | struct ast_framebuffer *ast_fb; | ||
286 | int ret; | ||
287 | |||
288 | obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); | ||
289 | if (obj == NULL) | ||
290 | return ERR_PTR(-ENOENT); | ||
291 | |||
292 | ast_fb = kzalloc(sizeof(*ast_fb), GFP_KERNEL); | ||
293 | if (!ast_fb) { | ||
294 | drm_gem_object_unreference_unlocked(obj); | ||
295 | return ERR_PTR(-ENOMEM); | ||
296 | } | ||
297 | |||
298 | ret = ast_framebuffer_init(dev, ast_fb, mode_cmd, obj); | ||
299 | if (ret) { | ||
300 | drm_gem_object_unreference_unlocked(obj); | ||
301 | kfree(ast_fb); | ||
302 | return ERR_PTR(ret); | ||
303 | } | ||
304 | return &ast_fb->base; | ||
305 | } | ||
306 | |||
307 | static const struct drm_mode_config_funcs ast_mode_funcs = { | ||
308 | .fb_create = ast_user_framebuffer_create, | ||
309 | }; | ||
310 | |||
311 | static u32 ast_get_vram_info(struct drm_device *dev) | ||
312 | { | ||
313 | struct ast_private *ast = dev->dev_private; | ||
314 | u8 jreg; | ||
315 | |||
316 | ast_open_key(ast); | ||
317 | |||
318 | jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff); | ||
319 | switch (jreg & 3) { | ||
320 | case 0: return AST_VIDMEM_SIZE_8M; | ||
321 | case 1: return AST_VIDMEM_SIZE_16M; | ||
322 | case 2: return AST_VIDMEM_SIZE_32M; | ||
323 | case 3: return AST_VIDMEM_SIZE_64M; | ||
324 | } | ||
325 | return AST_VIDMEM_DEFAULT_SIZE; | ||
326 | } | ||
327 | |||
328 | int ast_driver_load(struct drm_device *dev, unsigned long flags) | ||
329 | { | ||
330 | struct ast_private *ast; | ||
331 | int ret = 0; | ||
332 | |||
333 | ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL); | ||
334 | if (!ast) | ||
335 | return -ENOMEM; | ||
336 | |||
337 | dev->dev_private = ast; | ||
338 | ast->dev = dev; | ||
339 | |||
340 | ast->regs = pci_iomap(dev->pdev, 1, 0); | ||
341 | if (!ast->regs) { | ||
342 | ret = -EIO; | ||
343 | goto out_free; | ||
344 | } | ||
345 | ast->ioregs = pci_iomap(dev->pdev, 2, 0); | ||
346 | if (!ast->ioregs) { | ||
347 | ret = -EIO; | ||
348 | goto out_free; | ||
349 | } | ||
350 | |||
351 | ast_detect_chip(dev); | ||
352 | |||
353 | if (ast->chip != AST1180) { | ||
354 | ast_get_dram_info(dev); | ||
355 | ast->vram_size = ast_get_vram_info(dev); | ||
356 | DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size); | ||
357 | } | ||
358 | |||
359 | ret = ast_mm_init(ast); | ||
360 | if (ret) | ||
361 | goto out_free; | ||
362 | |||
363 | drm_mode_config_init(dev); | ||
364 | |||
365 | dev->mode_config.funcs = (void *)&ast_mode_funcs; | ||
366 | dev->mode_config.min_width = 0; | ||
367 | dev->mode_config.min_height = 0; | ||
368 | dev->mode_config.preferred_depth = 24; | ||
369 | dev->mode_config.prefer_shadow = 1; | ||
370 | |||
371 | if (ast->chip == AST2100 || | ||
372 | ast->chip == AST2200 || | ||
373 | ast->chip == AST2300 || | ||
374 | ast->chip == AST1180) { | ||
375 | dev->mode_config.max_width = 1920; | ||
376 | dev->mode_config.max_height = 2048; | ||
377 | } else { | ||
378 | dev->mode_config.max_width = 1600; | ||
379 | dev->mode_config.max_height = 1200; | ||
380 | } | ||
381 | |||
382 | ret = ast_mode_init(dev); | ||
383 | if (ret) | ||
384 | goto out_free; | ||
385 | |||
386 | ret = ast_fbdev_init(dev); | ||
387 | if (ret) | ||
388 | goto out_free; | ||
389 | |||
390 | return 0; | ||
391 | out_free: | ||
392 | kfree(ast); | ||
393 | dev->dev_private = NULL; | ||
394 | return ret; | ||
395 | } | ||
396 | |||
397 | int ast_driver_unload(struct drm_device *dev) | ||
398 | { | ||
399 | struct ast_private *ast = dev->dev_private; | ||
400 | |||
401 | ast_mode_fini(dev); | ||
402 | ast_fbdev_fini(dev); | ||
403 | drm_mode_config_cleanup(dev); | ||
404 | |||
405 | ast_mm_fini(ast); | ||
406 | pci_iounmap(dev->pdev, ast->ioregs); | ||
407 | pci_iounmap(dev->pdev, ast->regs); | ||
408 | kfree(ast); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | int ast_gem_create(struct drm_device *dev, | ||
413 | u32 size, bool iskernel, | ||
414 | struct drm_gem_object **obj) | ||
415 | { | ||
416 | struct ast_bo *astbo; | ||
417 | int ret; | ||
418 | |||
419 | *obj = NULL; | ||
420 | |||
421 | size = roundup(size, PAGE_SIZE); | ||
422 | if (size == 0) | ||
423 | return -EINVAL; | ||
424 | |||
425 | ret = ast_bo_create(dev, size, 0, 0, &astbo); | ||
426 | if (ret) { | ||
427 | if (ret != -ERESTARTSYS) | ||
428 | DRM_ERROR("failed to allocate GEM object\n"); | ||
429 | return ret; | ||
430 | } | ||
431 | *obj = &astbo->gem; | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | int ast_dumb_create(struct drm_file *file, | ||
436 | struct drm_device *dev, | ||
437 | struct drm_mode_create_dumb *args) | ||
438 | { | ||
439 | int ret; | ||
440 | struct drm_gem_object *gobj; | ||
441 | u32 handle; | ||
442 | |||
443 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
444 | args->size = args->pitch * args->height; | ||
445 | |||
446 | ret = ast_gem_create(dev, args->size, false, | ||
447 | &gobj); | ||
448 | if (ret) | ||
449 | return ret; | ||
450 | |||
451 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
452 | drm_gem_object_unreference_unlocked(gobj); | ||
453 | if (ret) | ||
454 | return ret; | ||
455 | |||
456 | args->handle = handle; | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | int ast_dumb_destroy(struct drm_file *file, | ||
461 | struct drm_device *dev, | ||
462 | uint32_t handle) | ||
463 | { | ||
464 | return drm_gem_handle_delete(file, handle); | ||
465 | } | ||
466 | |||
467 | int ast_gem_init_object(struct drm_gem_object *obj) | ||
468 | { | ||
469 | BUG(); | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | void ast_bo_unref(struct ast_bo **bo) | ||
474 | { | ||
475 | struct ttm_buffer_object *tbo; | ||
476 | |||
477 | if ((*bo) == NULL) | ||
478 | return; | ||
479 | |||
480 | tbo = &((*bo)->bo); | ||
481 | ttm_bo_unref(&tbo); | ||
482 | if (tbo == NULL) | ||
483 | *bo = NULL; | ||
484 | |||
485 | } | ||
486 | void ast_gem_free_object(struct drm_gem_object *obj) | ||
487 | { | ||
488 | struct ast_bo *ast_bo = gem_to_ast_bo(obj); | ||
489 | |||
490 | if (!ast_bo) | ||
491 | return; | ||
492 | ast_bo_unref(&ast_bo); | ||
493 | } | ||
494 | |||
495 | |||
496 | static inline u64 ast_bo_mmap_offset(struct ast_bo *bo) | ||
497 | { | ||
498 | return bo->bo.addr_space_offset; | ||
499 | } | ||
500 | int | ||
501 | ast_dumb_mmap_offset(struct drm_file *file, | ||
502 | struct drm_device *dev, | ||
503 | uint32_t handle, | ||
504 | uint64_t *offset) | ||
505 | { | ||
506 | struct drm_gem_object *obj; | ||
507 | int ret; | ||
508 | struct ast_bo *bo; | ||
509 | |||
510 | mutex_lock(&dev->struct_mutex); | ||
511 | obj = drm_gem_object_lookup(dev, file, handle); | ||
512 | if (obj == NULL) { | ||
513 | ret = -ENOENT; | ||
514 | goto out_unlock; | ||
515 | } | ||
516 | |||
517 | bo = gem_to_ast_bo(obj); | ||
518 | *offset = ast_bo_mmap_offset(bo); | ||
519 | |||
520 | drm_gem_object_unreference(obj); | ||
521 | ret = 0; | ||
522 | out_unlock: | ||
523 | mutex_unlock(&dev->struct_mutex); | ||
524 | return ret; | ||
525 | |||
526 | } | ||
527 | |||
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c new file mode 100644 index 000000000000..65f9d231af14 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_mode.c | |||
@@ -0,0 +1,1160 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * Parts based on xf86-video-ast | ||
4 | * Copyright (c) 2005 ASPEED Technology Inc. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
18 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
20 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * The above copyright notice and this permission notice (including the | ||
23 | * next paragraph) shall be included in all copies or substantial portions | ||
24 | * of the Software. | ||
25 | * | ||
26 | */ | ||
27 | /* | ||
28 | * Authors: Dave Airlie <airlied@redhat.com> | ||
29 | */ | ||
30 | #include <linux/export.h> | ||
31 | #include "drmP.h" | ||
32 | #include "drm_crtc.h" | ||
33 | #include "drm_crtc_helper.h" | ||
34 | #include "ast_drv.h" | ||
35 | |||
36 | #include "ast_tables.h" | ||
37 | |||
38 | static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev); | ||
39 | static void ast_i2c_destroy(struct ast_i2c_chan *i2c); | ||
40 | static int ast_cursor_set(struct drm_crtc *crtc, | ||
41 | struct drm_file *file_priv, | ||
42 | uint32_t handle, | ||
43 | uint32_t width, | ||
44 | uint32_t height); | ||
45 | static int ast_cursor_move(struct drm_crtc *crtc, | ||
46 | int x, int y); | ||
47 | |||
48 | static inline void ast_load_palette_index(struct ast_private *ast, | ||
49 | u8 index, u8 red, u8 green, | ||
50 | u8 blue) | ||
51 | { | ||
52 | ast_io_write8(ast, AST_IO_DAC_INDEX_WRITE, index); | ||
53 | ast_io_read8(ast, AST_IO_SEQ_PORT); | ||
54 | ast_io_write8(ast, AST_IO_DAC_DATA, red); | ||
55 | ast_io_read8(ast, AST_IO_SEQ_PORT); | ||
56 | ast_io_write8(ast, AST_IO_DAC_DATA, green); | ||
57 | ast_io_read8(ast, AST_IO_SEQ_PORT); | ||
58 | ast_io_write8(ast, AST_IO_DAC_DATA, blue); | ||
59 | ast_io_read8(ast, AST_IO_SEQ_PORT); | ||
60 | } | ||
61 | |||
62 | static void ast_crtc_load_lut(struct drm_crtc *crtc) | ||
63 | { | ||
64 | struct ast_private *ast = crtc->dev->dev_private; | ||
65 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); | ||
66 | int i; | ||
67 | |||
68 | if (!crtc->enabled) | ||
69 | return; | ||
70 | |||
71 | for (i = 0; i < 256; i++) | ||
72 | ast_load_palette_index(ast, i, ast_crtc->lut_r[i], | ||
73 | ast_crtc->lut_g[i], ast_crtc->lut_b[i]); | ||
74 | } | ||
75 | |||
76 | static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
77 | struct drm_display_mode *adjusted_mode, | ||
78 | struct ast_vbios_mode_info *vbios_mode) | ||
79 | { | ||
80 | struct ast_private *ast = crtc->dev->dev_private; | ||
81 | u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate; | ||
82 | u32 hborder, vborder; | ||
83 | |||
84 | switch (crtc->fb->bits_per_pixel) { | ||
85 | case 8: | ||
86 | vbios_mode->std_table = &vbios_stdtable[VGAModeIndex]; | ||
87 | color_index = VGAModeIndex - 1; | ||
88 | break; | ||
89 | case 16: | ||
90 | vbios_mode->std_table = &vbios_stdtable[HiCModeIndex]; | ||
91 | color_index = HiCModeIndex; | ||
92 | break; | ||
93 | case 24: | ||
94 | case 32: | ||
95 | vbios_mode->std_table = &vbios_stdtable[TrueCModeIndex]; | ||
96 | color_index = TrueCModeIndex; | ||
97 | break; | ||
98 | default: | ||
99 | return false; | ||
100 | } | ||
101 | |||
102 | switch (crtc->mode.crtc_hdisplay) { | ||
103 | case 640: | ||
104 | vbios_mode->enh_table = &res_640x480[refresh_rate_index]; | ||
105 | break; | ||
106 | case 800: | ||
107 | vbios_mode->enh_table = &res_800x600[refresh_rate_index]; | ||
108 | break; | ||
109 | case 1024: | ||
110 | vbios_mode->enh_table = &res_1024x768[refresh_rate_index]; | ||
111 | break; | ||
112 | case 1280: | ||
113 | if (crtc->mode.crtc_vdisplay == 800) | ||
114 | vbios_mode->enh_table = &res_1280x800[refresh_rate_index]; | ||
115 | else | ||
116 | vbios_mode->enh_table = &res_1280x1024[refresh_rate_index]; | ||
117 | break; | ||
118 | case 1440: | ||
119 | vbios_mode->enh_table = &res_1440x900[refresh_rate_index]; | ||
120 | break; | ||
121 | case 1600: | ||
122 | vbios_mode->enh_table = &res_1600x1200[refresh_rate_index]; | ||
123 | break; | ||
124 | case 1680: | ||
125 | vbios_mode->enh_table = &res_1680x1050[refresh_rate_index]; | ||
126 | break; | ||
127 | case 1920: | ||
128 | if (crtc->mode.crtc_vdisplay == 1080) | ||
129 | vbios_mode->enh_table = &res_1920x1080[refresh_rate_index]; | ||
130 | else | ||
131 | vbios_mode->enh_table = &res_1920x1200[refresh_rate_index]; | ||
132 | break; | ||
133 | default: | ||
134 | return false; | ||
135 | } | ||
136 | |||
137 | refresh_rate = drm_mode_vrefresh(mode); | ||
138 | while (vbios_mode->enh_table->refresh_rate < refresh_rate) { | ||
139 | vbios_mode->enh_table++; | ||
140 | if ((vbios_mode->enh_table->refresh_rate > refresh_rate) || | ||
141 | (vbios_mode->enh_table->refresh_rate == 0xff)) { | ||
142 | vbios_mode->enh_table--; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0; | ||
148 | vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0; | ||
149 | |||
150 | adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht; | ||
151 | adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder; | ||
152 | adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder; | ||
153 | adjusted_mode->crtc_hsync_start = vbios_mode->enh_table->hde + hborder + | ||
154 | vbios_mode->enh_table->hfp; | ||
155 | adjusted_mode->crtc_hsync_end = (vbios_mode->enh_table->hde + hborder + | ||
156 | vbios_mode->enh_table->hfp + | ||
157 | vbios_mode->enh_table->hsync); | ||
158 | |||
159 | adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt; | ||
160 | adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder; | ||
161 | adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder; | ||
162 | adjusted_mode->crtc_vsync_start = vbios_mode->enh_table->vde + vborder + | ||
163 | vbios_mode->enh_table->vfp; | ||
164 | adjusted_mode->crtc_vsync_end = (vbios_mode->enh_table->vde + vborder + | ||
165 | vbios_mode->enh_table->vfp + | ||
166 | vbios_mode->enh_table->vsync); | ||
167 | |||
168 | refresh_rate_index = vbios_mode->enh_table->refresh_rate_index; | ||
169 | mode_id = vbios_mode->enh_table->mode_id; | ||
170 | |||
171 | if (ast->chip == AST1180) { | ||
172 | /* TODO 1180 */ | ||
173 | } else { | ||
174 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8c, (u8)((color_index & 0xf) << 4)); | ||
175 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff); | ||
176 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff); | ||
177 | |||
178 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8); | ||
179 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel); | ||
180 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000); | ||
181 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay); | ||
182 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8); | ||
183 | |||
184 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay); | ||
185 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8); | ||
186 | } | ||
187 | |||
188 | return true; | ||
189 | |||
190 | |||
191 | } | ||
192 | static void ast_set_std_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
193 | struct ast_vbios_mode_info *vbios_mode) | ||
194 | { | ||
195 | struct ast_private *ast = crtc->dev->dev_private; | ||
196 | struct ast_vbios_stdtable *stdtable; | ||
197 | u32 i; | ||
198 | u8 jreg; | ||
199 | |||
200 | stdtable = vbios_mode->std_table; | ||
201 | |||
202 | jreg = stdtable->misc; | ||
203 | ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg); | ||
204 | |||
205 | /* Set SEQ */ | ||
206 | ast_set_index_reg(ast, AST_IO_SEQ_PORT, 0x00, 0x03); | ||
207 | for (i = 0; i < 4; i++) { | ||
208 | jreg = stdtable->seq[i]; | ||
209 | if (!i) | ||
210 | jreg |= 0x20; | ||
211 | ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1) , jreg); | ||
212 | } | ||
213 | |||
214 | /* Set CRTC */ | ||
215 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00); | ||
216 | for (i = 0; i < 25; i++) | ||
217 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]); | ||
218 | |||
219 | /* set AR */ | ||
220 | jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ); | ||
221 | for (i = 0; i < 20; i++) { | ||
222 | jreg = stdtable->ar[i]; | ||
223 | ast_io_write8(ast, AST_IO_AR_PORT_WRITE, (u8)i); | ||
224 | ast_io_write8(ast, AST_IO_AR_PORT_WRITE, jreg); | ||
225 | } | ||
226 | ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x14); | ||
227 | ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x00); | ||
228 | |||
229 | jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ); | ||
230 | ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x20); | ||
231 | |||
232 | /* Set GR */ | ||
233 | for (i = 0; i < 9; i++) | ||
234 | ast_set_index_reg(ast, AST_IO_GR_PORT, i, stdtable->gr[i]); | ||
235 | } | ||
236 | |||
237 | static void ast_set_crtc_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
238 | struct ast_vbios_mode_info *vbios_mode) | ||
239 | { | ||
240 | struct ast_private *ast = crtc->dev->dev_private; | ||
241 | u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0; | ||
242 | u16 temp; | ||
243 | |||
244 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00); | ||
245 | |||
246 | temp = (mode->crtc_htotal >> 3) - 5; | ||
247 | if (temp & 0x100) | ||
248 | jregAC |= 0x01; /* HT D[8] */ | ||
249 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x00, 0x00, temp); | ||
250 | |||
251 | temp = (mode->crtc_hdisplay >> 3) - 1; | ||
252 | if (temp & 0x100) | ||
253 | jregAC |= 0x04; /* HDE D[8] */ | ||
254 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x01, 0x00, temp); | ||
255 | |||
256 | temp = (mode->crtc_hblank_start >> 3) - 1; | ||
257 | if (temp & 0x100) | ||
258 | jregAC |= 0x10; /* HBS D[8] */ | ||
259 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x02, 0x00, temp); | ||
260 | |||
261 | temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f; | ||
262 | if (temp & 0x20) | ||
263 | jreg05 |= 0x80; /* HBE D[5] */ | ||
264 | if (temp & 0x40) | ||
265 | jregAD |= 0x01; /* HBE D[5] */ | ||
266 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x03, 0xE0, (temp & 0x1f)); | ||
267 | |||
268 | temp = (mode->crtc_hsync_start >> 3) - 1; | ||
269 | if (temp & 0x100) | ||
270 | jregAC |= 0x40; /* HRS D[5] */ | ||
271 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x04, 0x00, temp); | ||
272 | |||
273 | temp = ((mode->crtc_hsync_end >> 3) - 1) & 0x3f; | ||
274 | if (temp & 0x20) | ||
275 | jregAD |= 0x04; /* HRE D[5] */ | ||
276 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05)); | ||
277 | |||
278 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAC, 0x00, jregAC); | ||
279 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAD, 0x00, jregAD); | ||
280 | |||
281 | /* vert timings */ | ||
282 | temp = (mode->crtc_vtotal) - 2; | ||
283 | if (temp & 0x100) | ||
284 | jreg07 |= 0x01; | ||
285 | if (temp & 0x200) | ||
286 | jreg07 |= 0x20; | ||
287 | if (temp & 0x400) | ||
288 | jregAE |= 0x01; | ||
289 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x06, 0x00, temp); | ||
290 | |||
291 | temp = (mode->crtc_vsync_start) - 1; | ||
292 | if (temp & 0x100) | ||
293 | jreg07 |= 0x04; | ||
294 | if (temp & 0x200) | ||
295 | jreg07 |= 0x80; | ||
296 | if (temp & 0x400) | ||
297 | jregAE |= 0x08; | ||
298 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x10, 0x00, temp); | ||
299 | |||
300 | temp = (mode->crtc_vsync_end - 1) & 0x3f; | ||
301 | if (temp & 0x10) | ||
302 | jregAE |= 0x20; | ||
303 | if (temp & 0x20) | ||
304 | jregAE |= 0x40; | ||
305 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x70, temp & 0xf); | ||
306 | |||
307 | temp = mode->crtc_vdisplay - 1; | ||
308 | if (temp & 0x100) | ||
309 | jreg07 |= 0x02; | ||
310 | if (temp & 0x200) | ||
311 | jreg07 |= 0x40; | ||
312 | if (temp & 0x400) | ||
313 | jregAE |= 0x02; | ||
314 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x12, 0x00, temp); | ||
315 | |||
316 | temp = mode->crtc_vblank_start - 1; | ||
317 | if (temp & 0x100) | ||
318 | jreg07 |= 0x08; | ||
319 | if (temp & 0x200) | ||
320 | jreg09 |= 0x20; | ||
321 | if (temp & 0x400) | ||
322 | jregAE |= 0x04; | ||
323 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x15, 0x00, temp); | ||
324 | |||
325 | temp = mode->crtc_vblank_end - 1; | ||
326 | if (temp & 0x100) | ||
327 | jregAE |= 0x10; | ||
328 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x16, 0x00, temp); | ||
329 | |||
330 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x07, 0x00, jreg07); | ||
331 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x09, 0xdf, jreg09); | ||
332 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAE, 0x00, (jregAE | 0x80)); | ||
333 | |||
334 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x80); | ||
335 | } | ||
336 | |||
337 | static void ast_set_offset_reg(struct drm_crtc *crtc) | ||
338 | { | ||
339 | struct ast_private *ast = crtc->dev->dev_private; | ||
340 | |||
341 | u16 offset; | ||
342 | |||
343 | offset = crtc->fb->pitches[0] >> 3; | ||
344 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff)); | ||
345 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f); | ||
346 | } | ||
347 | |||
348 | static void ast_set_dclk_reg(struct drm_device *dev, struct drm_display_mode *mode, | ||
349 | struct ast_vbios_mode_info *vbios_mode) | ||
350 | { | ||
351 | struct ast_private *ast = dev->dev_private; | ||
352 | struct ast_vbios_dclk_info *clk_info; | ||
353 | |||
354 | clk_info = &dclk_table[vbios_mode->enh_table->dclk_index]; | ||
355 | |||
356 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc0, 0x00, clk_info->param1); | ||
357 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc1, 0x00, clk_info->param2); | ||
358 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xbb, 0x0f, | ||
359 | (clk_info->param3 & 0x80) | ((clk_info->param3 & 0x3) << 4)); | ||
360 | } | ||
361 | |||
362 | static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
363 | struct ast_vbios_mode_info *vbios_mode) | ||
364 | { | ||
365 | struct ast_private *ast = crtc->dev->dev_private; | ||
366 | u8 jregA0 = 0, jregA3 = 0, jregA8 = 0; | ||
367 | |||
368 | switch (crtc->fb->bits_per_pixel) { | ||
369 | case 8: | ||
370 | jregA0 = 0x70; | ||
371 | jregA3 = 0x01; | ||
372 | jregA8 = 0x00; | ||
373 | break; | ||
374 | case 15: | ||
375 | case 16: | ||
376 | jregA0 = 0x70; | ||
377 | jregA3 = 0x04; | ||
378 | jregA8 = 0x02; | ||
379 | break; | ||
380 | case 32: | ||
381 | jregA0 = 0x70; | ||
382 | jregA3 = 0x08; | ||
383 | jregA8 = 0x02; | ||
384 | break; | ||
385 | } | ||
386 | |||
387 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa0, 0x8f, jregA0); | ||
388 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xf0, jregA3); | ||
389 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa8, 0xfd, jregA8); | ||
390 | |||
391 | /* Set Threshold */ | ||
392 | if (ast->chip == AST2300) { | ||
393 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78); | ||
394 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60); | ||
395 | } else if (ast->chip == AST2100 || | ||
396 | ast->chip == AST1100 || | ||
397 | ast->chip == AST2200 || | ||
398 | ast->chip == AST2150) { | ||
399 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x3f); | ||
400 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x2f); | ||
401 | } else { | ||
402 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x2f); | ||
403 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x1f); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode, | ||
408 | struct ast_vbios_mode_info *vbios_mode) | ||
409 | { | ||
410 | struct ast_private *ast = dev->dev_private; | ||
411 | u8 jreg; | ||
412 | |||
413 | jreg = ast_io_read8(ast, AST_IO_MISC_PORT_READ); | ||
414 | jreg |= (vbios_mode->enh_table->flags & SyncNN); | ||
415 | ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg); | ||
416 | } | ||
417 | |||
418 | bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
419 | struct ast_vbios_mode_info *vbios_mode) | ||
420 | { | ||
421 | switch (crtc->fb->bits_per_pixel) { | ||
422 | case 8: | ||
423 | break; | ||
424 | default: | ||
425 | return false; | ||
426 | } | ||
427 | return true; | ||
428 | } | ||
429 | |||
430 | void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset) | ||
431 | { | ||
432 | struct ast_private *ast = crtc->dev->dev_private; | ||
433 | u32 addr; | ||
434 | |||
435 | addr = offset >> 2; | ||
436 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0d, (u8)(addr & 0xff)); | ||
437 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0c, (u8)((addr >> 8) & 0xff)); | ||
438 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xaf, (u8)((addr >> 16) & 0xff)); | ||
439 | |||
440 | } | ||
441 | |||
442 | static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
443 | { | ||
444 | struct ast_private *ast = crtc->dev->dev_private; | ||
445 | |||
446 | if (ast->chip == AST1180) | ||
447 | return; | ||
448 | |||
449 | switch (mode) { | ||
450 | case DRM_MODE_DPMS_ON: | ||
451 | case DRM_MODE_DPMS_STANDBY: | ||
452 | case DRM_MODE_DPMS_SUSPEND: | ||
453 | ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0); | ||
454 | ast_crtc_load_lut(crtc); | ||
455 | break; | ||
456 | case DRM_MODE_DPMS_OFF: | ||
457 | ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20); | ||
458 | break; | ||
459 | } | ||
460 | } | ||
461 | |||
462 | static bool ast_crtc_mode_fixup(struct drm_crtc *crtc, | ||
463 | struct drm_display_mode *mode, | ||
464 | struct drm_display_mode *adjusted_mode) | ||
465 | { | ||
466 | return true; | ||
467 | } | ||
468 | |||
469 | /* ast is different - we will force move buffers out of VRAM */ | ||
470 | static int ast_crtc_do_set_base(struct drm_crtc *crtc, | ||
471 | struct drm_framebuffer *fb, | ||
472 | int x, int y, int atomic) | ||
473 | { | ||
474 | struct ast_private *ast = crtc->dev->dev_private; | ||
475 | struct drm_gem_object *obj; | ||
476 | struct ast_framebuffer *ast_fb; | ||
477 | struct ast_bo *bo; | ||
478 | int ret; | ||
479 | u64 gpu_addr; | ||
480 | |||
481 | /* push the previous fb to system ram */ | ||
482 | if (!atomic && fb) { | ||
483 | ast_fb = to_ast_framebuffer(fb); | ||
484 | obj = ast_fb->obj; | ||
485 | bo = gem_to_ast_bo(obj); | ||
486 | ret = ast_bo_reserve(bo, false); | ||
487 | if (ret) | ||
488 | return ret; | ||
489 | ast_bo_push_sysram(bo); | ||
490 | ast_bo_unreserve(bo); | ||
491 | } | ||
492 | |||
493 | ast_fb = to_ast_framebuffer(crtc->fb); | ||
494 | obj = ast_fb->obj; | ||
495 | bo = gem_to_ast_bo(obj); | ||
496 | |||
497 | ret = ast_bo_reserve(bo, false); | ||
498 | if (ret) | ||
499 | return ret; | ||
500 | |||
501 | ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | ||
502 | if (ret) { | ||
503 | ast_bo_unreserve(bo); | ||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | if (&ast->fbdev->afb == ast_fb) { | ||
508 | /* if pushing console in kmap it */ | ||
509 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
510 | if (ret) | ||
511 | DRM_ERROR("failed to kmap fbcon\n"); | ||
512 | } | ||
513 | ast_bo_unreserve(bo); | ||
514 | |||
515 | ast_set_start_address_crt1(crtc, (u32)gpu_addr); | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int ast_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
521 | struct drm_framebuffer *old_fb) | ||
522 | { | ||
523 | return ast_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
524 | } | ||
525 | |||
526 | static int ast_crtc_mode_set(struct drm_crtc *crtc, | ||
527 | struct drm_display_mode *mode, | ||
528 | struct drm_display_mode *adjusted_mode, | ||
529 | int x, int y, | ||
530 | struct drm_framebuffer *old_fb) | ||
531 | { | ||
532 | struct drm_device *dev = crtc->dev; | ||
533 | struct ast_private *ast = crtc->dev->dev_private; | ||
534 | struct ast_vbios_mode_info vbios_mode; | ||
535 | bool ret; | ||
536 | if (ast->chip == AST1180) { | ||
537 | DRM_ERROR("AST 1180 modesetting not supported\n"); | ||
538 | return -EINVAL; | ||
539 | } | ||
540 | |||
541 | ret = ast_get_vbios_mode_info(crtc, mode, adjusted_mode, &vbios_mode); | ||
542 | if (ret == false) | ||
543 | return -EINVAL; | ||
544 | ast_open_key(ast); | ||
545 | |||
546 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04); | ||
547 | |||
548 | ast_set_std_reg(crtc, adjusted_mode, &vbios_mode); | ||
549 | ast_set_crtc_reg(crtc, adjusted_mode, &vbios_mode); | ||
550 | ast_set_offset_reg(crtc); | ||
551 | ast_set_dclk_reg(dev, adjusted_mode, &vbios_mode); | ||
552 | ast_set_ext_reg(crtc, adjusted_mode, &vbios_mode); | ||
553 | ast_set_sync_reg(dev, adjusted_mode, &vbios_mode); | ||
554 | ast_set_dac_reg(crtc, adjusted_mode, &vbios_mode); | ||
555 | |||
556 | ast_crtc_mode_set_base(crtc, x, y, old_fb); | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static void ast_crtc_disable(struct drm_crtc *crtc) | ||
562 | { | ||
563 | |||
564 | } | ||
565 | |||
566 | static void ast_crtc_prepare(struct drm_crtc *crtc) | ||
567 | { | ||
568 | |||
569 | } | ||
570 | |||
571 | static void ast_crtc_commit(struct drm_crtc *crtc) | ||
572 | { | ||
573 | struct ast_private *ast = crtc->dev->dev_private; | ||
574 | ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0); | ||
575 | } | ||
576 | |||
577 | |||
578 | static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { | ||
579 | .dpms = ast_crtc_dpms, | ||
580 | .mode_fixup = ast_crtc_mode_fixup, | ||
581 | .mode_set = ast_crtc_mode_set, | ||
582 | .mode_set_base = ast_crtc_mode_set_base, | ||
583 | .disable = ast_crtc_disable, | ||
584 | .load_lut = ast_crtc_load_lut, | ||
585 | .disable = ast_crtc_disable, | ||
586 | .prepare = ast_crtc_prepare, | ||
587 | .commit = ast_crtc_commit, | ||
588 | |||
589 | }; | ||
590 | |||
591 | static void ast_crtc_reset(struct drm_crtc *crtc) | ||
592 | { | ||
593 | |||
594 | } | ||
595 | |||
596 | static void ast_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
597 | u16 *blue, uint32_t start, uint32_t size) | ||
598 | { | ||
599 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); | ||
600 | int end = (start + size > 256) ? 256 : start + size, i; | ||
601 | |||
602 | /* userspace palettes are always correct as is */ | ||
603 | for (i = start; i < end; i++) { | ||
604 | ast_crtc->lut_r[i] = red[i] >> 8; | ||
605 | ast_crtc->lut_g[i] = green[i] >> 8; | ||
606 | ast_crtc->lut_b[i] = blue[i] >> 8; | ||
607 | } | ||
608 | ast_crtc_load_lut(crtc); | ||
609 | } | ||
610 | |||
611 | |||
612 | static void ast_crtc_destroy(struct drm_crtc *crtc) | ||
613 | { | ||
614 | drm_crtc_cleanup(crtc); | ||
615 | kfree(crtc); | ||
616 | } | ||
617 | |||
618 | static const struct drm_crtc_funcs ast_crtc_funcs = { | ||
619 | .cursor_set = ast_cursor_set, | ||
620 | .cursor_move = ast_cursor_move, | ||
621 | .reset = ast_crtc_reset, | ||
622 | .set_config = drm_crtc_helper_set_config, | ||
623 | .gamma_set = ast_crtc_gamma_set, | ||
624 | .destroy = ast_crtc_destroy, | ||
625 | }; | ||
626 | |||
627 | int ast_crtc_init(struct drm_device *dev) | ||
628 | { | ||
629 | struct ast_crtc *crtc; | ||
630 | int i; | ||
631 | |||
632 | crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL); | ||
633 | if (!crtc) | ||
634 | return -ENOMEM; | ||
635 | |||
636 | drm_crtc_init(dev, &crtc->base, &ast_crtc_funcs); | ||
637 | drm_mode_crtc_set_gamma_size(&crtc->base, 256); | ||
638 | drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs); | ||
639 | |||
640 | for (i = 0; i < 256; i++) { | ||
641 | crtc->lut_r[i] = i; | ||
642 | crtc->lut_g[i] = i; | ||
643 | crtc->lut_b[i] = i; | ||
644 | } | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static void ast_encoder_destroy(struct drm_encoder *encoder) | ||
649 | { | ||
650 | drm_encoder_cleanup(encoder); | ||
651 | kfree(encoder); | ||
652 | } | ||
653 | |||
654 | |||
655 | static struct drm_encoder *ast_best_single_encoder(struct drm_connector *connector) | ||
656 | { | ||
657 | int enc_id = connector->encoder_ids[0]; | ||
658 | struct drm_mode_object *obj; | ||
659 | struct drm_encoder *encoder; | ||
660 | |||
661 | /* pick the encoder ids */ | ||
662 | if (enc_id) { | ||
663 | obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); | ||
664 | if (!obj) | ||
665 | return NULL; | ||
666 | encoder = obj_to_encoder(obj); | ||
667 | return encoder; | ||
668 | } | ||
669 | return NULL; | ||
670 | } | ||
671 | |||
672 | |||
673 | static const struct drm_encoder_funcs ast_enc_funcs = { | ||
674 | .destroy = ast_encoder_destroy, | ||
675 | }; | ||
676 | |||
677 | static void ast_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
678 | { | ||
679 | |||
680 | } | ||
681 | |||
682 | static bool ast_mode_fixup(struct drm_encoder *encoder, | ||
683 | struct drm_display_mode *mode, | ||
684 | struct drm_display_mode *adjusted_mode) | ||
685 | { | ||
686 | return true; | ||
687 | } | ||
688 | |||
689 | static void ast_encoder_mode_set(struct drm_encoder *encoder, | ||
690 | struct drm_display_mode *mode, | ||
691 | struct drm_display_mode *adjusted_mode) | ||
692 | { | ||
693 | } | ||
694 | |||
695 | static void ast_encoder_prepare(struct drm_encoder *encoder) | ||
696 | { | ||
697 | |||
698 | } | ||
699 | |||
700 | static void ast_encoder_commit(struct drm_encoder *encoder) | ||
701 | { | ||
702 | |||
703 | } | ||
704 | |||
705 | |||
706 | static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = { | ||
707 | .dpms = ast_encoder_dpms, | ||
708 | .mode_fixup = ast_mode_fixup, | ||
709 | .prepare = ast_encoder_prepare, | ||
710 | .commit = ast_encoder_commit, | ||
711 | .mode_set = ast_encoder_mode_set, | ||
712 | }; | ||
713 | |||
714 | int ast_encoder_init(struct drm_device *dev) | ||
715 | { | ||
716 | struct ast_encoder *ast_encoder; | ||
717 | |||
718 | ast_encoder = kzalloc(sizeof(struct ast_encoder), GFP_KERNEL); | ||
719 | if (!ast_encoder) | ||
720 | return -ENOMEM; | ||
721 | |||
722 | drm_encoder_init(dev, &ast_encoder->base, &ast_enc_funcs, | ||
723 | DRM_MODE_ENCODER_DAC); | ||
724 | drm_encoder_helper_add(&ast_encoder->base, &ast_enc_helper_funcs); | ||
725 | |||
726 | ast_encoder->base.possible_crtcs = 1; | ||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int ast_get_modes(struct drm_connector *connector) | ||
731 | { | ||
732 | struct ast_connector *ast_connector = to_ast_connector(connector); | ||
733 | struct edid *edid; | ||
734 | int ret; | ||
735 | |||
736 | edid = drm_get_edid(connector, &ast_connector->i2c->adapter); | ||
737 | if (edid) { | ||
738 | drm_mode_connector_update_edid_property(&ast_connector->base, edid); | ||
739 | ret = drm_add_edid_modes(connector, edid); | ||
740 | return ret; | ||
741 | } else | ||
742 | drm_mode_connector_update_edid_property(&ast_connector->base, NULL); | ||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static int ast_mode_valid(struct drm_connector *connector, | ||
747 | struct drm_display_mode *mode) | ||
748 | { | ||
749 | return MODE_OK; | ||
750 | } | ||
751 | |||
752 | static void ast_connector_destroy(struct drm_connector *connector) | ||
753 | { | ||
754 | struct ast_connector *ast_connector = to_ast_connector(connector); | ||
755 | ast_i2c_destroy(ast_connector->i2c); | ||
756 | drm_sysfs_connector_remove(connector); | ||
757 | drm_connector_cleanup(connector); | ||
758 | kfree(connector); | ||
759 | } | ||
760 | |||
761 | static enum drm_connector_status | ||
762 | ast_connector_detect(struct drm_connector *connector, bool force) | ||
763 | { | ||
764 | return connector_status_connected; | ||
765 | } | ||
766 | |||
767 | static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { | ||
768 | .mode_valid = ast_mode_valid, | ||
769 | .get_modes = ast_get_modes, | ||
770 | .best_encoder = ast_best_single_encoder, | ||
771 | }; | ||
772 | |||
773 | static const struct drm_connector_funcs ast_connector_funcs = { | ||
774 | .dpms = drm_helper_connector_dpms, | ||
775 | .detect = ast_connector_detect, | ||
776 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
777 | .destroy = ast_connector_destroy, | ||
778 | }; | ||
779 | |||
780 | int ast_connector_init(struct drm_device *dev) | ||
781 | { | ||
782 | struct ast_connector *ast_connector; | ||
783 | struct drm_connector *connector; | ||
784 | struct drm_encoder *encoder; | ||
785 | |||
786 | ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL); | ||
787 | if (!ast_connector) | ||
788 | return -ENOMEM; | ||
789 | |||
790 | connector = &ast_connector->base; | ||
791 | drm_connector_init(dev, connector, &ast_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
792 | |||
793 | drm_connector_helper_add(connector, &ast_connector_helper_funcs); | ||
794 | |||
795 | connector->interlace_allowed = 0; | ||
796 | connector->doublescan_allowed = 0; | ||
797 | |||
798 | drm_sysfs_connector_add(connector); | ||
799 | |||
800 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; | ||
801 | |||
802 | encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head); | ||
803 | drm_mode_connector_attach_encoder(connector, encoder); | ||
804 | |||
805 | ast_connector->i2c = ast_i2c_create(dev); | ||
806 | if (!ast_connector->i2c) | ||
807 | DRM_ERROR("failed to add ddc bus for connector\n"); | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | /* allocate cursor cache and pin at start of VRAM */ | ||
813 | int ast_cursor_init(struct drm_device *dev) | ||
814 | { | ||
815 | struct ast_private *ast = dev->dev_private; | ||
816 | int size; | ||
817 | int ret; | ||
818 | struct drm_gem_object *obj; | ||
819 | struct ast_bo *bo; | ||
820 | uint64_t gpu_addr; | ||
821 | |||
822 | size = (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE) * AST_DEFAULT_HWC_NUM; | ||
823 | |||
824 | ret = ast_gem_create(dev, size, true, &obj); | ||
825 | if (ret) | ||
826 | return ret; | ||
827 | bo = gem_to_ast_bo(obj); | ||
828 | ret = ast_bo_reserve(bo, false); | ||
829 | if (unlikely(ret != 0)) | ||
830 | goto fail; | ||
831 | |||
832 | ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | ||
833 | ast_bo_unreserve(bo); | ||
834 | if (ret) | ||
835 | goto fail; | ||
836 | |||
837 | /* kmap the object */ | ||
838 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &ast->cache_kmap); | ||
839 | if (ret) | ||
840 | goto fail; | ||
841 | |||
842 | ast->cursor_cache = obj; | ||
843 | ast->cursor_cache_gpu_addr = gpu_addr; | ||
844 | DRM_ERROR("pinned cursor cache at %llx\n", ast->cursor_cache_gpu_addr); | ||
845 | return 0; | ||
846 | fail: | ||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | void ast_cursor_fini(struct drm_device *dev) | ||
851 | { | ||
852 | struct ast_private *ast = dev->dev_private; | ||
853 | ttm_bo_kunmap(&ast->cache_kmap); | ||
854 | drm_gem_object_unreference_unlocked(ast->cursor_cache); | ||
855 | } | ||
856 | |||
857 | int ast_mode_init(struct drm_device *dev) | ||
858 | { | ||
859 | ast_cursor_init(dev); | ||
860 | ast_crtc_init(dev); | ||
861 | ast_encoder_init(dev); | ||
862 | ast_connector_init(dev); | ||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | void ast_mode_fini(struct drm_device *dev) | ||
867 | { | ||
868 | ast_cursor_fini(dev); | ||
869 | } | ||
870 | |||
871 | static int get_clock(void *i2c_priv) | ||
872 | { | ||
873 | struct ast_i2c_chan *i2c = i2c_priv; | ||
874 | struct ast_private *ast = i2c->dev->dev_private; | ||
875 | uint32_t val; | ||
876 | |||
877 | val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4; | ||
878 | return val & 1 ? 1 : 0; | ||
879 | } | ||
880 | |||
881 | static int get_data(void *i2c_priv) | ||
882 | { | ||
883 | struct ast_i2c_chan *i2c = i2c_priv; | ||
884 | struct ast_private *ast = i2c->dev->dev_private; | ||
885 | uint32_t val; | ||
886 | |||
887 | val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5; | ||
888 | return val & 1 ? 1 : 0; | ||
889 | } | ||
890 | |||
891 | static void set_clock(void *i2c_priv, int clock) | ||
892 | { | ||
893 | struct ast_i2c_chan *i2c = i2c_priv; | ||
894 | struct ast_private *ast = i2c->dev->dev_private; | ||
895 | int i; | ||
896 | u8 ujcrb7, jtemp; | ||
897 | |||
898 | for (i = 0; i < 0x10000; i++) { | ||
899 | ujcrb7 = ((clock & 0x01) ? 0 : 1); | ||
900 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfe, ujcrb7); | ||
901 | jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01); | ||
902 | if (ujcrb7 == jtemp) | ||
903 | break; | ||
904 | } | ||
905 | } | ||
906 | |||
907 | static void set_data(void *i2c_priv, int data) | ||
908 | { | ||
909 | struct ast_i2c_chan *i2c = i2c_priv; | ||
910 | struct ast_private *ast = i2c->dev->dev_private; | ||
911 | int i; | ||
912 | u8 ujcrb7, jtemp; | ||
913 | |||
914 | for (i = 0; i < 0x10000; i++) { | ||
915 | ujcrb7 = ((data & 0x01) ? 0 : 1) << 2; | ||
916 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfb, ujcrb7); | ||
917 | jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04); | ||
918 | if (ujcrb7 == jtemp) | ||
919 | break; | ||
920 | } | ||
921 | } | ||
922 | |||
923 | static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev) | ||
924 | { | ||
925 | struct ast_i2c_chan *i2c; | ||
926 | int ret; | ||
927 | |||
928 | i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL); | ||
929 | if (!i2c) | ||
930 | return NULL; | ||
931 | |||
932 | i2c->adapter.owner = THIS_MODULE; | ||
933 | i2c->adapter.class = I2C_CLASS_DDC; | ||
934 | i2c->adapter.dev.parent = &dev->pdev->dev; | ||
935 | i2c->dev = dev; | ||
936 | i2c_set_adapdata(&i2c->adapter, i2c); | ||
937 | snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), | ||
938 | "AST i2c bit bus"); | ||
939 | i2c->adapter.algo_data = &i2c->bit; | ||
940 | |||
941 | i2c->bit.udelay = 20; | ||
942 | i2c->bit.timeout = 2; | ||
943 | i2c->bit.data = i2c; | ||
944 | i2c->bit.setsda = set_data; | ||
945 | i2c->bit.setscl = set_clock; | ||
946 | i2c->bit.getsda = get_data; | ||
947 | i2c->bit.getscl = get_clock; | ||
948 | ret = i2c_bit_add_bus(&i2c->adapter); | ||
949 | if (ret) { | ||
950 | DRM_ERROR("Failed to register bit i2c\n"); | ||
951 | goto out_free; | ||
952 | } | ||
953 | |||
954 | return i2c; | ||
955 | out_free: | ||
956 | kfree(i2c); | ||
957 | return NULL; | ||
958 | } | ||
959 | |||
960 | static void ast_i2c_destroy(struct ast_i2c_chan *i2c) | ||
961 | { | ||
962 | if (!i2c) | ||
963 | return; | ||
964 | i2c_del_adapter(&i2c->adapter); | ||
965 | kfree(i2c); | ||
966 | } | ||
967 | |||
968 | void ast_show_cursor(struct drm_crtc *crtc) | ||
969 | { | ||
970 | struct ast_private *ast = crtc->dev->dev_private; | ||
971 | u8 jreg; | ||
972 | |||
973 | jreg = 0x2; | ||
974 | /* enable ARGB cursor */ | ||
975 | jreg |= 1; | ||
976 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg); | ||
977 | } | ||
978 | |||
979 | void ast_hide_cursor(struct drm_crtc *crtc) | ||
980 | { | ||
981 | struct ast_private *ast = crtc->dev->dev_private; | ||
982 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00); | ||
983 | } | ||
984 | |||
985 | static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height) | ||
986 | { | ||
987 | union { | ||
988 | u32 ul; | ||
989 | u8 b[4]; | ||
990 | } srcdata32[2], data32; | ||
991 | union { | ||
992 | u16 us; | ||
993 | u8 b[2]; | ||
994 | } data16; | ||
995 | u32 csum = 0; | ||
996 | s32 alpha_dst_delta, last_alpha_dst_delta; | ||
997 | u8 *srcxor, *dstxor; | ||
998 | int i, j; | ||
999 | u32 per_pixel_copy, two_pixel_copy; | ||
1000 | |||
1001 | alpha_dst_delta = AST_MAX_HWC_WIDTH << 1; | ||
1002 | last_alpha_dst_delta = alpha_dst_delta - (width << 1); | ||
1003 | |||
1004 | srcxor = src; | ||
1005 | dstxor = (u8 *)dst + last_alpha_dst_delta + (AST_MAX_HWC_HEIGHT - height) * alpha_dst_delta; | ||
1006 | per_pixel_copy = width & 1; | ||
1007 | two_pixel_copy = width >> 1; | ||
1008 | |||
1009 | for (j = 0; j < height; j++) { | ||
1010 | for (i = 0; i < two_pixel_copy; i++) { | ||
1011 | srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0; | ||
1012 | srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0; | ||
1013 | data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4); | ||
1014 | data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4); | ||
1015 | data32.b[2] = srcdata32[0].b[1] | (srcdata32[1].b[0] >> 4); | ||
1016 | data32.b[3] = srcdata32[0].b[3] | (srcdata32[1].b[2] >> 4); | ||
1017 | |||
1018 | writel(data32.ul, dstxor); | ||
1019 | csum += data32.ul; | ||
1020 | |||
1021 | dstxor += 4; | ||
1022 | srcxor += 8; | ||
1023 | |||
1024 | } | ||
1025 | |||
1026 | for (i = 0; i < per_pixel_copy; i++) { | ||
1027 | srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0; | ||
1028 | data16.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4); | ||
1029 | data16.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4); | ||
1030 | writew(data16.us, dstxor); | ||
1031 | csum += (u32)data16.us; | ||
1032 | |||
1033 | dstxor += 2; | ||
1034 | srcxor += 4; | ||
1035 | } | ||
1036 | dstxor += last_alpha_dst_delta; | ||
1037 | } | ||
1038 | return csum; | ||
1039 | } | ||
1040 | |||
1041 | static int ast_cursor_set(struct drm_crtc *crtc, | ||
1042 | struct drm_file *file_priv, | ||
1043 | uint32_t handle, | ||
1044 | uint32_t width, | ||
1045 | uint32_t height) | ||
1046 | { | ||
1047 | struct ast_private *ast = crtc->dev->dev_private; | ||
1048 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); | ||
1049 | struct drm_gem_object *obj; | ||
1050 | struct ast_bo *bo; | ||
1051 | uint64_t gpu_addr; | ||
1052 | u32 csum; | ||
1053 | int ret; | ||
1054 | struct ttm_bo_kmap_obj uobj_map; | ||
1055 | u8 *src, *dst; | ||
1056 | bool src_isiomem, dst_isiomem; | ||
1057 | if (!handle) { | ||
1058 | ast_hide_cursor(crtc); | ||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | if (width > AST_MAX_HWC_WIDTH || height > AST_MAX_HWC_HEIGHT) | ||
1063 | return -EINVAL; | ||
1064 | |||
1065 | obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); | ||
1066 | if (!obj) { | ||
1067 | DRM_ERROR("Cannot find cursor object %x for crtc\n", handle); | ||
1068 | return -ENOENT; | ||
1069 | } | ||
1070 | bo = gem_to_ast_bo(obj); | ||
1071 | |||
1072 | ret = ast_bo_reserve(bo, false); | ||
1073 | if (ret) | ||
1074 | goto fail; | ||
1075 | |||
1076 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map); | ||
1077 | |||
1078 | src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem); | ||
1079 | dst = ttm_kmap_obj_virtual(&ast->cache_kmap, &dst_isiomem); | ||
1080 | |||
1081 | if (src_isiomem == true) | ||
1082 | DRM_ERROR("src cursor bo should be in main memory\n"); | ||
1083 | if (dst_isiomem == false) | ||
1084 | DRM_ERROR("dst bo should be in VRAM\n"); | ||
1085 | |||
1086 | dst += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor; | ||
1087 | |||
1088 | /* do data transfer to cursor cache */ | ||
1089 | csum = copy_cursor_image(src, dst, width, height); | ||
1090 | |||
1091 | /* write checksum + signature */ | ||
1092 | ttm_bo_kunmap(&uobj_map); | ||
1093 | ast_bo_unreserve(bo); | ||
1094 | { | ||
1095 | u8 *dst = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; | ||
1096 | writel(csum, dst); | ||
1097 | writel(width, dst + AST_HWC_SIGNATURE_SizeX); | ||
1098 | writel(height, dst + AST_HWC_SIGNATURE_SizeY); | ||
1099 | writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX); | ||
1100 | writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY); | ||
1101 | |||
1102 | /* set pattern offset */ | ||
1103 | gpu_addr = ast->cursor_cache_gpu_addr; | ||
1104 | gpu_addr += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor; | ||
1105 | gpu_addr >>= 3; | ||
1106 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, gpu_addr & 0xff); | ||
1107 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, (gpu_addr >> 8) & 0xff); | ||
1108 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, (gpu_addr >> 16) & 0xff); | ||
1109 | } | ||
1110 | ast_crtc->cursor_width = width; | ||
1111 | ast_crtc->cursor_height = height; | ||
1112 | ast_crtc->offset_x = AST_MAX_HWC_WIDTH - width; | ||
1113 | ast_crtc->offset_y = AST_MAX_HWC_WIDTH - height; | ||
1114 | |||
1115 | ast->next_cursor = (ast->next_cursor + 1) % AST_DEFAULT_HWC_NUM; | ||
1116 | |||
1117 | ast_show_cursor(crtc); | ||
1118 | |||
1119 | drm_gem_object_unreference_unlocked(obj); | ||
1120 | return 0; | ||
1121 | fail: | ||
1122 | drm_gem_object_unreference_unlocked(obj); | ||
1123 | return ret; | ||
1124 | } | ||
1125 | |||
1126 | static int ast_cursor_move(struct drm_crtc *crtc, | ||
1127 | int x, int y) | ||
1128 | { | ||
1129 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); | ||
1130 | struct ast_private *ast = crtc->dev->dev_private; | ||
1131 | int x_offset, y_offset; | ||
1132 | u8 *sig; | ||
1133 | |||
1134 | sig = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; | ||
1135 | writel(x, sig + AST_HWC_SIGNATURE_X); | ||
1136 | writel(y, sig + AST_HWC_SIGNATURE_Y); | ||
1137 | |||
1138 | x_offset = ast_crtc->offset_x; | ||
1139 | y_offset = ast_crtc->offset_y; | ||
1140 | if (x < 0) { | ||
1141 | x_offset = (-x) + ast_crtc->offset_x; | ||
1142 | x = 0; | ||
1143 | } | ||
1144 | |||
1145 | if (y < 0) { | ||
1146 | y_offset = (-y) + ast_crtc->offset_y; | ||
1147 | y = 0; | ||
1148 | } | ||
1149 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc2, x_offset); | ||
1150 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc3, y_offset); | ||
1151 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc4, (x & 0xff)); | ||
1152 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc5, ((x >> 8) & 0x0f)); | ||
1153 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc6, (y & 0xff)); | ||
1154 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07)); | ||
1155 | |||
1156 | /* dummy write to fire HWC */ | ||
1157 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xCB, 0xFF, 0x00); | ||
1158 | |||
1159 | return 0; | ||
1160 | } | ||
diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c new file mode 100644 index 000000000000..6edbee63b0cb --- /dev/null +++ b/drivers/gpu/drm/ast/ast_post.c | |||
@@ -0,0 +1,1780 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the | ||
6 | * "Software"), to deal in the Software without restriction, including | ||
7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
9 | * permit persons to whom the Software is furnished to do so, subject to | ||
10 | * the following conditions: | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * The above copyright notice and this permission notice (including the | ||
21 | * next paragraph) shall be included in all copies or substantial portions | ||
22 | * of the Software. | ||
23 | * | ||
24 | */ | ||
25 | /* | ||
26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
27 | */ | ||
28 | |||
29 | #include "drmP.h" | ||
30 | #include "ast_drv.h" | ||
31 | |||
32 | #include "ast_dram_tables.h" | ||
33 | |||
34 | static void ast_init_dram_2300(struct drm_device *dev); | ||
35 | |||
36 | static void | ||
37 | ast_enable_vga(struct drm_device *dev) | ||
38 | { | ||
39 | struct ast_private *ast = dev->dev_private; | ||
40 | |||
41 | ast_io_write8(ast, 0x43, 0x01); | ||
42 | ast_io_write8(ast, 0x42, 0x01); | ||
43 | } | ||
44 | |||
45 | #if 0 /* will use later */ | ||
46 | static bool | ||
47 | ast_is_vga_enabled(struct drm_device *dev) | ||
48 | { | ||
49 | struct ast_private *ast = dev->dev_private; | ||
50 | u8 ch; | ||
51 | |||
52 | if (ast->chip == AST1180) { | ||
53 | /* TODO 1180 */ | ||
54 | } else { | ||
55 | ch = ast_io_read8(ast, 0x43); | ||
56 | if (ch) { | ||
57 | ast_open_key(ast); | ||
58 | ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff); | ||
59 | return ch & 0x04; | ||
60 | } | ||
61 | } | ||
62 | return 0; | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff }; | ||
67 | static const u8 extreginfo_ast2300a0[] = { 0x0f, 0x04, 0x1c, 0xff }; | ||
68 | static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff }; | ||
69 | |||
70 | static void | ||
71 | ast_set_def_ext_reg(struct drm_device *dev) | ||
72 | { | ||
73 | struct ast_private *ast = dev->dev_private; | ||
74 | u8 i, index, reg; | ||
75 | const u8 *ext_reg_info; | ||
76 | |||
77 | /* reset scratch */ | ||
78 | for (i = 0x81; i <= 0x8f; i++) | ||
79 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, 0x00); | ||
80 | |||
81 | if (ast->chip == AST2300) { | ||
82 | if (dev->pdev->revision >= 0x20) | ||
83 | ext_reg_info = extreginfo_ast2300; | ||
84 | else | ||
85 | ext_reg_info = extreginfo_ast2300a0; | ||
86 | } else | ||
87 | ext_reg_info = extreginfo; | ||
88 | |||
89 | index = 0xa0; | ||
90 | while (*ext_reg_info != 0xff) { | ||
91 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, index, 0x00, *ext_reg_info); | ||
92 | index++; | ||
93 | ext_reg_info++; | ||
94 | } | ||
95 | |||
96 | /* disable standard IO/MEM decode if secondary */ | ||
97 | /* ast_set_index_reg-mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x3); */ | ||
98 | |||
99 | /* Set Ext. Default */ | ||
100 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x8c, 0x00, 0x01); | ||
101 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x00, 0x00); | ||
102 | |||
103 | /* Enable RAMDAC for A1 */ | ||
104 | reg = 0x04; | ||
105 | if (ast->chip == AST2300) | ||
106 | reg |= 0x20; | ||
107 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff, reg); | ||
108 | } | ||
109 | |||
110 | static inline u32 mindwm(struct ast_private *ast, u32 r) | ||
111 | { | ||
112 | ast_write32(ast, 0xf004, r & 0xffff0000); | ||
113 | ast_write32(ast, 0xf000, 0x1); | ||
114 | |||
115 | return ast_read32(ast, 0x10000 + (r & 0x0000ffff)); | ||
116 | } | ||
117 | |||
118 | static inline void moutdwm(struct ast_private *ast, u32 r, u32 v) | ||
119 | { | ||
120 | ast_write32(ast, 0xf004, r & 0xffff0000); | ||
121 | ast_write32(ast, 0xf000, 0x1); | ||
122 | ast_write32(ast, 0x10000 + (r & 0x0000ffff), v); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * AST2100/2150 DLL CBR Setting | ||
127 | */ | ||
128 | #define CBR_SIZE_AST2150 ((16 << 10) - 1) | ||
129 | #define CBR_PASSNUM_AST2150 5 | ||
130 | #define CBR_THRESHOLD_AST2150 10 | ||
131 | #define CBR_THRESHOLD2_AST2150 10 | ||
132 | #define TIMEOUT_AST2150 5000000 | ||
133 | |||
134 | #define CBR_PATNUM_AST2150 8 | ||
135 | |||
136 | static const u32 pattern_AST2150[14] = { | ||
137 | 0xFF00FF00, | ||
138 | 0xCC33CC33, | ||
139 | 0xAA55AA55, | ||
140 | 0xFFFE0001, | ||
141 | 0x683501FE, | ||
142 | 0x0F1929B0, | ||
143 | 0x2D0B4346, | ||
144 | 0x60767F02, | ||
145 | 0x6FBE36A6, | ||
146 | 0x3A253035, | ||
147 | 0x3019686D, | ||
148 | 0x41C6167E, | ||
149 | 0x620152BF, | ||
150 | 0x20F050E0 | ||
151 | }; | ||
152 | |||
153 | static u32 mmctestburst2_ast2150(struct ast_private *ast, u32 datagen) | ||
154 | { | ||
155 | u32 data, timeout; | ||
156 | |||
157 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
158 | moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3)); | ||
159 | timeout = 0; | ||
160 | do { | ||
161 | data = mindwm(ast, 0x1e6e0070) & 0x40; | ||
162 | if (++timeout > TIMEOUT_AST2150) { | ||
163 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
164 | return 0xffffffff; | ||
165 | } | ||
166 | } while (!data); | ||
167 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
168 | moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3)); | ||
169 | timeout = 0; | ||
170 | do { | ||
171 | data = mindwm(ast, 0x1e6e0070) & 0x40; | ||
172 | if (++timeout > TIMEOUT_AST2150) { | ||
173 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
174 | return 0xffffffff; | ||
175 | } | ||
176 | } while (!data); | ||
177 | data = (mindwm(ast, 0x1e6e0070) & 0x80) >> 7; | ||
178 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
179 | return data; | ||
180 | } | ||
181 | |||
182 | #if 0 /* unused in DDX driver - here for completeness */ | ||
183 | static u32 mmctestsingle2_ast2150(struct ast_private *ast, u32 datagen) | ||
184 | { | ||
185 | u32 data, timeout; | ||
186 | |||
187 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
188 | moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3)); | ||
189 | timeout = 0; | ||
190 | do { | ||
191 | data = mindwm(ast, 0x1e6e0070) & 0x40; | ||
192 | if (++timeout > TIMEOUT_AST2150) { | ||
193 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
194 | return 0xffffffff; | ||
195 | } | ||
196 | } while (!data); | ||
197 | data = (mindwm(ast, 0x1e6e0070) & 0x80) >> 7; | ||
198 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
199 | return data; | ||
200 | } | ||
201 | #endif | ||
202 | |||
203 | static int cbrtest_ast2150(struct ast_private *ast) | ||
204 | { | ||
205 | int i; | ||
206 | |||
207 | for (i = 0; i < 8; i++) | ||
208 | if (mmctestburst2_ast2150(ast, i)) | ||
209 | return 0; | ||
210 | return 1; | ||
211 | } | ||
212 | |||
213 | static int cbrscan_ast2150(struct ast_private *ast, int busw) | ||
214 | { | ||
215 | u32 patcnt, loop; | ||
216 | |||
217 | for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) { | ||
218 | moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]); | ||
219 | for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) { | ||
220 | if (cbrtest_ast2150(ast)) | ||
221 | break; | ||
222 | } | ||
223 | if (loop == CBR_PASSNUM_AST2150) | ||
224 | return 0; | ||
225 | } | ||
226 | return 1; | ||
227 | } | ||
228 | |||
229 | |||
230 | static void cbrdlli_ast2150(struct ast_private *ast, int busw) | ||
231 | { | ||
232 | u32 dll_min[4], dll_max[4], dlli, data, passcnt; | ||
233 | |||
234 | cbr_start: | ||
235 | dll_min[0] = dll_min[1] = dll_min[2] = dll_min[3] = 0xff; | ||
236 | dll_max[0] = dll_max[1] = dll_max[2] = dll_max[3] = 0x0; | ||
237 | passcnt = 0; | ||
238 | |||
239 | for (dlli = 0; dlli < 100; dlli++) { | ||
240 | moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); | ||
241 | data = cbrscan_ast2150(ast, busw); | ||
242 | if (data != 0) { | ||
243 | if (data & 0x1) { | ||
244 | if (dll_min[0] > dlli) | ||
245 | dll_min[0] = dlli; | ||
246 | if (dll_max[0] < dlli) | ||
247 | dll_max[0] = dlli; | ||
248 | } | ||
249 | passcnt++; | ||
250 | } else if (passcnt >= CBR_THRESHOLD_AST2150) | ||
251 | goto cbr_start; | ||
252 | } | ||
253 | if (dll_max[0] == 0 || (dll_max[0]-dll_min[0]) < CBR_THRESHOLD_AST2150) | ||
254 | goto cbr_start; | ||
255 | |||
256 | dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4); | ||
257 | moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); | ||
258 | } | ||
259 | |||
260 | |||
261 | |||
262 | static void ast_init_dram_reg(struct drm_device *dev) | ||
263 | { | ||
264 | struct ast_private *ast = dev->dev_private; | ||
265 | u8 j; | ||
266 | u32 data, temp, i; | ||
267 | const struct ast_dramstruct *dram_reg_info; | ||
268 | |||
269 | j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); | ||
270 | |||
271 | if ((j & 0x80) == 0) { /* VGA only */ | ||
272 | if (ast->chip == AST2000) { | ||
273 | dram_reg_info = ast2000_dram_table_data; | ||
274 | ast_write32(ast, 0xf004, 0x1e6e0000); | ||
275 | ast_write32(ast, 0xf000, 0x1); | ||
276 | ast_write32(ast, 0x10100, 0xa8); | ||
277 | |||
278 | do { | ||
279 | ; | ||
280 | } while (ast_read32(ast, 0x10100) != 0xa8); | ||
281 | } else {/* AST2100/1100 */ | ||
282 | if (ast->chip == AST2100 || ast->chip == 2200) | ||
283 | dram_reg_info = ast2100_dram_table_data; | ||
284 | else | ||
285 | dram_reg_info = ast1100_dram_table_data; | ||
286 | |||
287 | ast_write32(ast, 0xf004, 0x1e6e0000); | ||
288 | ast_write32(ast, 0xf000, 0x1); | ||
289 | ast_write32(ast, 0x12000, 0x1688A8A8); | ||
290 | do { | ||
291 | ; | ||
292 | } while (ast_read32(ast, 0x12000) != 0x01); | ||
293 | |||
294 | ast_write32(ast, 0x10000, 0xfc600309); | ||
295 | do { | ||
296 | ; | ||
297 | } while (ast_read32(ast, 0x10000) != 0x01); | ||
298 | } | ||
299 | |||
300 | while (dram_reg_info->index != 0xffff) { | ||
301 | if (dram_reg_info->index == 0xff00) {/* delay fn */ | ||
302 | for (i = 0; i < 15; i++) | ||
303 | udelay(dram_reg_info->data); | ||
304 | } else if (dram_reg_info->index == 0x4 && ast->chip != AST2000) { | ||
305 | data = dram_reg_info->data; | ||
306 | if (ast->dram_type == AST_DRAM_1Gx16) | ||
307 | data = 0x00000d89; | ||
308 | else if (ast->dram_type == AST_DRAM_1Gx32) | ||
309 | data = 0x00000c8d; | ||
310 | |||
311 | temp = ast_read32(ast, 0x12070); | ||
312 | temp &= 0xc; | ||
313 | temp <<= 2; | ||
314 | ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp); | ||
315 | } else | ||
316 | ast_write32(ast, 0x10000 + dram_reg_info->index, dram_reg_info->data); | ||
317 | dram_reg_info++; | ||
318 | } | ||
319 | |||
320 | /* AST 2100/2150 DRAM calibration */ | ||
321 | data = ast_read32(ast, 0x10120); | ||
322 | if (data == 0x5061) { /* 266Mhz */ | ||
323 | data = ast_read32(ast, 0x10004); | ||
324 | if (data & 0x40) | ||
325 | cbrdlli_ast2150(ast, 16); /* 16 bits */ | ||
326 | else | ||
327 | cbrdlli_ast2150(ast, 32); /* 32 bits */ | ||
328 | } | ||
329 | |||
330 | switch (ast->chip) { | ||
331 | case AST2000: | ||
332 | temp = ast_read32(ast, 0x10140); | ||
333 | ast_write32(ast, 0x10140, temp | 0x40); | ||
334 | break; | ||
335 | case AST1100: | ||
336 | case AST2100: | ||
337 | case AST2200: | ||
338 | case AST2150: | ||
339 | temp = ast_read32(ast, 0x1200c); | ||
340 | ast_write32(ast, 0x1200c, temp & 0xfffffffd); | ||
341 | temp = ast_read32(ast, 0x12040); | ||
342 | ast_write32(ast, 0x12040, temp | 0x40); | ||
343 | break; | ||
344 | default: | ||
345 | break; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | /* wait ready */ | ||
350 | do { | ||
351 | j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); | ||
352 | } while ((j & 0x40) == 0); | ||
353 | } | ||
354 | |||
355 | void ast_post_gpu(struct drm_device *dev) | ||
356 | { | ||
357 | u32 reg; | ||
358 | struct ast_private *ast = dev->dev_private; | ||
359 | |||
360 | pci_read_config_dword(ast->dev->pdev, 0x04, ®); | ||
361 | reg |= 0x3; | ||
362 | pci_write_config_dword(ast->dev->pdev, 0x04, reg); | ||
363 | |||
364 | ast_enable_vga(dev); | ||
365 | ast_open_key(ast); | ||
366 | ast_set_def_ext_reg(dev); | ||
367 | |||
368 | if (ast->chip == AST2300) | ||
369 | ast_init_dram_2300(dev); | ||
370 | else | ||
371 | ast_init_dram_reg(dev); | ||
372 | } | ||
373 | |||
374 | /* AST 2300 DRAM settings */ | ||
375 | #define AST_DDR3 0 | ||
376 | #define AST_DDR2 1 | ||
377 | |||
378 | struct ast2300_dram_param { | ||
379 | u32 dram_type; | ||
380 | u32 dram_chipid; | ||
381 | u32 dram_freq; | ||
382 | u32 vram_size; | ||
383 | u32 odt; | ||
384 | u32 wodt; | ||
385 | u32 rodt; | ||
386 | u32 dram_config; | ||
387 | u32 reg_PERIOD; | ||
388 | u32 reg_MADJ; | ||
389 | u32 reg_SADJ; | ||
390 | u32 reg_MRS; | ||
391 | u32 reg_EMRS; | ||
392 | u32 reg_AC1; | ||
393 | u32 reg_AC2; | ||
394 | u32 reg_DQSIC; | ||
395 | u32 reg_DRV; | ||
396 | u32 reg_IOZ; | ||
397 | u32 reg_DQIDLY; | ||
398 | u32 reg_FREQ; | ||
399 | u32 madj_max; | ||
400 | u32 dll2_finetune_step; | ||
401 | }; | ||
402 | |||
403 | /* | ||
404 | * DQSI DLL CBR Setting | ||
405 | */ | ||
406 | #define CBR_SIZE1 ((4 << 10) - 1) | ||
407 | #define CBR_SIZE2 ((64 << 10) - 1) | ||
408 | #define CBR_PASSNUM 5 | ||
409 | #define CBR_PASSNUM2 5 | ||
410 | #define CBR_THRESHOLD 10 | ||
411 | #define CBR_THRESHOLD2 10 | ||
412 | #define TIMEOUT 5000000 | ||
413 | #define CBR_PATNUM 8 | ||
414 | |||
415 | static const u32 pattern[8] = { | ||
416 | 0xFF00FF00, | ||
417 | 0xCC33CC33, | ||
418 | 0xAA55AA55, | ||
419 | 0x88778877, | ||
420 | 0x92CC4D6E, | ||
421 | 0x543D3CDE, | ||
422 | 0xF1E843C7, | ||
423 | 0x7C61D253 | ||
424 | }; | ||
425 | |||
426 | #if 0 /* unused in DDX, included for completeness */ | ||
427 | static int mmc_test_burst(struct ast_private *ast, u32 datagen) | ||
428 | { | ||
429 | u32 data, timeout; | ||
430 | |||
431 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
432 | moutdwm(ast, 0x1e6e0070, 0x000000c1 | (datagen << 3)); | ||
433 | timeout = 0; | ||
434 | do { | ||
435 | data = mindwm(ast, 0x1e6e0070) & 0x3000; | ||
436 | if (data & 0x2000) { | ||
437 | return 0; | ||
438 | } | ||
439 | if (++timeout > TIMEOUT) { | ||
440 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
441 | return 0; | ||
442 | } | ||
443 | } while (!data); | ||
444 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
445 | return 1; | ||
446 | } | ||
447 | #endif | ||
448 | |||
449 | static int mmc_test_burst2(struct ast_private *ast, u32 datagen) | ||
450 | { | ||
451 | u32 data, timeout; | ||
452 | |||
453 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
454 | moutdwm(ast, 0x1e6e0070, 0x00000041 | (datagen << 3)); | ||
455 | timeout = 0; | ||
456 | do { | ||
457 | data = mindwm(ast, 0x1e6e0070) & 0x1000; | ||
458 | if (++timeout > TIMEOUT) { | ||
459 | moutdwm(ast, 0x1e6e0070, 0x0); | ||
460 | return -1; | ||
461 | } | ||
462 | } while (!data); | ||
463 | data = mindwm(ast, 0x1e6e0078); | ||
464 | data = (data | (data >> 16)) & 0xffff; | ||
465 | moutdwm(ast, 0x1e6e0070, 0x0); | ||
466 | return data; | ||
467 | } | ||
468 | |||
469 | #if 0 /* Unused in DDX here for completeness */ | ||
470 | static int mmc_test_single(struct ast_private *ast, u32 datagen) | ||
471 | { | ||
472 | u32 data, timeout; | ||
473 | |||
474 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
475 | moutdwm(ast, 0x1e6e0070, 0x000000c5 | (datagen << 3)); | ||
476 | timeout = 0; | ||
477 | do { | ||
478 | data = mindwm(ast, 0x1e6e0070) & 0x3000; | ||
479 | if (data & 0x2000) | ||
480 | return 0; | ||
481 | if (++timeout > TIMEOUT) { | ||
482 | moutdwm(ast, 0x1e6e0070, 0x0); | ||
483 | return 0; | ||
484 | } | ||
485 | } while (!data); | ||
486 | moutdwm(ast, 0x1e6e0070, 0x0); | ||
487 | return 1; | ||
488 | } | ||
489 | #endif | ||
490 | |||
491 | static int mmc_test_single2(struct ast_private *ast, u32 datagen) | ||
492 | { | ||
493 | u32 data, timeout; | ||
494 | |||
495 | moutdwm(ast, 0x1e6e0070, 0x00000000); | ||
496 | moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3)); | ||
497 | timeout = 0; | ||
498 | do { | ||
499 | data = mindwm(ast, 0x1e6e0070) & 0x1000; | ||
500 | if (++timeout > TIMEOUT) { | ||
501 | moutdwm(ast, 0x1e6e0070, 0x0); | ||
502 | return -1; | ||
503 | } | ||
504 | } while (!data); | ||
505 | data = mindwm(ast, 0x1e6e0078); | ||
506 | data = (data | (data >> 16)) & 0xffff; | ||
507 | moutdwm(ast, 0x1e6e0070, 0x0); | ||
508 | return data; | ||
509 | } | ||
510 | |||
511 | static int cbr_test(struct ast_private *ast) | ||
512 | { | ||
513 | u32 data; | ||
514 | int i; | ||
515 | data = mmc_test_single2(ast, 0); | ||
516 | if ((data & 0xff) && (data & 0xff00)) | ||
517 | return 0; | ||
518 | for (i = 0; i < 8; i++) { | ||
519 | data = mmc_test_burst2(ast, i); | ||
520 | if ((data & 0xff) && (data & 0xff00)) | ||
521 | return 0; | ||
522 | } | ||
523 | if (!data) | ||
524 | return 3; | ||
525 | else if (data & 0xff) | ||
526 | return 2; | ||
527 | return 1; | ||
528 | } | ||
529 | |||
530 | static int cbr_scan(struct ast_private *ast) | ||
531 | { | ||
532 | u32 data, data2, patcnt, loop; | ||
533 | |||
534 | data2 = 3; | ||
535 | for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { | ||
536 | moutdwm(ast, 0x1e6e007c, pattern[patcnt]); | ||
537 | for (loop = 0; loop < CBR_PASSNUM2; loop++) { | ||
538 | if ((data = cbr_test(ast)) != 0) { | ||
539 | data2 &= data; | ||
540 | if (!data2) | ||
541 | return 0; | ||
542 | break; | ||
543 | } | ||
544 | } | ||
545 | if (loop == CBR_PASSNUM2) | ||
546 | return 0; | ||
547 | } | ||
548 | return data2; | ||
549 | } | ||
550 | |||
551 | static u32 cbr_test2(struct ast_private *ast) | ||
552 | { | ||
553 | u32 data; | ||
554 | |||
555 | data = mmc_test_burst2(ast, 0); | ||
556 | if (data == 0xffff) | ||
557 | return 0; | ||
558 | data |= mmc_test_single2(ast, 0); | ||
559 | if (data == 0xffff) | ||
560 | return 0; | ||
561 | |||
562 | return ~data & 0xffff; | ||
563 | } | ||
564 | |||
565 | static u32 cbr_scan2(struct ast_private *ast) | ||
566 | { | ||
567 | u32 data, data2, patcnt, loop; | ||
568 | |||
569 | data2 = 0xffff; | ||
570 | for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { | ||
571 | moutdwm(ast, 0x1e6e007c, pattern[patcnt]); | ||
572 | for (loop = 0; loop < CBR_PASSNUM2; loop++) { | ||
573 | if ((data = cbr_test2(ast)) != 0) { | ||
574 | data2 &= data; | ||
575 | if (!data) | ||
576 | return 0; | ||
577 | break; | ||
578 | } | ||
579 | } | ||
580 | if (loop == CBR_PASSNUM2) | ||
581 | return 0; | ||
582 | } | ||
583 | return data2; | ||
584 | } | ||
585 | |||
586 | #if 0 /* unused in DDX - added for completeness */ | ||
587 | static void finetuneDQI(struct ast_private *ast, struct ast2300_dram_param *param) | ||
588 | { | ||
589 | u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt; | ||
590 | |||
591 | gold_sadj[0] = (mindwm(ast, 0x1E6E0024) >> 16) & 0xffff; | ||
592 | gold_sadj[1] = gold_sadj[0] >> 8; | ||
593 | gold_sadj[0] = gold_sadj[0] & 0xff; | ||
594 | gold_sadj[0] = (gold_sadj[0] + gold_sadj[1]) >> 1; | ||
595 | gold_sadj[1] = gold_sadj[0]; | ||
596 | |||
597 | for (cnt = 0; cnt < 16; cnt++) { | ||
598 | dllmin[cnt] = 0xff; | ||
599 | dllmax[cnt] = 0x0; | ||
600 | } | ||
601 | passcnt = 0; | ||
602 | for (dlli = 0; dlli < 76; dlli++) { | ||
603 | moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24)); | ||
604 | /* Wait DQSI latch phase calibration */ | ||
605 | moutdwm(ast, 0x1E6E0074, 0x00000010); | ||
606 | moutdwm(ast, 0x1E6E0070, 0x00000003); | ||
607 | do { | ||
608 | data = mindwm(ast, 0x1E6E0070); | ||
609 | } while (!(data & 0x00001000)); | ||
610 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
611 | |||
612 | moutdwm(ast, 0x1E6E0074, CBR_SIZE1); | ||
613 | data = cbr_scan2(ast); | ||
614 | if (data != 0) { | ||
615 | mask = 0x00010001; | ||
616 | for (cnt = 0; cnt < 16; cnt++) { | ||
617 | if (data & mask) { | ||
618 | if (dllmin[cnt] > dlli) { | ||
619 | dllmin[cnt] = dlli; | ||
620 | } | ||
621 | if (dllmax[cnt] < dlli) { | ||
622 | dllmax[cnt] = dlli; | ||
623 | } | ||
624 | } | ||
625 | mask <<= 1; | ||
626 | } | ||
627 | passcnt++; | ||
628 | } else if (passcnt >= CBR_THRESHOLD) { | ||
629 | break; | ||
630 | } | ||
631 | } | ||
632 | data = 0; | ||
633 | for (cnt = 0; cnt < 8; cnt++) { | ||
634 | data >>= 3; | ||
635 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD)) { | ||
636 | dlli = (dllmin[cnt] + dllmax[cnt]) >> 1; | ||
637 | if (gold_sadj[0] >= dlli) { | ||
638 | dlli = (gold_sadj[0] - dlli) >> 1; | ||
639 | if (dlli > 3) { | ||
640 | dlli = 3; | ||
641 | } | ||
642 | } else { | ||
643 | dlli = (dlli - gold_sadj[0]) >> 1; | ||
644 | if (dlli > 4) { | ||
645 | dlli = 4; | ||
646 | } | ||
647 | dlli = (8 - dlli) & 0x7; | ||
648 | } | ||
649 | data |= dlli << 21; | ||
650 | } | ||
651 | } | ||
652 | moutdwm(ast, 0x1E6E0080, data); | ||
653 | |||
654 | data = 0; | ||
655 | for (cnt = 8; cnt < 16; cnt++) { | ||
656 | data >>= 3; | ||
657 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD)) { | ||
658 | dlli = (dllmin[cnt] + dllmax[cnt]) >> 1; | ||
659 | if (gold_sadj[1] >= dlli) { | ||
660 | dlli = (gold_sadj[1] - dlli) >> 1; | ||
661 | if (dlli > 3) { | ||
662 | dlli = 3; | ||
663 | } else { | ||
664 | dlli = (dlli - 1) & 0x7; | ||
665 | } | ||
666 | } else { | ||
667 | dlli = (dlli - gold_sadj[1]) >> 1; | ||
668 | dlli += 1; | ||
669 | if (dlli > 4) { | ||
670 | dlli = 4; | ||
671 | } | ||
672 | dlli = (8 - dlli) & 0x7; | ||
673 | } | ||
674 | data |= dlli << 21; | ||
675 | } | ||
676 | } | ||
677 | moutdwm(ast, 0x1E6E0084, data); | ||
678 | |||
679 | } /* finetuneDQI */ | ||
680 | #endif | ||
681 | |||
682 | static void finetuneDQI_L(struct ast_private *ast, struct ast2300_dram_param *param) | ||
683 | { | ||
684 | u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt; | ||
685 | |||
686 | FINETUNE_START: | ||
687 | for (cnt = 0; cnt < 16; cnt++) { | ||
688 | dllmin[cnt] = 0xff; | ||
689 | dllmax[cnt] = 0x0; | ||
690 | } | ||
691 | passcnt = 0; | ||
692 | for (dlli = 0; dlli < 76; dlli++) { | ||
693 | moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24)); | ||
694 | /* Wait DQSI latch phase calibration */ | ||
695 | moutdwm(ast, 0x1E6E0074, 0x00000010); | ||
696 | moutdwm(ast, 0x1E6E0070, 0x00000003); | ||
697 | do { | ||
698 | data = mindwm(ast, 0x1E6E0070); | ||
699 | } while (!(data & 0x00001000)); | ||
700 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
701 | |||
702 | moutdwm(ast, 0x1E6E0074, CBR_SIZE1); | ||
703 | data = cbr_scan2(ast); | ||
704 | if (data != 0) { | ||
705 | mask = 0x00010001; | ||
706 | for (cnt = 0; cnt < 16; cnt++) { | ||
707 | if (data & mask) { | ||
708 | if (dllmin[cnt] > dlli) { | ||
709 | dllmin[cnt] = dlli; | ||
710 | } | ||
711 | if (dllmax[cnt] < dlli) { | ||
712 | dllmax[cnt] = dlli; | ||
713 | } | ||
714 | } | ||
715 | mask <<= 1; | ||
716 | } | ||
717 | passcnt++; | ||
718 | } else if (passcnt >= CBR_THRESHOLD2) { | ||
719 | break; | ||
720 | } | ||
721 | } | ||
722 | gold_sadj[0] = 0x0; | ||
723 | passcnt = 0; | ||
724 | for (cnt = 0; cnt < 16; cnt++) { | ||
725 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { | ||
726 | gold_sadj[0] += dllmin[cnt]; | ||
727 | passcnt++; | ||
728 | } | ||
729 | } | ||
730 | if (passcnt != 16) { | ||
731 | goto FINETUNE_START; | ||
732 | } | ||
733 | gold_sadj[0] = gold_sadj[0] >> 4; | ||
734 | gold_sadj[1] = gold_sadj[0]; | ||
735 | |||
736 | data = 0; | ||
737 | for (cnt = 0; cnt < 8; cnt++) { | ||
738 | data >>= 3; | ||
739 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { | ||
740 | dlli = dllmin[cnt]; | ||
741 | if (gold_sadj[0] >= dlli) { | ||
742 | dlli = ((gold_sadj[0] - dlli) * 19) >> 5; | ||
743 | if (dlli > 3) { | ||
744 | dlli = 3; | ||
745 | } | ||
746 | } else { | ||
747 | dlli = ((dlli - gold_sadj[0]) * 19) >> 5; | ||
748 | if (dlli > 4) { | ||
749 | dlli = 4; | ||
750 | } | ||
751 | dlli = (8 - dlli) & 0x7; | ||
752 | } | ||
753 | data |= dlli << 21; | ||
754 | } | ||
755 | } | ||
756 | moutdwm(ast, 0x1E6E0080, data); | ||
757 | |||
758 | data = 0; | ||
759 | for (cnt = 8; cnt < 16; cnt++) { | ||
760 | data >>= 3; | ||
761 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { | ||
762 | dlli = dllmin[cnt]; | ||
763 | if (gold_sadj[1] >= dlli) { | ||
764 | dlli = ((gold_sadj[1] - dlli) * 19) >> 5; | ||
765 | if (dlli > 3) { | ||
766 | dlli = 3; | ||
767 | } else { | ||
768 | dlli = (dlli - 1) & 0x7; | ||
769 | } | ||
770 | } else { | ||
771 | dlli = ((dlli - gold_sadj[1]) * 19) >> 5; | ||
772 | dlli += 1; | ||
773 | if (dlli > 4) { | ||
774 | dlli = 4; | ||
775 | } | ||
776 | dlli = (8 - dlli) & 0x7; | ||
777 | } | ||
778 | data |= dlli << 21; | ||
779 | } | ||
780 | } | ||
781 | moutdwm(ast, 0x1E6E0084, data); | ||
782 | |||
783 | } /* finetuneDQI_L */ | ||
784 | |||
785 | static void finetuneDQI_L2(struct ast_private *ast, struct ast2300_dram_param *param) | ||
786 | { | ||
787 | u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt, data2; | ||
788 | |||
789 | for (cnt = 0; cnt < 16; cnt++) { | ||
790 | dllmin[cnt] = 0xff; | ||
791 | dllmax[cnt] = 0x0; | ||
792 | } | ||
793 | passcnt = 0; | ||
794 | for (dlli = 0; dlli < 76; dlli++) { | ||
795 | moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24)); | ||
796 | /* Wait DQSI latch phase calibration */ | ||
797 | moutdwm(ast, 0x1E6E0074, 0x00000010); | ||
798 | moutdwm(ast, 0x1E6E0070, 0x00000003); | ||
799 | do { | ||
800 | data = mindwm(ast, 0x1E6E0070); | ||
801 | } while (!(data & 0x00001000)); | ||
802 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
803 | |||
804 | moutdwm(ast, 0x1E6E0074, CBR_SIZE2); | ||
805 | data = cbr_scan2(ast); | ||
806 | if (data != 0) { | ||
807 | mask = 0x00010001; | ||
808 | for (cnt = 0; cnt < 16; cnt++) { | ||
809 | if (data & mask) { | ||
810 | if (dllmin[cnt] > dlli) { | ||
811 | dllmin[cnt] = dlli; | ||
812 | } | ||
813 | if (dllmax[cnt] < dlli) { | ||
814 | dllmax[cnt] = dlli; | ||
815 | } | ||
816 | } | ||
817 | mask <<= 1; | ||
818 | } | ||
819 | passcnt++; | ||
820 | } else if (passcnt >= CBR_THRESHOLD2) { | ||
821 | break; | ||
822 | } | ||
823 | } | ||
824 | gold_sadj[0] = 0x0; | ||
825 | gold_sadj[1] = 0xFF; | ||
826 | for (cnt = 0; cnt < 8; cnt++) { | ||
827 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { | ||
828 | if (gold_sadj[0] < dllmin[cnt]) { | ||
829 | gold_sadj[0] = dllmin[cnt]; | ||
830 | } | ||
831 | if (gold_sadj[1] > dllmax[cnt]) { | ||
832 | gold_sadj[1] = dllmax[cnt]; | ||
833 | } | ||
834 | } | ||
835 | } | ||
836 | gold_sadj[0] = (gold_sadj[1] + gold_sadj[0]) >> 1; | ||
837 | gold_sadj[1] = mindwm(ast, 0x1E6E0080); | ||
838 | |||
839 | data = 0; | ||
840 | for (cnt = 0; cnt < 8; cnt++) { | ||
841 | data >>= 3; | ||
842 | data2 = gold_sadj[1] & 0x7; | ||
843 | gold_sadj[1] >>= 3; | ||
844 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { | ||
845 | dlli = (dllmin[cnt] + dllmax[cnt]) >> 1; | ||
846 | if (gold_sadj[0] >= dlli) { | ||
847 | dlli = (gold_sadj[0] - dlli) >> 1; | ||
848 | if (dlli > 0) { | ||
849 | dlli = 1; | ||
850 | } | ||
851 | if (data2 != 3) { | ||
852 | data2 = (data2 + dlli) & 0x7; | ||
853 | } | ||
854 | } else { | ||
855 | dlli = (dlli - gold_sadj[0]) >> 1; | ||
856 | if (dlli > 0) { | ||
857 | dlli = 1; | ||
858 | } | ||
859 | if (data2 != 4) { | ||
860 | data2 = (data2 - dlli) & 0x7; | ||
861 | } | ||
862 | } | ||
863 | } | ||
864 | data |= data2 << 21; | ||
865 | } | ||
866 | moutdwm(ast, 0x1E6E0080, data); | ||
867 | |||
868 | gold_sadj[0] = 0x0; | ||
869 | gold_sadj[1] = 0xFF; | ||
870 | for (cnt = 8; cnt < 16; cnt++) { | ||
871 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { | ||
872 | if (gold_sadj[0] < dllmin[cnt]) { | ||
873 | gold_sadj[0] = dllmin[cnt]; | ||
874 | } | ||
875 | if (gold_sadj[1] > dllmax[cnt]) { | ||
876 | gold_sadj[1] = dllmax[cnt]; | ||
877 | } | ||
878 | } | ||
879 | } | ||
880 | gold_sadj[0] = (gold_sadj[1] + gold_sadj[0]) >> 1; | ||
881 | gold_sadj[1] = mindwm(ast, 0x1E6E0084); | ||
882 | |||
883 | data = 0; | ||
884 | for (cnt = 8; cnt < 16; cnt++) { | ||
885 | data >>= 3; | ||
886 | data2 = gold_sadj[1] & 0x7; | ||
887 | gold_sadj[1] >>= 3; | ||
888 | if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { | ||
889 | dlli = (dllmin[cnt] + dllmax[cnt]) >> 1; | ||
890 | if (gold_sadj[0] >= dlli) { | ||
891 | dlli = (gold_sadj[0] - dlli) >> 1; | ||
892 | if (dlli > 0) { | ||
893 | dlli = 1; | ||
894 | } | ||
895 | if (data2 != 3) { | ||
896 | data2 = (data2 + dlli) & 0x7; | ||
897 | } | ||
898 | } else { | ||
899 | dlli = (dlli - gold_sadj[0]) >> 1; | ||
900 | if (dlli > 0) { | ||
901 | dlli = 1; | ||
902 | } | ||
903 | if (data2 != 4) { | ||
904 | data2 = (data2 - dlli) & 0x7; | ||
905 | } | ||
906 | } | ||
907 | } | ||
908 | data |= data2 << 21; | ||
909 | } | ||
910 | moutdwm(ast, 0x1E6E0084, data); | ||
911 | |||
912 | } /* finetuneDQI_L2 */ | ||
913 | |||
914 | static void cbr_dll2(struct ast_private *ast, struct ast2300_dram_param *param) | ||
915 | { | ||
916 | u32 dllmin[2], dllmax[2], dlli, data, data2, passcnt; | ||
917 | |||
918 | |||
919 | finetuneDQI_L(ast, param); | ||
920 | finetuneDQI_L2(ast, param); | ||
921 | |||
922 | CBR_START2: | ||
923 | dllmin[0] = dllmin[1] = 0xff; | ||
924 | dllmax[0] = dllmax[1] = 0x0; | ||
925 | passcnt = 0; | ||
926 | for (dlli = 0; dlli < 76; dlli++) { | ||
927 | moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli << 24)); | ||
928 | /* Wait DQSI latch phase calibration */ | ||
929 | moutdwm(ast, 0x1E6E0074, 0x00000010); | ||
930 | moutdwm(ast, 0x1E6E0070, 0x00000003); | ||
931 | do { | ||
932 | data = mindwm(ast, 0x1E6E0070); | ||
933 | } while (!(data & 0x00001000)); | ||
934 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
935 | |||
936 | moutdwm(ast, 0x1E6E0074, CBR_SIZE2); | ||
937 | data = cbr_scan(ast); | ||
938 | if (data != 0) { | ||
939 | if (data & 0x1) { | ||
940 | if (dllmin[0] > dlli) { | ||
941 | dllmin[0] = dlli; | ||
942 | } | ||
943 | if (dllmax[0] < dlli) { | ||
944 | dllmax[0] = dlli; | ||
945 | } | ||
946 | } | ||
947 | if (data & 0x2) { | ||
948 | if (dllmin[1] > dlli) { | ||
949 | dllmin[1] = dlli; | ||
950 | } | ||
951 | if (dllmax[1] < dlli) { | ||
952 | dllmax[1] = dlli; | ||
953 | } | ||
954 | } | ||
955 | passcnt++; | ||
956 | } else if (passcnt >= CBR_THRESHOLD) { | ||
957 | break; | ||
958 | } | ||
959 | } | ||
960 | if (dllmax[0] == 0 || (dllmax[0]-dllmin[0]) < CBR_THRESHOLD) { | ||
961 | goto CBR_START2; | ||
962 | } | ||
963 | if (dllmax[1] == 0 || (dllmax[1]-dllmin[1]) < CBR_THRESHOLD) { | ||
964 | goto CBR_START2; | ||
965 | } | ||
966 | dlli = (dllmin[1] + dllmax[1]) >> 1; | ||
967 | dlli <<= 8; | ||
968 | dlli += (dllmin[0] + dllmax[0]) >> 1; | ||
969 | moutdwm(ast, 0x1E6E0068, (mindwm(ast, 0x1E6E0068) & 0xFFFF) | (dlli << 16)); | ||
970 | |||
971 | data = (mindwm(ast, 0x1E6E0080) >> 24) & 0x1F; | ||
972 | data2 = (mindwm(ast, 0x1E6E0018) & 0xff80ffff) | (data << 16); | ||
973 | moutdwm(ast, 0x1E6E0018, data2); | ||
974 | moutdwm(ast, 0x1E6E0024, 0x8001 | (data << 1) | (param->dll2_finetune_step << 8)); | ||
975 | |||
976 | /* Wait DQSI latch phase calibration */ | ||
977 | moutdwm(ast, 0x1E6E0074, 0x00000010); | ||
978 | moutdwm(ast, 0x1E6E0070, 0x00000003); | ||
979 | do { | ||
980 | data = mindwm(ast, 0x1E6E0070); | ||
981 | } while (!(data & 0x00001000)); | ||
982 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
983 | moutdwm(ast, 0x1E6E0070, 0x00000003); | ||
984 | do { | ||
985 | data = mindwm(ast, 0x1E6E0070); | ||
986 | } while (!(data & 0x00001000)); | ||
987 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
988 | } /* CBRDLL2 */ | ||
989 | |||
990 | static void get_ddr3_info(struct ast_private *ast, struct ast2300_dram_param *param) | ||
991 | { | ||
992 | u32 trap, trap_AC2, trap_MRS; | ||
993 | |||
994 | moutdwm(ast, 0x1E6E2000, 0x1688A8A8); | ||
995 | |||
996 | /* Ger trap info */ | ||
997 | trap = (mindwm(ast, 0x1E6E2070) >> 25) & 0x3; | ||
998 | trap_AC2 = 0x00020000 + (trap << 16); | ||
999 | trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19); | ||
1000 | trap_MRS = 0x00000010 + (trap << 4); | ||
1001 | trap_MRS |= ((trap & 0x2) << 18); | ||
1002 | |||
1003 | param->reg_MADJ = 0x00034C4C; | ||
1004 | param->reg_SADJ = 0x00001800; | ||
1005 | param->reg_DRV = 0x000000F0; | ||
1006 | param->reg_PERIOD = param->dram_freq; | ||
1007 | param->rodt = 0; | ||
1008 | |||
1009 | switch (param->dram_freq) { | ||
1010 | case 336: | ||
1011 | moutdwm(ast, 0x1E6E2020, 0x0190); | ||
1012 | param->wodt = 0; | ||
1013 | param->reg_AC1 = 0x22202725; | ||
1014 | param->reg_AC2 = 0xAA007613 | trap_AC2; | ||
1015 | param->reg_DQSIC = 0x000000BA; | ||
1016 | param->reg_MRS = 0x04001400 | trap_MRS; | ||
1017 | param->reg_EMRS = 0x00000000; | ||
1018 | param->reg_IOZ = 0x00000034; | ||
1019 | param->reg_DQIDLY = 0x00000074; | ||
1020 | param->reg_FREQ = 0x00004DC0; | ||
1021 | param->madj_max = 96; | ||
1022 | param->dll2_finetune_step = 3; | ||
1023 | break; | ||
1024 | default: | ||
1025 | case 396: | ||
1026 | moutdwm(ast, 0x1E6E2020, 0x03F1); | ||
1027 | param->wodt = 1; | ||
1028 | param->reg_AC1 = 0x33302825; | ||
1029 | param->reg_AC2 = 0xCC009617 | trap_AC2; | ||
1030 | param->reg_DQSIC = 0x000000E2; | ||
1031 | param->reg_MRS = 0x04001600 | trap_MRS; | ||
1032 | param->reg_EMRS = 0x00000000; | ||
1033 | param->reg_IOZ = 0x00000034; | ||
1034 | param->reg_DRV = 0x000000FA; | ||
1035 | param->reg_DQIDLY = 0x00000089; | ||
1036 | param->reg_FREQ = 0x000050C0; | ||
1037 | param->madj_max = 96; | ||
1038 | param->dll2_finetune_step = 4; | ||
1039 | |||
1040 | switch (param->dram_chipid) { | ||
1041 | default: | ||
1042 | case AST_DRAM_512Mx16: | ||
1043 | case AST_DRAM_1Gx16: | ||
1044 | param->reg_AC2 = 0xCC009617 | trap_AC2; | ||
1045 | break; | ||
1046 | case AST_DRAM_2Gx16: | ||
1047 | param->reg_AC2 = 0xCC009622 | trap_AC2; | ||
1048 | break; | ||
1049 | case AST_DRAM_4Gx16: | ||
1050 | param->reg_AC2 = 0xCC00963F | trap_AC2; | ||
1051 | break; | ||
1052 | } | ||
1053 | break; | ||
1054 | |||
1055 | case 408: | ||
1056 | moutdwm(ast, 0x1E6E2020, 0x01F0); | ||
1057 | param->wodt = 1; | ||
1058 | param->reg_AC1 = 0x33302825; | ||
1059 | param->reg_AC2 = 0xCC009617 | trap_AC2; | ||
1060 | param->reg_DQSIC = 0x000000E2; | ||
1061 | param->reg_MRS = 0x04001600 | trap_MRS; | ||
1062 | param->reg_EMRS = 0x00000000; | ||
1063 | param->reg_IOZ = 0x00000034; | ||
1064 | param->reg_DRV = 0x000000FA; | ||
1065 | param->reg_DQIDLY = 0x00000089; | ||
1066 | param->reg_FREQ = 0x000050C0; | ||
1067 | param->madj_max = 96; | ||
1068 | param->dll2_finetune_step = 4; | ||
1069 | |||
1070 | switch (param->dram_chipid) { | ||
1071 | default: | ||
1072 | case AST_DRAM_512Mx16: | ||
1073 | case AST_DRAM_1Gx16: | ||
1074 | param->reg_AC2 = 0xCC009617 | trap_AC2; | ||
1075 | break; | ||
1076 | case AST_DRAM_2Gx16: | ||
1077 | param->reg_AC2 = 0xCC009622 | trap_AC2; | ||
1078 | break; | ||
1079 | case AST_DRAM_4Gx16: | ||
1080 | param->reg_AC2 = 0xCC00963F | trap_AC2; | ||
1081 | break; | ||
1082 | } | ||
1083 | |||
1084 | break; | ||
1085 | case 456: | ||
1086 | moutdwm(ast, 0x1E6E2020, 0x0230); | ||
1087 | param->wodt = 0; | ||
1088 | param->reg_AC1 = 0x33302926; | ||
1089 | param->reg_AC2 = 0xCD44961A; | ||
1090 | param->reg_DQSIC = 0x000000FC; | ||
1091 | param->reg_MRS = 0x00081830; | ||
1092 | param->reg_EMRS = 0x00000000; | ||
1093 | param->reg_IOZ = 0x00000045; | ||
1094 | param->reg_DQIDLY = 0x00000097; | ||
1095 | param->reg_FREQ = 0x000052C0; | ||
1096 | param->madj_max = 88; | ||
1097 | param->dll2_finetune_step = 4; | ||
1098 | break; | ||
1099 | case 504: | ||
1100 | moutdwm(ast, 0x1E6E2020, 0x0270); | ||
1101 | param->wodt = 1; | ||
1102 | param->reg_AC1 = 0x33302926; | ||
1103 | param->reg_AC2 = 0xDE44A61D; | ||
1104 | param->reg_DQSIC = 0x00000117; | ||
1105 | param->reg_MRS = 0x00081A30; | ||
1106 | param->reg_EMRS = 0x00000000; | ||
1107 | param->reg_IOZ = 0x070000BB; | ||
1108 | param->reg_DQIDLY = 0x000000A0; | ||
1109 | param->reg_FREQ = 0x000054C0; | ||
1110 | param->madj_max = 79; | ||
1111 | param->dll2_finetune_step = 4; | ||
1112 | break; | ||
1113 | case 528: | ||
1114 | moutdwm(ast, 0x1E6E2020, 0x0290); | ||
1115 | param->wodt = 1; | ||
1116 | param->rodt = 1; | ||
1117 | param->reg_AC1 = 0x33302926; | ||
1118 | param->reg_AC2 = 0xEF44B61E; | ||
1119 | param->reg_DQSIC = 0x00000125; | ||
1120 | param->reg_MRS = 0x00081A30; | ||
1121 | param->reg_EMRS = 0x00000040; | ||
1122 | param->reg_DRV = 0x000000F5; | ||
1123 | param->reg_IOZ = 0x00000023; | ||
1124 | param->reg_DQIDLY = 0x00000088; | ||
1125 | param->reg_FREQ = 0x000055C0; | ||
1126 | param->madj_max = 76; | ||
1127 | param->dll2_finetune_step = 3; | ||
1128 | break; | ||
1129 | case 576: | ||
1130 | moutdwm(ast, 0x1E6E2020, 0x0140); | ||
1131 | param->reg_MADJ = 0x00136868; | ||
1132 | param->reg_SADJ = 0x00004534; | ||
1133 | param->wodt = 1; | ||
1134 | param->rodt = 1; | ||
1135 | param->reg_AC1 = 0x33302A37; | ||
1136 | param->reg_AC2 = 0xEF56B61E; | ||
1137 | param->reg_DQSIC = 0x0000013F; | ||
1138 | param->reg_MRS = 0x00101A50; | ||
1139 | param->reg_EMRS = 0x00000040; | ||
1140 | param->reg_DRV = 0x000000FA; | ||
1141 | param->reg_IOZ = 0x00000023; | ||
1142 | param->reg_DQIDLY = 0x00000078; | ||
1143 | param->reg_FREQ = 0x000057C0; | ||
1144 | param->madj_max = 136; | ||
1145 | param->dll2_finetune_step = 3; | ||
1146 | break; | ||
1147 | case 600: | ||
1148 | moutdwm(ast, 0x1E6E2020, 0x02E1); | ||
1149 | param->reg_MADJ = 0x00136868; | ||
1150 | param->reg_SADJ = 0x00004534; | ||
1151 | param->wodt = 1; | ||
1152 | param->rodt = 1; | ||
1153 | param->reg_AC1 = 0x32302A37; | ||
1154 | param->reg_AC2 = 0xDF56B61F; | ||
1155 | param->reg_DQSIC = 0x0000014D; | ||
1156 | param->reg_MRS = 0x00101A50; | ||
1157 | param->reg_EMRS = 0x00000004; | ||
1158 | param->reg_DRV = 0x000000F5; | ||
1159 | param->reg_IOZ = 0x00000023; | ||
1160 | param->reg_DQIDLY = 0x00000078; | ||
1161 | param->reg_FREQ = 0x000058C0; | ||
1162 | param->madj_max = 132; | ||
1163 | param->dll2_finetune_step = 3; | ||
1164 | break; | ||
1165 | case 624: | ||
1166 | moutdwm(ast, 0x1E6E2020, 0x0160); | ||
1167 | param->reg_MADJ = 0x00136868; | ||
1168 | param->reg_SADJ = 0x00004534; | ||
1169 | param->wodt = 1; | ||
1170 | param->rodt = 1; | ||
1171 | param->reg_AC1 = 0x32302A37; | ||
1172 | param->reg_AC2 = 0xEF56B621; | ||
1173 | param->reg_DQSIC = 0x0000015A; | ||
1174 | param->reg_MRS = 0x02101A50; | ||
1175 | param->reg_EMRS = 0x00000004; | ||
1176 | param->reg_DRV = 0x000000F5; | ||
1177 | param->reg_IOZ = 0x00000034; | ||
1178 | param->reg_DQIDLY = 0x00000078; | ||
1179 | param->reg_FREQ = 0x000059C0; | ||
1180 | param->madj_max = 128; | ||
1181 | param->dll2_finetune_step = 3; | ||
1182 | break; | ||
1183 | } /* switch freq */ | ||
1184 | |||
1185 | switch (param->dram_chipid) { | ||
1186 | case AST_DRAM_512Mx16: | ||
1187 | param->dram_config = 0x130; | ||
1188 | break; | ||
1189 | default: | ||
1190 | case AST_DRAM_1Gx16: | ||
1191 | param->dram_config = 0x131; | ||
1192 | break; | ||
1193 | case AST_DRAM_2Gx16: | ||
1194 | param->dram_config = 0x132; | ||
1195 | break; | ||
1196 | case AST_DRAM_4Gx16: | ||
1197 | param->dram_config = 0x133; | ||
1198 | break; | ||
1199 | }; /* switch size */ | ||
1200 | |||
1201 | switch (param->vram_size) { | ||
1202 | default: | ||
1203 | case AST_VIDMEM_SIZE_8M: | ||
1204 | param->dram_config |= 0x00; | ||
1205 | break; | ||
1206 | case AST_VIDMEM_SIZE_16M: | ||
1207 | param->dram_config |= 0x04; | ||
1208 | break; | ||
1209 | case AST_VIDMEM_SIZE_32M: | ||
1210 | param->dram_config |= 0x08; | ||
1211 | break; | ||
1212 | case AST_VIDMEM_SIZE_64M: | ||
1213 | param->dram_config |= 0x0c; | ||
1214 | break; | ||
1215 | } | ||
1216 | |||
1217 | } | ||
1218 | |||
1219 | static void ddr3_init(struct ast_private *ast, struct ast2300_dram_param *param) | ||
1220 | { | ||
1221 | u32 data, data2; | ||
1222 | |||
1223 | moutdwm(ast, 0x1E6E0000, 0xFC600309); | ||
1224 | moutdwm(ast, 0x1E6E0018, 0x00000100); | ||
1225 | moutdwm(ast, 0x1E6E0024, 0x00000000); | ||
1226 | moutdwm(ast, 0x1E6E0034, 0x00000000); | ||
1227 | udelay(10); | ||
1228 | moutdwm(ast, 0x1E6E0064, param->reg_MADJ); | ||
1229 | moutdwm(ast, 0x1E6E0068, param->reg_SADJ); | ||
1230 | udelay(10); | ||
1231 | moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); | ||
1232 | udelay(10); | ||
1233 | |||
1234 | moutdwm(ast, 0x1E6E0004, param->dram_config); | ||
1235 | moutdwm(ast, 0x1E6E0008, 0x90040f); | ||
1236 | moutdwm(ast, 0x1E6E0010, param->reg_AC1); | ||
1237 | moutdwm(ast, 0x1E6E0014, param->reg_AC2); | ||
1238 | moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); | ||
1239 | moutdwm(ast, 0x1E6E0080, 0x00000000); | ||
1240 | moutdwm(ast, 0x1E6E0084, 0x00000000); | ||
1241 | moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); | ||
1242 | moutdwm(ast, 0x1E6E0018, 0x4040A170); | ||
1243 | moutdwm(ast, 0x1E6E0018, 0x20402370); | ||
1244 | moutdwm(ast, 0x1E6E0038, 0x00000000); | ||
1245 | moutdwm(ast, 0x1E6E0040, 0xFF444444); | ||
1246 | moutdwm(ast, 0x1E6E0044, 0x22222222); | ||
1247 | moutdwm(ast, 0x1E6E0048, 0x22222222); | ||
1248 | moutdwm(ast, 0x1E6E004C, 0x00000002); | ||
1249 | moutdwm(ast, 0x1E6E0050, 0x80000000); | ||
1250 | moutdwm(ast, 0x1E6E0050, 0x00000000); | ||
1251 | moutdwm(ast, 0x1E6E0054, 0); | ||
1252 | moutdwm(ast, 0x1E6E0060, param->reg_DRV); | ||
1253 | moutdwm(ast, 0x1E6E006C, param->reg_IOZ); | ||
1254 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
1255 | moutdwm(ast, 0x1E6E0074, 0x00000000); | ||
1256 | moutdwm(ast, 0x1E6E0078, 0x00000000); | ||
1257 | moutdwm(ast, 0x1E6E007C, 0x00000000); | ||
1258 | /* Wait MCLK2X lock to MCLK */ | ||
1259 | do { | ||
1260 | data = mindwm(ast, 0x1E6E001C); | ||
1261 | } while (!(data & 0x08000000)); | ||
1262 | moutdwm(ast, 0x1E6E0034, 0x00000001); | ||
1263 | moutdwm(ast, 0x1E6E000C, 0x00005C04); | ||
1264 | udelay(10); | ||
1265 | moutdwm(ast, 0x1E6E000C, 0x00000000); | ||
1266 | moutdwm(ast, 0x1E6E0034, 0x00000000); | ||
1267 | data = mindwm(ast, 0x1E6E001C); | ||
1268 | data = (data >> 8) & 0xff; | ||
1269 | while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { | ||
1270 | data2 = (mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; | ||
1271 | if ((data2 & 0xff) > param->madj_max) { | ||
1272 | break; | ||
1273 | } | ||
1274 | moutdwm(ast, 0x1E6E0064, data2); | ||
1275 | if (data2 & 0x00100000) { | ||
1276 | data2 = ((data2 & 0xff) >> 3) + 3; | ||
1277 | } else { | ||
1278 | data2 = ((data2 & 0xff) >> 2) + 5; | ||
1279 | } | ||
1280 | data = mindwm(ast, 0x1E6E0068) & 0xffff00ff; | ||
1281 | data2 += data & 0xff; | ||
1282 | data = data | (data2 << 8); | ||
1283 | moutdwm(ast, 0x1E6E0068, data); | ||
1284 | udelay(10); | ||
1285 | moutdwm(ast, 0x1E6E0064, mindwm(ast, 0x1E6E0064) | 0xC0000); | ||
1286 | udelay(10); | ||
1287 | data = mindwm(ast, 0x1E6E0018) & 0xfffff1ff; | ||
1288 | moutdwm(ast, 0x1E6E0018, data); | ||
1289 | data = data | 0x200; | ||
1290 | moutdwm(ast, 0x1E6E0018, data); | ||
1291 | do { | ||
1292 | data = mindwm(ast, 0x1E6E001C); | ||
1293 | } while (!(data & 0x08000000)); | ||
1294 | |||
1295 | moutdwm(ast, 0x1E6E0034, 0x00000001); | ||
1296 | moutdwm(ast, 0x1E6E000C, 0x00005C04); | ||
1297 | udelay(10); | ||
1298 | moutdwm(ast, 0x1E6E000C, 0x00000000); | ||
1299 | moutdwm(ast, 0x1E6E0034, 0x00000000); | ||
1300 | data = mindwm(ast, 0x1E6E001C); | ||
1301 | data = (data >> 8) & 0xff; | ||
1302 | } | ||
1303 | data = mindwm(ast, 0x1E6E0018) | 0xC00; | ||
1304 | moutdwm(ast, 0x1E6E0018, data); | ||
1305 | |||
1306 | moutdwm(ast, 0x1E6E0034, 0x00000001); | ||
1307 | moutdwm(ast, 0x1E6E000C, 0x00000040); | ||
1308 | udelay(50); | ||
1309 | /* Mode Register Setting */ | ||
1310 | moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); | ||
1311 | moutdwm(ast, 0x1E6E0030, param->reg_EMRS); | ||
1312 | moutdwm(ast, 0x1E6E0028, 0x00000005); | ||
1313 | moutdwm(ast, 0x1E6E0028, 0x00000007); | ||
1314 | moutdwm(ast, 0x1E6E0028, 0x00000003); | ||
1315 | moutdwm(ast, 0x1E6E0028, 0x00000001); | ||
1316 | moutdwm(ast, 0x1E6E002C, param->reg_MRS); | ||
1317 | moutdwm(ast, 0x1E6E000C, 0x00005C08); | ||
1318 | moutdwm(ast, 0x1E6E0028, 0x00000001); | ||
1319 | |||
1320 | moutdwm(ast, 0x1E6E000C, 0x7FFF5C01); | ||
1321 | data = 0; | ||
1322 | if (param->wodt) { | ||
1323 | data = 0x300; | ||
1324 | } | ||
1325 | if (param->rodt) { | ||
1326 | data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); | ||
1327 | } | ||
1328 | moutdwm(ast, 0x1E6E0034, data | 0x3); | ||
1329 | |||
1330 | /* Wait DQI delay lock */ | ||
1331 | do { | ||
1332 | data = mindwm(ast, 0x1E6E0080); | ||
1333 | } while (!(data & 0x40000000)); | ||
1334 | /* Wait DQSI delay lock */ | ||
1335 | do { | ||
1336 | data = mindwm(ast, 0x1E6E0020); | ||
1337 | } while (!(data & 0x00000800)); | ||
1338 | /* Calibrate the DQSI delay */ | ||
1339 | cbr_dll2(ast, param); | ||
1340 | |||
1341 | moutdwm(ast, 0x1E6E0120, param->reg_FREQ); | ||
1342 | /* ECC Memory Initialization */ | ||
1343 | #ifdef ECC | ||
1344 | moutdwm(ast, 0x1E6E007C, 0x00000000); | ||
1345 | moutdwm(ast, 0x1E6E0070, 0x221); | ||
1346 | do { | ||
1347 | data = mindwm(ast, 0x1E6E0070); | ||
1348 | } while (!(data & 0x00001000)); | ||
1349 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
1350 | moutdwm(ast, 0x1E6E0050, 0x80000000); | ||
1351 | moutdwm(ast, 0x1E6E0050, 0x00000000); | ||
1352 | #endif | ||
1353 | |||
1354 | |||
1355 | } | ||
1356 | |||
1357 | static void get_ddr2_info(struct ast_private *ast, struct ast2300_dram_param *param) | ||
1358 | { | ||
1359 | u32 trap, trap_AC2, trap_MRS; | ||
1360 | |||
1361 | moutdwm(ast, 0x1E6E2000, 0x1688A8A8); | ||
1362 | |||
1363 | /* Ger trap info */ | ||
1364 | trap = (mindwm(ast, 0x1E6E2070) >> 25) & 0x3; | ||
1365 | trap_AC2 = (trap << 20) | (trap << 16); | ||
1366 | trap_AC2 += 0x00110000; | ||
1367 | trap_MRS = 0x00000040 | (trap << 4); | ||
1368 | |||
1369 | |||
1370 | param->reg_MADJ = 0x00034C4C; | ||
1371 | param->reg_SADJ = 0x00001800; | ||
1372 | param->reg_DRV = 0x000000F0; | ||
1373 | param->reg_PERIOD = param->dram_freq; | ||
1374 | param->rodt = 0; | ||
1375 | |||
1376 | switch (param->dram_freq) { | ||
1377 | case 264: | ||
1378 | moutdwm(ast, 0x1E6E2020, 0x0130); | ||
1379 | param->wodt = 0; | ||
1380 | param->reg_AC1 = 0x11101513; | ||
1381 | param->reg_AC2 = 0x78117011; | ||
1382 | param->reg_DQSIC = 0x00000092; | ||
1383 | param->reg_MRS = 0x00000842; | ||
1384 | param->reg_EMRS = 0x00000000; | ||
1385 | param->reg_DRV = 0x000000F0; | ||
1386 | param->reg_IOZ = 0x00000034; | ||
1387 | param->reg_DQIDLY = 0x0000005A; | ||
1388 | param->reg_FREQ = 0x00004AC0; | ||
1389 | param->madj_max = 138; | ||
1390 | param->dll2_finetune_step = 3; | ||
1391 | break; | ||
1392 | case 336: | ||
1393 | moutdwm(ast, 0x1E6E2020, 0x0190); | ||
1394 | param->wodt = 1; | ||
1395 | param->reg_AC1 = 0x22202613; | ||
1396 | param->reg_AC2 = 0xAA009016 | trap_AC2; | ||
1397 | param->reg_DQSIC = 0x000000BA; | ||
1398 | param->reg_MRS = 0x00000A02 | trap_MRS; | ||
1399 | param->reg_EMRS = 0x00000040; | ||
1400 | param->reg_DRV = 0x000000FA; | ||
1401 | param->reg_IOZ = 0x00000034; | ||
1402 | param->reg_DQIDLY = 0x00000074; | ||
1403 | param->reg_FREQ = 0x00004DC0; | ||
1404 | param->madj_max = 96; | ||
1405 | param->dll2_finetune_step = 3; | ||
1406 | break; | ||
1407 | default: | ||
1408 | case 396: | ||
1409 | moutdwm(ast, 0x1E6E2020, 0x03F1); | ||
1410 | param->wodt = 1; | ||
1411 | param->rodt = 0; | ||
1412 | param->reg_AC1 = 0x33302714; | ||
1413 | param->reg_AC2 = 0xCC00B01B | trap_AC2; | ||
1414 | param->reg_DQSIC = 0x000000E2; | ||
1415 | param->reg_MRS = 0x00000C02 | trap_MRS; | ||
1416 | param->reg_EMRS = 0x00000040; | ||
1417 | param->reg_DRV = 0x000000FA; | ||
1418 | param->reg_IOZ = 0x00000034; | ||
1419 | param->reg_DQIDLY = 0x00000089; | ||
1420 | param->reg_FREQ = 0x000050C0; | ||
1421 | param->madj_max = 96; | ||
1422 | param->dll2_finetune_step = 4; | ||
1423 | |||
1424 | switch (param->dram_chipid) { | ||
1425 | case AST_DRAM_512Mx16: | ||
1426 | param->reg_AC2 = 0xCC00B016 | trap_AC2; | ||
1427 | break; | ||
1428 | default: | ||
1429 | case AST_DRAM_1Gx16: | ||
1430 | param->reg_AC2 = 0xCC00B01B | trap_AC2; | ||
1431 | break; | ||
1432 | case AST_DRAM_2Gx16: | ||
1433 | param->reg_AC2 = 0xCC00B02B | trap_AC2; | ||
1434 | break; | ||
1435 | case AST_DRAM_4Gx16: | ||
1436 | param->reg_AC2 = 0xCC00B03F | trap_AC2; | ||
1437 | break; | ||
1438 | } | ||
1439 | |||
1440 | break; | ||
1441 | |||
1442 | case 408: | ||
1443 | moutdwm(ast, 0x1E6E2020, 0x01F0); | ||
1444 | param->wodt = 1; | ||
1445 | param->rodt = 0; | ||
1446 | param->reg_AC1 = 0x33302714; | ||
1447 | param->reg_AC2 = 0xCC00B01B | trap_AC2; | ||
1448 | param->reg_DQSIC = 0x000000E2; | ||
1449 | param->reg_MRS = 0x00000C02 | trap_MRS; | ||
1450 | param->reg_EMRS = 0x00000040; | ||
1451 | param->reg_DRV = 0x000000FA; | ||
1452 | param->reg_IOZ = 0x00000034; | ||
1453 | param->reg_DQIDLY = 0x00000089; | ||
1454 | param->reg_FREQ = 0x000050C0; | ||
1455 | param->madj_max = 96; | ||
1456 | param->dll2_finetune_step = 4; | ||
1457 | |||
1458 | switch (param->dram_chipid) { | ||
1459 | case AST_DRAM_512Mx16: | ||
1460 | param->reg_AC2 = 0xCC00B016 | trap_AC2; | ||
1461 | break; | ||
1462 | default: | ||
1463 | case AST_DRAM_1Gx16: | ||
1464 | param->reg_AC2 = 0xCC00B01B | trap_AC2; | ||
1465 | break; | ||
1466 | case AST_DRAM_2Gx16: | ||
1467 | param->reg_AC2 = 0xCC00B02B | trap_AC2; | ||
1468 | break; | ||
1469 | case AST_DRAM_4Gx16: | ||
1470 | param->reg_AC2 = 0xCC00B03F | trap_AC2; | ||
1471 | break; | ||
1472 | } | ||
1473 | |||
1474 | break; | ||
1475 | case 456: | ||
1476 | moutdwm(ast, 0x1E6E2020, 0x0230); | ||
1477 | param->wodt = 0; | ||
1478 | param->reg_AC1 = 0x33302815; | ||
1479 | param->reg_AC2 = 0xCD44B01E; | ||
1480 | param->reg_DQSIC = 0x000000FC; | ||
1481 | param->reg_MRS = 0x00000E72; | ||
1482 | param->reg_EMRS = 0x00000000; | ||
1483 | param->reg_DRV = 0x00000000; | ||
1484 | param->reg_IOZ = 0x00000034; | ||
1485 | param->reg_DQIDLY = 0x00000097; | ||
1486 | param->reg_FREQ = 0x000052C0; | ||
1487 | param->madj_max = 88; | ||
1488 | param->dll2_finetune_step = 3; | ||
1489 | break; | ||
1490 | case 504: | ||
1491 | moutdwm(ast, 0x1E6E2020, 0x0261); | ||
1492 | param->wodt = 1; | ||
1493 | param->rodt = 1; | ||
1494 | param->reg_AC1 = 0x33302815; | ||
1495 | param->reg_AC2 = 0xDE44C022; | ||
1496 | param->reg_DQSIC = 0x00000117; | ||
1497 | param->reg_MRS = 0x00000E72; | ||
1498 | param->reg_EMRS = 0x00000040; | ||
1499 | param->reg_DRV = 0x0000000A; | ||
1500 | param->reg_IOZ = 0x00000045; | ||
1501 | param->reg_DQIDLY = 0x000000A0; | ||
1502 | param->reg_FREQ = 0x000054C0; | ||
1503 | param->madj_max = 79; | ||
1504 | param->dll2_finetune_step = 3; | ||
1505 | break; | ||
1506 | case 528: | ||
1507 | moutdwm(ast, 0x1E6E2020, 0x0120); | ||
1508 | param->wodt = 1; | ||
1509 | param->rodt = 1; | ||
1510 | param->reg_AC1 = 0x33302815; | ||
1511 | param->reg_AC2 = 0xEF44D024; | ||
1512 | param->reg_DQSIC = 0x00000125; | ||
1513 | param->reg_MRS = 0x00000E72; | ||
1514 | param->reg_EMRS = 0x00000004; | ||
1515 | param->reg_DRV = 0x000000F9; | ||
1516 | param->reg_IOZ = 0x00000045; | ||
1517 | param->reg_DQIDLY = 0x000000A7; | ||
1518 | param->reg_FREQ = 0x000055C0; | ||
1519 | param->madj_max = 76; | ||
1520 | param->dll2_finetune_step = 3; | ||
1521 | break; | ||
1522 | case 552: | ||
1523 | moutdwm(ast, 0x1E6E2020, 0x02A1); | ||
1524 | param->wodt = 1; | ||
1525 | param->rodt = 1; | ||
1526 | param->reg_AC1 = 0x43402915; | ||
1527 | param->reg_AC2 = 0xFF44E025; | ||
1528 | param->reg_DQSIC = 0x00000132; | ||
1529 | param->reg_MRS = 0x00000E72; | ||
1530 | param->reg_EMRS = 0x00000040; | ||
1531 | param->reg_DRV = 0x0000000A; | ||
1532 | param->reg_IOZ = 0x00000045; | ||
1533 | param->reg_DQIDLY = 0x000000AD; | ||
1534 | param->reg_FREQ = 0x000056C0; | ||
1535 | param->madj_max = 76; | ||
1536 | param->dll2_finetune_step = 3; | ||
1537 | break; | ||
1538 | case 576: | ||
1539 | moutdwm(ast, 0x1E6E2020, 0x0140); | ||
1540 | param->wodt = 1; | ||
1541 | param->rodt = 1; | ||
1542 | param->reg_AC1 = 0x43402915; | ||
1543 | param->reg_AC2 = 0xFF44E027; | ||
1544 | param->reg_DQSIC = 0x0000013F; | ||
1545 | param->reg_MRS = 0x00000E72; | ||
1546 | param->reg_EMRS = 0x00000004; | ||
1547 | param->reg_DRV = 0x000000F5; | ||
1548 | param->reg_IOZ = 0x00000045; | ||
1549 | param->reg_DQIDLY = 0x000000B3; | ||
1550 | param->reg_FREQ = 0x000057C0; | ||
1551 | param->madj_max = 76; | ||
1552 | param->dll2_finetune_step = 3; | ||
1553 | break; | ||
1554 | } | ||
1555 | |||
1556 | switch (param->dram_chipid) { | ||
1557 | case AST_DRAM_512Mx16: | ||
1558 | param->dram_config = 0x100; | ||
1559 | break; | ||
1560 | default: | ||
1561 | case AST_DRAM_1Gx16: | ||
1562 | param->dram_config = 0x121; | ||
1563 | break; | ||
1564 | case AST_DRAM_2Gx16: | ||
1565 | param->dram_config = 0x122; | ||
1566 | break; | ||
1567 | case AST_DRAM_4Gx16: | ||
1568 | param->dram_config = 0x123; | ||
1569 | break; | ||
1570 | }; /* switch size */ | ||
1571 | |||
1572 | switch (param->vram_size) { | ||
1573 | default: | ||
1574 | case AST_VIDMEM_SIZE_8M: | ||
1575 | param->dram_config |= 0x00; | ||
1576 | break; | ||
1577 | case AST_VIDMEM_SIZE_16M: | ||
1578 | param->dram_config |= 0x04; | ||
1579 | break; | ||
1580 | case AST_VIDMEM_SIZE_32M: | ||
1581 | param->dram_config |= 0x08; | ||
1582 | break; | ||
1583 | case AST_VIDMEM_SIZE_64M: | ||
1584 | param->dram_config |= 0x0c; | ||
1585 | break; | ||
1586 | } | ||
1587 | } | ||
1588 | |||
1589 | static void ddr2_init(struct ast_private *ast, struct ast2300_dram_param *param) | ||
1590 | { | ||
1591 | u32 data, data2; | ||
1592 | |||
1593 | moutdwm(ast, 0x1E6E0000, 0xFC600309); | ||
1594 | moutdwm(ast, 0x1E6E0018, 0x00000100); | ||
1595 | moutdwm(ast, 0x1E6E0024, 0x00000000); | ||
1596 | moutdwm(ast, 0x1E6E0064, param->reg_MADJ); | ||
1597 | moutdwm(ast, 0x1E6E0068, param->reg_SADJ); | ||
1598 | udelay(10); | ||
1599 | moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); | ||
1600 | udelay(10); | ||
1601 | |||
1602 | moutdwm(ast, 0x1E6E0004, param->dram_config); | ||
1603 | moutdwm(ast, 0x1E6E0008, 0x90040f); | ||
1604 | moutdwm(ast, 0x1E6E0010, param->reg_AC1); | ||
1605 | moutdwm(ast, 0x1E6E0014, param->reg_AC2); | ||
1606 | moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); | ||
1607 | moutdwm(ast, 0x1E6E0080, 0x00000000); | ||
1608 | moutdwm(ast, 0x1E6E0084, 0x00000000); | ||
1609 | moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); | ||
1610 | moutdwm(ast, 0x1E6E0018, 0x4040A130); | ||
1611 | moutdwm(ast, 0x1E6E0018, 0x20402330); | ||
1612 | moutdwm(ast, 0x1E6E0038, 0x00000000); | ||
1613 | moutdwm(ast, 0x1E6E0040, 0xFF808000); | ||
1614 | moutdwm(ast, 0x1E6E0044, 0x88848466); | ||
1615 | moutdwm(ast, 0x1E6E0048, 0x44440008); | ||
1616 | moutdwm(ast, 0x1E6E004C, 0x00000000); | ||
1617 | moutdwm(ast, 0x1E6E0050, 0x80000000); | ||
1618 | moutdwm(ast, 0x1E6E0050, 0x00000000); | ||
1619 | moutdwm(ast, 0x1E6E0054, 0); | ||
1620 | moutdwm(ast, 0x1E6E0060, param->reg_DRV); | ||
1621 | moutdwm(ast, 0x1E6E006C, param->reg_IOZ); | ||
1622 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
1623 | moutdwm(ast, 0x1E6E0074, 0x00000000); | ||
1624 | moutdwm(ast, 0x1E6E0078, 0x00000000); | ||
1625 | moutdwm(ast, 0x1E6E007C, 0x00000000); | ||
1626 | |||
1627 | /* Wait MCLK2X lock to MCLK */ | ||
1628 | do { | ||
1629 | data = mindwm(ast, 0x1E6E001C); | ||
1630 | } while (!(data & 0x08000000)); | ||
1631 | moutdwm(ast, 0x1E6E0034, 0x00000001); | ||
1632 | moutdwm(ast, 0x1E6E000C, 0x00005C04); | ||
1633 | udelay(10); | ||
1634 | moutdwm(ast, 0x1E6E000C, 0x00000000); | ||
1635 | moutdwm(ast, 0x1E6E0034, 0x00000000); | ||
1636 | data = mindwm(ast, 0x1E6E001C); | ||
1637 | data = (data >> 8) & 0xff; | ||
1638 | while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { | ||
1639 | data2 = (mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; | ||
1640 | if ((data2 & 0xff) > param->madj_max) { | ||
1641 | break; | ||
1642 | } | ||
1643 | moutdwm(ast, 0x1E6E0064, data2); | ||
1644 | if (data2 & 0x00100000) { | ||
1645 | data2 = ((data2 & 0xff) >> 3) + 3; | ||
1646 | } else { | ||
1647 | data2 = ((data2 & 0xff) >> 2) + 5; | ||
1648 | } | ||
1649 | data = mindwm(ast, 0x1E6E0068) & 0xffff00ff; | ||
1650 | data2 += data & 0xff; | ||
1651 | data = data | (data2 << 8); | ||
1652 | moutdwm(ast, 0x1E6E0068, data); | ||
1653 | udelay(10); | ||
1654 | moutdwm(ast, 0x1E6E0064, mindwm(ast, 0x1E6E0064) | 0xC0000); | ||
1655 | udelay(10); | ||
1656 | data = mindwm(ast, 0x1E6E0018) & 0xfffff1ff; | ||
1657 | moutdwm(ast, 0x1E6E0018, data); | ||
1658 | data = data | 0x200; | ||
1659 | moutdwm(ast, 0x1E6E0018, data); | ||
1660 | do { | ||
1661 | data = mindwm(ast, 0x1E6E001C); | ||
1662 | } while (!(data & 0x08000000)); | ||
1663 | |||
1664 | moutdwm(ast, 0x1E6E0034, 0x00000001); | ||
1665 | moutdwm(ast, 0x1E6E000C, 0x00005C04); | ||
1666 | udelay(10); | ||
1667 | moutdwm(ast, 0x1E6E000C, 0x00000000); | ||
1668 | moutdwm(ast, 0x1E6E0034, 0x00000000); | ||
1669 | data = mindwm(ast, 0x1E6E001C); | ||
1670 | data = (data >> 8) & 0xff; | ||
1671 | } | ||
1672 | data = mindwm(ast, 0x1E6E0018) | 0xC00; | ||
1673 | moutdwm(ast, 0x1E6E0018, data); | ||
1674 | |||
1675 | moutdwm(ast, 0x1E6E0034, 0x00000001); | ||
1676 | moutdwm(ast, 0x1E6E000C, 0x00000000); | ||
1677 | udelay(50); | ||
1678 | /* Mode Register Setting */ | ||
1679 | moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); | ||
1680 | moutdwm(ast, 0x1E6E0030, param->reg_EMRS); | ||
1681 | moutdwm(ast, 0x1E6E0028, 0x00000005); | ||
1682 | moutdwm(ast, 0x1E6E0028, 0x00000007); | ||
1683 | moutdwm(ast, 0x1E6E0028, 0x00000003); | ||
1684 | moutdwm(ast, 0x1E6E0028, 0x00000001); | ||
1685 | |||
1686 | moutdwm(ast, 0x1E6E000C, 0x00005C08); | ||
1687 | moutdwm(ast, 0x1E6E002C, param->reg_MRS); | ||
1688 | moutdwm(ast, 0x1E6E0028, 0x00000001); | ||
1689 | moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380); | ||
1690 | moutdwm(ast, 0x1E6E0028, 0x00000003); | ||
1691 | moutdwm(ast, 0x1E6E0030, param->reg_EMRS); | ||
1692 | moutdwm(ast, 0x1E6E0028, 0x00000003); | ||
1693 | |||
1694 | moutdwm(ast, 0x1E6E000C, 0x7FFF5C01); | ||
1695 | data = 0; | ||
1696 | if (param->wodt) { | ||
1697 | data = 0x500; | ||
1698 | } | ||
1699 | if (param->rodt) { | ||
1700 | data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); | ||
1701 | } | ||
1702 | moutdwm(ast, 0x1E6E0034, data | 0x3); | ||
1703 | moutdwm(ast, 0x1E6E0120, param->reg_FREQ); | ||
1704 | |||
1705 | /* Wait DQI delay lock */ | ||
1706 | do { | ||
1707 | data = mindwm(ast, 0x1E6E0080); | ||
1708 | } while (!(data & 0x40000000)); | ||
1709 | /* Wait DQSI delay lock */ | ||
1710 | do { | ||
1711 | data = mindwm(ast, 0x1E6E0020); | ||
1712 | } while (!(data & 0x00000800)); | ||
1713 | /* Calibrate the DQSI delay */ | ||
1714 | cbr_dll2(ast, param); | ||
1715 | |||
1716 | /* ECC Memory Initialization */ | ||
1717 | #ifdef ECC | ||
1718 | moutdwm(ast, 0x1E6E007C, 0x00000000); | ||
1719 | moutdwm(ast, 0x1E6E0070, 0x221); | ||
1720 | do { | ||
1721 | data = mindwm(ast, 0x1E6E0070); | ||
1722 | } while (!(data & 0x00001000)); | ||
1723 | moutdwm(ast, 0x1E6E0070, 0x00000000); | ||
1724 | moutdwm(ast, 0x1E6E0050, 0x80000000); | ||
1725 | moutdwm(ast, 0x1E6E0050, 0x00000000); | ||
1726 | #endif | ||
1727 | |||
1728 | } | ||
1729 | |||
1730 | static void ast_init_dram_2300(struct drm_device *dev) | ||
1731 | { | ||
1732 | struct ast_private *ast = dev->dev_private; | ||
1733 | struct ast2300_dram_param param; | ||
1734 | u32 temp; | ||
1735 | u8 reg; | ||
1736 | |||
1737 | reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); | ||
1738 | if ((reg & 0x80) == 0) {/* vga only */ | ||
1739 | ast_write32(ast, 0xf004, 0x1e6e0000); | ||
1740 | ast_write32(ast, 0xf000, 0x1); | ||
1741 | ast_write32(ast, 0x12000, 0x1688a8a8); | ||
1742 | do { | ||
1743 | ; | ||
1744 | } while (ast_read32(ast, 0x12000) != 0x1); | ||
1745 | |||
1746 | ast_write32(ast, 0x10000, 0xfc600309); | ||
1747 | do { | ||
1748 | ; | ||
1749 | } while (ast_read32(ast, 0x10000) != 0x1); | ||
1750 | |||
1751 | /* Slow down CPU/AHB CLK in VGA only mode */ | ||
1752 | temp = ast_read32(ast, 0x12008); | ||
1753 | temp |= 0x73; | ||
1754 | ast_write32(ast, 0x12008, temp); | ||
1755 | |||
1756 | param.dram_type = AST_DDR3; | ||
1757 | if (temp & 0x01000000) | ||
1758 | param.dram_type = AST_DDR2; | ||
1759 | param.dram_chipid = ast->dram_type; | ||
1760 | param.dram_freq = ast->mclk; | ||
1761 | param.vram_size = ast->vram_size; | ||
1762 | |||
1763 | if (param.dram_type == AST_DDR3) { | ||
1764 | get_ddr3_info(ast, ¶m); | ||
1765 | ddr3_init(ast, ¶m); | ||
1766 | } else { | ||
1767 | get_ddr2_info(ast, ¶m); | ||
1768 | ddr2_init(ast, ¶m); | ||
1769 | } | ||
1770 | |||
1771 | temp = mindwm(ast, 0x1e6e2040); | ||
1772 | moutdwm(ast, 0x1e6e2040, temp | 0x40); | ||
1773 | } | ||
1774 | |||
1775 | /* wait ready */ | ||
1776 | do { | ||
1777 | reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); | ||
1778 | } while ((reg & 0x40) == 0); | ||
1779 | } | ||
1780 | |||
diff --git a/drivers/gpu/drm/ast/ast_tables.h b/drivers/gpu/drm/ast/ast_tables.h new file mode 100644 index 000000000000..95fa6aba26bc --- /dev/null +++ b/drivers/gpu/drm/ast/ast_tables.h | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 ASPEED Technology Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that | ||
7 | * copyright notice and this permission notice appear in supporting | ||
8 | * documentation, and that the name of the authors not be used in | ||
9 | * advertising or publicity pertaining to distribution of the software without | ||
10 | * specific, written prior permission. The authors makes no representations | ||
11 | * about the suitability of this software for any purpose. It is provided | ||
12 | * "as is" without express or implied warranty. | ||
13 | * | ||
14 | * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
20 | * PERFORMANCE OF THIS SOFTWARE. | ||
21 | */ | ||
22 | /* Ported from xf86-video-ast driver */ | ||
23 | |||
24 | #ifndef AST_TABLES_H | ||
25 | #define AST_TABLES_H | ||
26 | |||
27 | /* Std. Table Index Definition */ | ||
28 | #define TextModeIndex 0 | ||
29 | #define EGAModeIndex 1 | ||
30 | #define VGAModeIndex 2 | ||
31 | #define HiCModeIndex 3 | ||
32 | #define TrueCModeIndex 4 | ||
33 | |||
34 | #define Charx8Dot 0x00000001 | ||
35 | #define HalfDCLK 0x00000002 | ||
36 | #define DoubleScanMode 0x00000004 | ||
37 | #define LineCompareOff 0x00000008 | ||
38 | #define SyncPP 0x00000000 | ||
39 | #define SyncPN 0x00000040 | ||
40 | #define SyncNP 0x00000080 | ||
41 | #define SyncNN 0x000000C0 | ||
42 | #define HBorder 0x00000020 | ||
43 | #define VBorder 0x00000010 | ||
44 | #define WideScreenMode 0x00000100 | ||
45 | |||
46 | |||
47 | /* DCLK Index */ | ||
48 | #define VCLK25_175 0x00 | ||
49 | #define VCLK28_322 0x01 | ||
50 | #define VCLK31_5 0x02 | ||
51 | #define VCLK36 0x03 | ||
52 | #define VCLK40 0x04 | ||
53 | #define VCLK49_5 0x05 | ||
54 | #define VCLK50 0x06 | ||
55 | #define VCLK56_25 0x07 | ||
56 | #define VCLK65 0x08 | ||
57 | #define VCLK75 0x09 | ||
58 | #define VCLK78_75 0x0A | ||
59 | #define VCLK94_5 0x0B | ||
60 | #define VCLK108 0x0C | ||
61 | #define VCLK135 0x0D | ||
62 | #define VCLK157_5 0x0E | ||
63 | #define VCLK162 0x0F | ||
64 | /* #define VCLK193_25 0x10 */ | ||
65 | #define VCLK154 0x10 | ||
66 | #define VCLK83_5 0x11 | ||
67 | #define VCLK106_5 0x12 | ||
68 | #define VCLK146_25 0x13 | ||
69 | #define VCLK148_5 0x14 | ||
70 | |||
71 | static struct ast_vbios_dclk_info dclk_table[] = { | ||
72 | {0x2C, 0xE7, 0x03}, /* 00: VCLK25_175 */ | ||
73 | {0x95, 0x62, 0x03}, /* 01: VCLK28_322 */ | ||
74 | {0x67, 0x63, 0x01}, /* 02: VCLK31_5 */ | ||
75 | {0x76, 0x63, 0x01}, /* 03: VCLK36 */ | ||
76 | {0xEE, 0x67, 0x01}, /* 04: VCLK40 */ | ||
77 | {0x82, 0x62, 0x01}, /* 05: VCLK49_5 */ | ||
78 | {0xC6, 0x64, 0x01}, /* 06: VCLK50 */ | ||
79 | {0x94, 0x62, 0x01}, /* 07: VCLK56_25 */ | ||
80 | {0x80, 0x64, 0x00}, /* 08: VCLK65 */ | ||
81 | {0x7B, 0x63, 0x00}, /* 09: VCLK75 */ | ||
82 | {0x67, 0x62, 0x00}, /* 0A: VCLK78_75 */ | ||
83 | {0x7C, 0x62, 0x00}, /* 0B: VCLK94_5 */ | ||
84 | {0x8E, 0x62, 0x00}, /* 0C: VCLK108 */ | ||
85 | {0x85, 0x24, 0x00}, /* 0D: VCLK135 */ | ||
86 | {0x67, 0x22, 0x00}, /* 0E: VCLK157_5 */ | ||
87 | {0x6A, 0x22, 0x00}, /* 0F: VCLK162 */ | ||
88 | {0x4d, 0x4c, 0x80}, /* 10: VCLK154 */ | ||
89 | {0xa7, 0x78, 0x80}, /* 11: VCLK83.5 */ | ||
90 | {0x28, 0x49, 0x80}, /* 12: VCLK106.5 */ | ||
91 | {0x37, 0x49, 0x80}, /* 13: VCLK146.25 */ | ||
92 | {0x1f, 0x45, 0x80}, /* 14: VCLK148.5 */ | ||
93 | }; | ||
94 | |||
95 | static struct ast_vbios_stdtable vbios_stdtable[] = { | ||
96 | /* MD_2_3_400 */ | ||
97 | { | ||
98 | 0x67, | ||
99 | {0x00,0x03,0x00,0x02}, | ||
100 | {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, | ||
101 | 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, | ||
102 | 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, | ||
103 | 0xff}, | ||
104 | {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, | ||
105 | 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, | ||
106 | 0x0c,0x00,0x0f,0x08}, | ||
107 | {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, | ||
108 | 0xff} | ||
109 | }, | ||
110 | /* Mode12/ExtEGATable */ | ||
111 | { | ||
112 | 0xe3, | ||
113 | {0x01,0x0f,0x00,0x06}, | ||
114 | {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, | ||
115 | 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, | ||
116 | 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3, | ||
117 | 0xff}, | ||
118 | {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, | ||
119 | 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, | ||
120 | 0x01,0x00,0x0f,0x00}, | ||
121 | {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, | ||
122 | 0xff} | ||
123 | }, | ||
124 | /* ExtVGATable */ | ||
125 | { | ||
126 | 0x2f, | ||
127 | {0x01,0x0f,0x00,0x0e}, | ||
128 | {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, | ||
129 | 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, | ||
130 | 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, | ||
131 | 0xff}, | ||
132 | {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, | ||
133 | 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, | ||
134 | 0x01,0x00,0x00,0x00}, | ||
135 | {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, | ||
136 | 0xff} | ||
137 | }, | ||
138 | /* ExtHiCTable */ | ||
139 | { | ||
140 | 0x2f, | ||
141 | {0x01,0x0f,0x00,0x0e}, | ||
142 | {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, | ||
143 | 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, | ||
144 | 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, | ||
145 | 0xff}, | ||
146 | {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, | ||
147 | 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, | ||
148 | 0x01,0x00,0x00,0x00}, | ||
149 | {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, | ||
150 | 0xff} | ||
151 | }, | ||
152 | /* ExtTrueCTable */ | ||
153 | { | ||
154 | 0x2f, | ||
155 | {0x01,0x0f,0x00,0x0e}, | ||
156 | {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, | ||
157 | 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, | ||
158 | 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, | ||
159 | 0xff}, | ||
160 | {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, | ||
161 | 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, | ||
162 | 0x01,0x00,0x00,0x00}, | ||
163 | {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, | ||
164 | 0xff} | ||
165 | }, | ||
166 | }; | ||
167 | |||
168 | static struct ast_vbios_enhtable res_640x480[] = { | ||
169 | { 800, 640, 8, 96, 525, 480, 2, 2, VCLK25_175, /* 60Hz */ | ||
170 | (SyncNN | HBorder | VBorder | Charx8Dot), 60, 1, 0x2E }, | ||
171 | { 832, 640, 16, 40, 520, 480, 1, 3, VCLK31_5, /* 72Hz */ | ||
172 | (SyncNN | HBorder | VBorder | Charx8Dot), 72, 2, 0x2E }, | ||
173 | { 840, 640, 16, 64, 500, 480, 1, 3, VCLK31_5, /* 75Hz */ | ||
174 | (SyncNN | Charx8Dot) , 75, 3, 0x2E }, | ||
175 | { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* 85Hz */ | ||
176 | (SyncNN | Charx8Dot) , 85, 4, 0x2E }, | ||
177 | { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* end */ | ||
178 | (SyncNN | Charx8Dot) , 0xFF, 4, 0x2E }, | ||
179 | }; | ||
180 | |||
181 | static struct ast_vbios_enhtable res_800x600[] = { | ||
182 | {1024, 800, 24, 72, 625, 600, 1, 2, VCLK36, /* 56Hz */ | ||
183 | (SyncPP | Charx8Dot), 56, 1, 0x30 }, | ||
184 | {1056, 800, 40, 128, 628, 600, 1, 4, VCLK40, /* 60Hz */ | ||
185 | (SyncPP | Charx8Dot), 60, 2, 0x30 }, | ||
186 | {1040, 800, 56, 120, 666, 600, 37, 6, VCLK50, /* 72Hz */ | ||
187 | (SyncPP | Charx8Dot), 72, 3, 0x30 }, | ||
188 | {1056, 800, 16, 80, 625, 600, 1, 3, VCLK49_5, /* 75Hz */ | ||
189 | (SyncPP | Charx8Dot), 75, 4, 0x30 }, | ||
190 | {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* 85Hz */ | ||
191 | (SyncPP | Charx8Dot), 84, 5, 0x30 }, | ||
192 | {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* end */ | ||
193 | (SyncPP | Charx8Dot), 0xFF, 5, 0x30 }, | ||
194 | }; | ||
195 | |||
196 | |||
197 | static struct ast_vbios_enhtable res_1024x768[] = { | ||
198 | {1344, 1024, 24, 136, 806, 768, 3, 6, VCLK65, /* 60Hz */ | ||
199 | (SyncNN | Charx8Dot), 60, 1, 0x31 }, | ||
200 | {1328, 1024, 24, 136, 806, 768, 3, 6, VCLK75, /* 70Hz */ | ||
201 | (SyncNN | Charx8Dot), 70, 2, 0x31 }, | ||
202 | {1312, 1024, 16, 96, 800, 768, 1, 3, VCLK78_75, /* 75Hz */ | ||
203 | (SyncPP | Charx8Dot), 75, 3, 0x31 }, | ||
204 | {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* 85Hz */ | ||
205 | (SyncPP | Charx8Dot), 84, 4, 0x31 }, | ||
206 | {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* end */ | ||
207 | (SyncPP | Charx8Dot), 0xFF, 4, 0x31 }, | ||
208 | }; | ||
209 | |||
210 | static struct ast_vbios_enhtable res_1280x1024[] = { | ||
211 | {1688, 1280, 48, 112, 1066, 1024, 1, 3, VCLK108, /* 60Hz */ | ||
212 | (SyncPP | Charx8Dot), 60, 1, 0x32 }, | ||
213 | {1688, 1280, 16, 144, 1066, 1024, 1, 3, VCLK135, /* 75Hz */ | ||
214 | (SyncPP | Charx8Dot), 75, 2, 0x32 }, | ||
215 | {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* 85Hz */ | ||
216 | (SyncPP | Charx8Dot), 85, 3, 0x32 }, | ||
217 | {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* end */ | ||
218 | (SyncPP | Charx8Dot), 0xFF, 3, 0x32 }, | ||
219 | }; | ||
220 | |||
221 | static struct ast_vbios_enhtable res_1600x1200[] = { | ||
222 | {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* 60Hz */ | ||
223 | (SyncPP | Charx8Dot), 60, 1, 0x33 }, | ||
224 | {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* end */ | ||
225 | (SyncPP | Charx8Dot), 0xFF, 1, 0x33 }, | ||
226 | }; | ||
227 | |||
228 | static struct ast_vbios_enhtable res_1920x1200[] = { | ||
229 | {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */ | ||
230 | (SyncNP | Charx8Dot), 60, 1, 0x34 }, | ||
231 | {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */ | ||
232 | (SyncNP | Charx8Dot), 0xFF, 1, 0x34 }, | ||
233 | }; | ||
234 | |||
235 | /* 16:10 */ | ||
236 | static struct ast_vbios_enhtable res_1280x800[] = { | ||
237 | {1680, 1280, 72,128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */ | ||
238 | (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x35 }, | ||
239 | {1680, 1280, 72,128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */ | ||
240 | (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x35 }, | ||
241 | |||
242 | }; | ||
243 | |||
244 | static struct ast_vbios_enhtable res_1440x900[] = { | ||
245 | {1904, 1440, 80,152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */ | ||
246 | (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x36 }, | ||
247 | {1904, 1440, 80,152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */ | ||
248 | (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x36 }, | ||
249 | }; | ||
250 | |||
251 | static struct ast_vbios_enhtable res_1680x1050[] = { | ||
252 | {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */ | ||
253 | (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x37 }, | ||
254 | {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */ | ||
255 | (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x37 }, | ||
256 | }; | ||
257 | |||
258 | /* HDTV */ | ||
259 | static struct ast_vbios_enhtable res_1920x1080[] = { | ||
260 | {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */ | ||
261 | (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x38 }, | ||
262 | {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */ | ||
263 | (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x38 }, | ||
264 | }; | ||
265 | #endif | ||
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c new file mode 100644 index 000000000000..aad12f747175 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_ttm.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the | ||
6 | * "Software"), to deal in the Software without restriction, including | ||
7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
9 | * permit persons to whom the Software is furnished to do so, subject to | ||
10 | * the following conditions: | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * The above copyright notice and this permission notice (including the | ||
21 | * next paragraph) shall be included in all copies or substantial portions | ||
22 | * of the Software. | ||
23 | * | ||
24 | */ | ||
25 | /* | ||
26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
27 | */ | ||
28 | #include "drmP.h" | ||
29 | #include "ast_drv.h" | ||
30 | #include <ttm/ttm_page_alloc.h> | ||
31 | |||
32 | static inline struct ast_private * | ||
33 | ast_bdev(struct ttm_bo_device *bd) | ||
34 | { | ||
35 | return container_of(bd, struct ast_private, ttm.bdev); | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | ast_ttm_mem_global_init(struct drm_global_reference *ref) | ||
40 | { | ||
41 | return ttm_mem_global_init(ref->object); | ||
42 | } | ||
43 | |||
44 | static void | ||
45 | ast_ttm_mem_global_release(struct drm_global_reference *ref) | ||
46 | { | ||
47 | ttm_mem_global_release(ref->object); | ||
48 | } | ||
49 | |||
50 | static int ast_ttm_global_init(struct ast_private *ast) | ||
51 | { | ||
52 | struct drm_global_reference *global_ref; | ||
53 | int r; | ||
54 | |||
55 | global_ref = &ast->ttm.mem_global_ref; | ||
56 | global_ref->global_type = DRM_GLOBAL_TTM_MEM; | ||
57 | global_ref->size = sizeof(struct ttm_mem_global); | ||
58 | global_ref->init = &ast_ttm_mem_global_init; | ||
59 | global_ref->release = &ast_ttm_mem_global_release; | ||
60 | r = drm_global_item_ref(global_ref); | ||
61 | if (r != 0) { | ||
62 | DRM_ERROR("Failed setting up TTM memory accounting " | ||
63 | "subsystem.\n"); | ||
64 | return r; | ||
65 | } | ||
66 | |||
67 | ast->ttm.bo_global_ref.mem_glob = | ||
68 | ast->ttm.mem_global_ref.object; | ||
69 | global_ref = &ast->ttm.bo_global_ref.ref; | ||
70 | global_ref->global_type = DRM_GLOBAL_TTM_BO; | ||
71 | global_ref->size = sizeof(struct ttm_bo_global); | ||
72 | global_ref->init = &ttm_bo_global_init; | ||
73 | global_ref->release = &ttm_bo_global_release; | ||
74 | r = drm_global_item_ref(global_ref); | ||
75 | if (r != 0) { | ||
76 | DRM_ERROR("Failed setting up TTM BO subsystem.\n"); | ||
77 | drm_global_item_unref(&ast->ttm.mem_global_ref); | ||
78 | return r; | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | void | ||
84 | ast_ttm_global_release(struct ast_private *ast) | ||
85 | { | ||
86 | if (ast->ttm.mem_global_ref.release == NULL) | ||
87 | return; | ||
88 | |||
89 | drm_global_item_unref(&ast->ttm.bo_global_ref.ref); | ||
90 | drm_global_item_unref(&ast->ttm.mem_global_ref); | ||
91 | ast->ttm.mem_global_ref.release = NULL; | ||
92 | } | ||
93 | |||
94 | |||
95 | static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
96 | { | ||
97 | struct ast_bo *bo; | ||
98 | |||
99 | bo = container_of(tbo, struct ast_bo, bo); | ||
100 | |||
101 | drm_gem_object_release(&bo->gem); | ||
102 | kfree(bo); | ||
103 | } | ||
104 | |||
105 | bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo) | ||
106 | { | ||
107 | if (bo->destroy == &ast_bo_ttm_destroy) | ||
108 | return true; | ||
109 | return false; | ||
110 | } | ||
111 | |||
112 | static int | ||
113 | ast_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | ||
114 | struct ttm_mem_type_manager *man) | ||
115 | { | ||
116 | switch (type) { | ||
117 | case TTM_PL_SYSTEM: | ||
118 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
119 | man->available_caching = TTM_PL_MASK_CACHING; | ||
120 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
121 | break; | ||
122 | case TTM_PL_VRAM: | ||
123 | man->func = &ttm_bo_manager_func; | ||
124 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
125 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
126 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
127 | TTM_PL_FLAG_WC; | ||
128 | man->default_caching = TTM_PL_FLAG_WC; | ||
129 | break; | ||
130 | default: | ||
131 | DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | ast_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
139 | { | ||
140 | struct ast_bo *astbo = ast_bo(bo); | ||
141 | |||
142 | if (!ast_ttm_bo_is_ast_bo(bo)) | ||
143 | return; | ||
144 | |||
145 | ast_ttm_placement(astbo, TTM_PL_FLAG_SYSTEM); | ||
146 | *pl = astbo->placement; | ||
147 | } | ||
148 | |||
149 | static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | ||
150 | { | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
155 | struct ttm_mem_reg *mem) | ||
156 | { | ||
157 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
158 | struct ast_private *ast = ast_bdev(bdev); | ||
159 | |||
160 | mem->bus.addr = NULL; | ||
161 | mem->bus.offset = 0; | ||
162 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
163 | mem->bus.base = 0; | ||
164 | mem->bus.is_iomem = false; | ||
165 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
166 | return -EINVAL; | ||
167 | switch (mem->mem_type) { | ||
168 | case TTM_PL_SYSTEM: | ||
169 | /* system memory */ | ||
170 | return 0; | ||
171 | case TTM_PL_VRAM: | ||
172 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
173 | mem->bus.base = pci_resource_start(ast->dev->pdev, 0); | ||
174 | mem->bus.is_iomem = true; | ||
175 | break; | ||
176 | default: | ||
177 | return -EINVAL; | ||
178 | break; | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static void ast_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | ||
184 | { | ||
185 | } | ||
186 | |||
187 | static int ast_bo_move(struct ttm_buffer_object *bo, | ||
188 | bool evict, bool interruptible, | ||
189 | bool no_wait_reserve, bool no_wait_gpu, | ||
190 | struct ttm_mem_reg *new_mem) | ||
191 | { | ||
192 | int r; | ||
193 | r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); | ||
194 | return r; | ||
195 | } | ||
196 | |||
197 | |||
198 | static void ast_ttm_backend_destroy(struct ttm_tt *tt) | ||
199 | { | ||
200 | ttm_tt_fini(tt); | ||
201 | kfree(tt); | ||
202 | } | ||
203 | |||
204 | static struct ttm_backend_func ast_tt_backend_func = { | ||
205 | .destroy = &ast_ttm_backend_destroy, | ||
206 | }; | ||
207 | |||
208 | |||
209 | struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, | ||
210 | unsigned long size, uint32_t page_flags, | ||
211 | struct page *dummy_read_page) | ||
212 | { | ||
213 | struct ttm_tt *tt; | ||
214 | |||
215 | tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); | ||
216 | if (tt == NULL) | ||
217 | return NULL; | ||
218 | tt->func = &ast_tt_backend_func; | ||
219 | if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { | ||
220 | kfree(tt); | ||
221 | return NULL; | ||
222 | } | ||
223 | return tt; | ||
224 | } | ||
225 | |||
226 | static int ast_ttm_tt_populate(struct ttm_tt *ttm) | ||
227 | { | ||
228 | return ttm_pool_populate(ttm); | ||
229 | } | ||
230 | |||
231 | static void ast_ttm_tt_unpopulate(struct ttm_tt *ttm) | ||
232 | { | ||
233 | ttm_pool_unpopulate(ttm); | ||
234 | } | ||
235 | |||
236 | struct ttm_bo_driver ast_bo_driver = { | ||
237 | .ttm_tt_create = ast_ttm_tt_create, | ||
238 | .ttm_tt_populate = ast_ttm_tt_populate, | ||
239 | .ttm_tt_unpopulate = ast_ttm_tt_unpopulate, | ||
240 | .init_mem_type = ast_bo_init_mem_type, | ||
241 | .evict_flags = ast_bo_evict_flags, | ||
242 | .move = ast_bo_move, | ||
243 | .verify_access = ast_bo_verify_access, | ||
244 | .io_mem_reserve = &ast_ttm_io_mem_reserve, | ||
245 | .io_mem_free = &ast_ttm_io_mem_free, | ||
246 | }; | ||
247 | |||
248 | int ast_mm_init(struct ast_private *ast) | ||
249 | { | ||
250 | int ret; | ||
251 | struct drm_device *dev = ast->dev; | ||
252 | struct ttm_bo_device *bdev = &ast->ttm.bdev; | ||
253 | |||
254 | ret = ast_ttm_global_init(ast); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | ret = ttm_bo_device_init(&ast->ttm.bdev, | ||
259 | ast->ttm.bo_global_ref.ref.object, | ||
260 | &ast_bo_driver, DRM_FILE_PAGE_OFFSET, | ||
261 | true); | ||
262 | if (ret) { | ||
263 | DRM_ERROR("Error initialising bo driver; %d\n", ret); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | ||
268 | ast->vram_size >> PAGE_SHIFT); | ||
269 | if (ret) { | ||
270 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | ast->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), | ||
275 | pci_resource_len(dev->pdev, 0), | ||
276 | DRM_MTRR_WC); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | void ast_mm_fini(struct ast_private *ast) | ||
282 | { | ||
283 | struct drm_device *dev = ast->dev; | ||
284 | ttm_bo_device_release(&ast->ttm.bdev); | ||
285 | |||
286 | ast_ttm_global_release(ast); | ||
287 | |||
288 | if (ast->fb_mtrr >= 0) { | ||
289 | drm_mtrr_del(ast->fb_mtrr, | ||
290 | pci_resource_start(dev->pdev, 0), | ||
291 | pci_resource_len(dev->pdev, 0), DRM_MTRR_WC); | ||
292 | ast->fb_mtrr = -1; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | void ast_ttm_placement(struct ast_bo *bo, int domain) | ||
297 | { | ||
298 | u32 c = 0; | ||
299 | bo->placement.fpfn = 0; | ||
300 | bo->placement.lpfn = 0; | ||
301 | bo->placement.placement = bo->placements; | ||
302 | bo->placement.busy_placement = bo->placements; | ||
303 | if (domain & TTM_PL_FLAG_VRAM) | ||
304 | bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
305 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
306 | bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
307 | if (!c) | ||
308 | bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
309 | bo->placement.num_placement = c; | ||
310 | bo->placement.num_busy_placement = c; | ||
311 | } | ||
312 | |||
313 | int ast_bo_reserve(struct ast_bo *bo, bool no_wait) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); | ||
318 | if (ret) { | ||
319 | if (ret != -ERESTARTSYS) | ||
320 | DRM_ERROR("reserve failed %p\n", bo); | ||
321 | return ret; | ||
322 | } | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | void ast_bo_unreserve(struct ast_bo *bo) | ||
327 | { | ||
328 | ttm_bo_unreserve(&bo->bo); | ||
329 | } | ||
330 | |||
331 | int ast_bo_create(struct drm_device *dev, int size, int align, | ||
332 | uint32_t flags, struct ast_bo **pastbo) | ||
333 | { | ||
334 | struct ast_private *ast = dev->dev_private; | ||
335 | struct ast_bo *astbo; | ||
336 | size_t acc_size; | ||
337 | int ret; | ||
338 | |||
339 | astbo = kzalloc(sizeof(struct ast_bo), GFP_KERNEL); | ||
340 | if (!astbo) | ||
341 | return -ENOMEM; | ||
342 | |||
343 | ret = drm_gem_object_init(dev, &astbo->gem, size); | ||
344 | if (ret) { | ||
345 | kfree(astbo); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | astbo->gem.driver_private = NULL; | ||
350 | astbo->bo.bdev = &ast->ttm.bdev; | ||
351 | |||
352 | ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
353 | |||
354 | acc_size = ttm_bo_dma_acc_size(&ast->ttm.bdev, size, | ||
355 | sizeof(struct ast_bo)); | ||
356 | |||
357 | ret = ttm_bo_init(&ast->ttm.bdev, &astbo->bo, size, | ||
358 | ttm_bo_type_device, &astbo->placement, | ||
359 | align >> PAGE_SHIFT, 0, false, NULL, acc_size, | ||
360 | ast_bo_ttm_destroy); | ||
361 | if (ret) | ||
362 | return ret; | ||
363 | |||
364 | *pastbo = astbo; | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static inline u64 ast_bo_gpu_offset(struct ast_bo *bo) | ||
369 | { | ||
370 | return bo->bo.offset; | ||
371 | } | ||
372 | |||
373 | int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
374 | { | ||
375 | int i, ret; | ||
376 | |||
377 | if (bo->pin_count) { | ||
378 | bo->pin_count++; | ||
379 | if (gpu_addr) | ||
380 | *gpu_addr = ast_bo_gpu_offset(bo); | ||
381 | } | ||
382 | |||
383 | ast_ttm_placement(bo, pl_flag); | ||
384 | for (i = 0; i < bo->placement.num_placement; i++) | ||
385 | bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; | ||
386 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
387 | if (ret) | ||
388 | return ret; | ||
389 | |||
390 | bo->pin_count = 1; | ||
391 | if (gpu_addr) | ||
392 | *gpu_addr = ast_bo_gpu_offset(bo); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | int ast_bo_unpin(struct ast_bo *bo) | ||
397 | { | ||
398 | int i, ret; | ||
399 | if (!bo->pin_count) { | ||
400 | DRM_ERROR("unpin bad %p\n", bo); | ||
401 | return 0; | ||
402 | } | ||
403 | bo->pin_count--; | ||
404 | if (bo->pin_count) | ||
405 | return 0; | ||
406 | |||
407 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
408 | bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; | ||
409 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
410 | if (ret) | ||
411 | return ret; | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | int ast_bo_push_sysram(struct ast_bo *bo) | ||
417 | { | ||
418 | int i, ret; | ||
419 | if (!bo->pin_count) { | ||
420 | DRM_ERROR("unpin bad %p\n", bo); | ||
421 | return 0; | ||
422 | } | ||
423 | bo->pin_count--; | ||
424 | if (bo->pin_count) | ||
425 | return 0; | ||
426 | |||
427 | if (bo->kmap.virtual) | ||
428 | ttm_bo_kunmap(&bo->kmap); | ||
429 | |||
430 | ast_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); | ||
431 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
432 | bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; | ||
433 | |||
434 | ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false); | ||
435 | if (ret) { | ||
436 | DRM_ERROR("pushing to VRAM failed\n"); | ||
437 | return ret; | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | int ast_mmap(struct file *filp, struct vm_area_struct *vma) | ||
443 | { | ||
444 | struct drm_file *file_priv; | ||
445 | struct ast_private *ast; | ||
446 | |||
447 | if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) | ||
448 | return drm_mmap(filp, vma); | ||
449 | |||
450 | file_priv = filp->private_data; | ||
451 | ast = file_priv->minor->dev->dev_private; | ||
452 | return ttm_bo_mmap(filp, vma, &ast->ttm.bdev); | ||
453 | } | ||