Commit | Line | Data |
---|---|---|
0a6659bd GH |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify | |
3 | * it under the terms of the GNU General Public License as published by | |
4 | * the Free Software Foundation; either version 2 of the License, or | |
5 | * (at your option) any later version. | |
6 | */ | |
7 | ||
8 | #include "bochs.h" | |
9 | ||
10 | /* ---------------------------------------------------------------------- */ | |
11 | ||
12 | static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val) | |
13 | { | |
14 | if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df)) | |
15 | return; | |
16 | ||
17 | if (bochs->mmio) { | |
18 | int offset = ioport - 0x3c0 + 0x400; | |
19 | writeb(val, bochs->mmio + offset); | |
20 | } else { | |
21 | outb(val, ioport); | |
22 | } | |
23 | } | |
24 | ||
25 | static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg) | |
26 | { | |
27 | u16 ret = 0; | |
28 | ||
29 | if (bochs->mmio) { | |
30 | int offset = 0x500 + (reg << 1); | |
31 | ret = readw(bochs->mmio + offset); | |
32 | } else { | |
33 | outw(reg, VBE_DISPI_IOPORT_INDEX); | |
34 | ret = inw(VBE_DISPI_IOPORT_DATA); | |
35 | } | |
36 | return ret; | |
37 | } | |
38 | ||
39 | static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val) | |
40 | { | |
41 | if (bochs->mmio) { | |
42 | int offset = 0x500 + (reg << 1); | |
43 | writew(val, bochs->mmio + offset); | |
44 | } else { | |
45 | outw(reg, VBE_DISPI_IOPORT_INDEX); | |
46 | outw(val, VBE_DISPI_IOPORT_DATA); | |
47 | } | |
48 | } | |
49 | ||
50 | int bochs_hw_init(struct drm_device *dev, uint32_t flags) | |
51 | { | |
52 | struct bochs_device *bochs = dev->dev_private; | |
53 | struct pci_dev *pdev = dev->pdev; | |
54 | unsigned long addr, size, mem, ioaddr, iosize; | |
55 | u16 id; | |
56 | ||
57 | if (/* (ent->driver_data == BOCHS_QEMU_STDVGA) && */ | |
58 | (pdev->resource[2].flags & IORESOURCE_MEM)) { | |
59 | /* mmio bar with vga and bochs registers present */ | |
60 | if (pci_request_region(pdev, 2, "bochs-drm") != 0) { | |
61 | DRM_ERROR("Cannot request mmio region\n"); | |
62 | return -EBUSY; | |
63 | } | |
64 | ioaddr = pci_resource_start(pdev, 2); | |
65 | iosize = pci_resource_len(pdev, 2); | |
66 | bochs->mmio = ioremap(ioaddr, iosize); | |
67 | if (bochs->mmio == NULL) { | |
68 | DRM_ERROR("Cannot map mmio region\n"); | |
69 | return -ENOMEM; | |
70 | } | |
71 | } else { | |
72 | ioaddr = VBE_DISPI_IOPORT_INDEX; | |
73 | iosize = 2; | |
74 | if (!request_region(ioaddr, iosize, "bochs-drm")) { | |
75 | DRM_ERROR("Cannot request ioports\n"); | |
76 | return -EBUSY; | |
77 | } | |
78 | bochs->ioports = 1; | |
79 | } | |
80 | ||
81 | id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID); | |
82 | mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K) | |
83 | * 64 * 1024; | |
84 | if ((id & 0xfff0) != VBE_DISPI_ID0) { | |
85 | DRM_ERROR("ID mismatch\n"); | |
86 | return -ENODEV; | |
87 | } | |
88 | ||
89 | if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0) | |
90 | return -ENODEV; | |
91 | addr = pci_resource_start(pdev, 0); | |
92 | size = pci_resource_len(pdev, 0); | |
93 | if (addr == 0) | |
94 | return -ENODEV; | |
95 | if (size != mem) { | |
96 | DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n", | |
97 | size, mem); | |
98 | size = min(size, mem); | |
99 | } | |
100 | ||
101 | if (pci_request_region(pdev, 0, "bochs-drm") != 0) { | |
102 | DRM_ERROR("Cannot request framebuffer\n"); | |
103 | return -EBUSY; | |
104 | } | |
105 | ||
106 | bochs->fb_map = ioremap(addr, size); | |
107 | if (bochs->fb_map == NULL) { | |
108 | DRM_ERROR("Cannot map framebuffer\n"); | |
109 | return -ENOMEM; | |
110 | } | |
111 | bochs->fb_base = addr; | |
112 | bochs->fb_size = size; | |
113 | ||
114 | DRM_INFO("Found bochs VGA, ID 0x%x.\n", id); | |
115 | DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n", | |
116 | size / 1024, addr, | |
117 | bochs->ioports ? "ioports" : "mmio", | |
118 | ioaddr); | |
119 | return 0; | |
120 | } | |
121 | ||
122 | void bochs_hw_fini(struct drm_device *dev) | |
123 | { | |
124 | struct bochs_device *bochs = dev->dev_private; | |
125 | ||
126 | if (bochs->mmio) | |
127 | iounmap(bochs->mmio); | |
128 | if (bochs->ioports) | |
129 | release_region(VBE_DISPI_IOPORT_INDEX, 2); | |
130 | if (bochs->fb_map) | |
131 | iounmap(bochs->fb_map); | |
132 | pci_release_regions(dev->pdev); | |
133 | } | |
134 | ||
135 | void bochs_hw_setmode(struct bochs_device *bochs, | |
136 | struct drm_display_mode *mode) | |
137 | { | |
138 | bochs->xres = mode->hdisplay; | |
139 | bochs->yres = mode->vdisplay; | |
140 | bochs->bpp = 32; | |
141 | bochs->stride = mode->hdisplay * (bochs->bpp / 8); | |
142 | bochs->yres_virtual = bochs->fb_size / bochs->stride; | |
143 | ||
144 | DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n", | |
145 | bochs->xres, bochs->yres, bochs->bpp, | |
146 | bochs->yres_virtual); | |
147 | ||
148 | bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ | |
149 | ||
150 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp); | |
151 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, bochs->xres); | |
152 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, bochs->yres); | |
153 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK, 0); | |
154 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, bochs->xres); | |
155 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT, | |
156 | bochs->yres_virtual); | |
157 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, 0); | |
158 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, 0); | |
159 | ||
160 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, | |
161 | VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); | |
162 | } | |
163 | ||
164 | void bochs_hw_setbase(struct bochs_device *bochs, | |
165 | int x, int y, u64 addr) | |
166 | { | |
167 | unsigned long offset = (unsigned long)addr + | |
168 | y * bochs->stride + | |
169 | x * (bochs->bpp / 8); | |
170 | int vy = offset / bochs->stride; | |
171 | int vx = (offset % bochs->stride) * 8 / bochs->bpp; | |
172 | ||
173 | DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n", | |
174 | x, y, addr, offset, vx, vy); | |
175 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx); | |
176 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy); | |
177 | } |