1 /* SPDX-License-Identifier: MIT */
3 * Copied from Linux drivers/gpu/drm/ast/ast_mode.c
6 #include <console/console.h>
8 #include <device/pci_def.h>
9 #include <framebuffer_info.h>
14 * Set framebuffer MMIO address, which must fall into BAR0 MMIO window.
16 * Complete reimplementation as the original expects multiple kernel internal
17 * subsystems to be present.
19 int ast_crtc_do_set_base(struct drm_crtc
*crtc
)
21 struct ast_private
*ast
= crtc
->dev
->dev_private
;
22 struct drm_framebuffer
*fb
= crtc
->primary
->fb
;
25 struct resource
*res
= probe_resource(crtc
->dev
->pdev
, PCI_BASE_ADDRESS_0
);
27 printk(BIOS_ERR
, "BAR0 resource not found.\n");
31 if (res
->size
< fb
->pitches
[0] * crtc
->mode
.vdisplay
) {
32 dev_err(dev
->pdev
, "Framebuffer doesn't fit into BAR0 MMIO window\n");
36 fb
->mmio_addr
= (uintptr_t)res2mmio(res
, 4095, 4095);
38 ast_set_offset_reg(crtc
);
39 ast_set_start_address_crt1(ast
, fb
->mmio_addr
);
44 static void ast_edid_to_drmmode(struct edid
*edid
, struct drm_display_mode
*mode
)
46 memset(mode
, 0, sizeof(*mode
));
48 mode
->hdisplay
= edid
->mode
.ha
;
49 mode
->vdisplay
= edid
->mode
.va
;
50 mode
->crtc_hdisplay
= edid
->mode
.ha
;
51 mode
->crtc_vdisplay
= edid
->mode
.va
;
53 /* EDID clock is in 10kHz, but drm clock is in KHz */
54 mode
->clock
= edid
->mode
.pixel_clock
* 10;
55 mode
->vrefresh
= edid
->mode
.refresh
;
57 mode
->crtc_hblank_start
= edid
->mode
.ha
;
58 mode
->crtc_hblank_end
= edid
->mode
.ha
+ edid
->mode
.hbl
;
59 mode
->crtc_hsync_start
= edid
->mode
.ha
+ edid
->mode
.hso
;
60 mode
->crtc_hsync_end
= edid
->mode
.ha
+ edid
->mode
.hso
+ edid
->mode
.hspw
;
61 mode
->crtc_htotal
= mode
->crtc_hblank_end
;
63 mode
->crtc_vblank_start
= edid
->mode
.va
;
64 mode
->crtc_vblank_end
= edid
->mode
.va
+ edid
->mode
.vbl
;
65 mode
->crtc_vsync_start
= edid
->mode
.va
+ edid
->mode
.vso
;
66 mode
->crtc_vsync_end
= edid
->mode
.va
+ edid
->mode
.vso
+ edid
->mode
.vspw
;
67 mode
->crtc_vtotal
= mode
->crtc_vblank_end
;
70 if (edid
->mode
.phsync
== '+')
71 mode
->flags
|= DRM_MODE_FLAG_PHSYNC
;
73 mode
->flags
|= DRM_MODE_FLAG_NHSYNC
;
75 if (edid
->mode
.pvsync
== '+')
76 mode
->flags
|= DRM_MODE_FLAG_PVSYNC
;
78 mode
->flags
|= DRM_MODE_FLAG_NVSYNC
;
81 static int ast_select_mode(struct drm_connector
*connector
,
84 struct ast_private
*ast
= connector
->dev
->dev_private
;
89 if (ast
->tx_chip_type
== AST_TX_DP501
) {
90 ast
->dp501_maxclk
= 0xff;
91 flags
= ast_dp501_read_edid(connector
->dev
, (u8
*)raw
);
93 ast
->dp501_maxclk
= ast_get_dp501_max_clk(connector
->dev
);
95 dev_err(dev
->pdev
, "I2C transmission error\n");
99 ast_software_i2c_read(ast
, raw
);
101 if (decode_edid(raw
, sizeof(raw
), edid
) != EDID_CONFORMANT
) {
103 * Servers often run headless, so a missing EDID is not an error.
104 * We still need to initialize a framebuffer for KVM, though.
106 dev_info(dev
->pdev
, "Failed to decode EDID\n");
107 printk(BIOS_DEBUG
, "Assuming VGA for KVM\n");
109 memset(edid
, 0, sizeof(*edid
));
111 edid
->mode
.pixel_clock
= 6411;
112 edid
->mode
.refresh
= 60;
113 edid
->mode
.ha
= 1024;
116 edid
->mode
.hbl
= 264;
117 edid
->mode
.phsync
= '-';
123 edid
->mode
.pvsync
= '+';
126 printk(BIOS_DEBUG
, "AST: Display has %dpx x %dpx\n", edid
->mode
.ha
, edid
->mode
.va
);
128 widescreen
= !!(((edid
->mode
.ha
* 4) % (edid
->mode
.va
* 3)));
130 while (ast_mode_valid(connector
, edid
->mode
.ha
, edid
->mode
.va
) != MODE_OK
) {
131 /* Select a compatible smaller mode */
132 if (edid
->mode
.ha
> 1920 && widescreen
) {
133 edid
->mode
.ha
= 1920;
134 edid
->mode
.va
= 1080;
135 } else if (edid
->mode
.ha
>= 1920 && widescreen
) {
136 edid
->mode
.ha
= 1680;
137 edid
->mode
.va
= 1050;
138 } else if (edid
->mode
.ha
>= 1680 && widescreen
) {
139 edid
->mode
.ha
= 1600;
141 } else if (edid
->mode
.ha
>= 1680 && !widescreen
) {
142 edid
->mode
.ha
= 1600;
143 edid
->mode
.va
= 1200;
144 } else if (edid
->mode
.ha
>= 1600 && widescreen
) {
145 edid
->mode
.ha
= 1440;
147 } else if (edid
->mode
.ha
>= 1440 && widescreen
) {
148 edid
->mode
.ha
= 1360;
150 } else if (edid
->mode
.ha
>= 1360 && widescreen
) {
151 edid
->mode
.ha
= 1280;
153 } else if (edid
->mode
.ha
>= 1360 && !widescreen
) {
154 edid
->mode
.ha
= 1280;
155 edid
->mode
.va
= 1024;
156 } else if (edid
->mode
.ha
>= 1280) {
157 edid
->mode
.ha
= 1024;
159 } else if (edid
->mode
.ha
>= 1024) {
162 } else if (edid
->mode
.ha
>= 800) {
166 dev_err(dev
->pdev
, "No compatible mode found.\n");
175 int ast_driver_framebuffer_init(struct drm_device
*dev
, int flags
)
177 struct drm_display_mode adjusted_mode
;
178 struct drm_crtc crtc
;
179 struct drm_format format
;
180 struct drm_primary primary
;
181 struct drm_framebuffer fb
;
182 struct drm_connector connector
;
186 /* Init wrapper structs */
189 format
.cpp
[0] = 4; /* 32 BPP */
195 crtc
.primary
= &primary
;
197 /* Read EDID and find mode */
198 ret
= ast_select_mode(&connector
, &edid
);
200 dev_err(dev
->pdev
, "Failed to select mode.\n");
204 /* Updated edid for fb_fill_framebuffer_info */
205 edid
.x_resolution
= edid
.mode
.ha
;
206 edid
.y_resolution
= edid
.mode
.va
;
207 edid
.framebuffer_bits_per_pixel
= format
.cpp
[0] * 8;
208 edid
.bytes_per_line
= ALIGN_UP(edid
.x_resolution
* format
.cpp
[0], 8);
210 /* Updated framebuffer info for ast_crtc_mode_set */
211 fb
.pitches
[0] = edid
.bytes_per_line
;
213 printk(BIOS_DEBUG
, "Using framebuffer %dpx x %dpx pitch %d @ %d BPP\n",
214 edid
.x_resolution
, edid
.y_resolution
, edid
.bytes_per_line
,
215 edid
.framebuffer_bits_per_pixel
);
217 /* Convert EDID to AST DRM mode */
218 ast_edid_to_drmmode(&edid
, &crtc
.mode
);
220 memcpy(&adjusted_mode
, &crtc
.mode
, sizeof(crtc
.mode
));
222 ret
= ast_crtc_mode_set(&crtc
, &crtc
.mode
, &adjusted_mode
);
224 dev_err(dev
->pdev
, "Failed to set mode.\n");
228 ast_hide_cursor(&crtc
);
230 /* Advertise new mode */
231 fb_new_framebuffer_info_from_edid(&edid
, fb
.mmio_addr
);
234 memset((void *)(uintptr_t)fb
.mmio_addr
, 0, edid
.bytes_per_line
* edid
.y_resolution
);