--- /dev/null
+From cef1d00cd56f600121ad121875655ad410a001b8 Mon Sep 17 00:00:00 2001
+From: Mark Kettenis <kettenis@openbsd.org>
+Date: Sun, 21 Jul 2013 16:44:09 -0400
+Subject: drm/radeon: fix combios tables on older cards
+
+From: Mark Kettenis <kettenis@openbsd.org>
+
+commit cef1d00cd56f600121ad121875655ad410a001b8 upstream.
+
+Noticed that my old Radeon 7500 hung after printing
+
+ drm: GPU not posted. posting now...
+
+when it wasn't selected as the primary card the BIOS. Some digging
+revealed that it was hanging in combios_parse_mmio_table() while
+parsing the ASIC INIT 3 table. Looking at the BIOS ROM for the card,
+it becomes obvious that there is no ASIC INIT 3 table in the BIOS.
+The code is just processing random garbage. No surprise it hangs!
+
+Why do I say that there is no ASIC INIT 3 table is the BIOS? This
+table is found through the MISC INFO table. The MISC INFO table can
+be found at offset 0x5e in the COMBIOS header. But the header is
+smaller than that. The COMBIOS header starts at offset 0x126. The
+standard PCI Data Structure (the bit that starts with 'PCIR') lives at
+offset 0x180. That means that the COMBIOS header can not be larger
+than 0x5a bytes and therefore cannot contain a MISC INFO table.
+
+I looked at a dozen or so BIOS images, some my own, some downloaded from:
+
+ <http://www.techpowerup.com/vgabios/index.php?manufacturer=ATI&page=1>
+
+It is fairly obvious that the size of the COMBIOS header can be found
+at offset 0x6 of the header. Not sure if it is a 16-bit number or
+just an 8-bit number, but that doesn't really matter since the tables
+seems to be always smaller than 256 bytes.
+
+So I think combios_get_table_offset() should check if the requested
+table is present. This can be done by checking the offset against the
+size of the header. See the diff below. The diff is against the WIP
+OpenBSD codebase that roughly corresponds to Linux 3.8.13 at this
+point. But I don't think this bit of the code changed much since
+then.
+
+For what it is worth:
+
+Signed-off-by: Mark Kettenis <kettenis@openbsd.org>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/radeon/radeon_combios.c | 145 +++++++++-----------------------
+ 1 file changed, 41 insertions(+), 104 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/radeon_combios.c
++++ b/drivers/gpu/drm/radeon/radeon_combios.c
+@@ -147,7 +147,7 @@ static uint16_t combios_get_table_offset
+ enum radeon_combios_table_offset table)
+ {
+ struct radeon_device *rdev = dev->dev_private;
+- int rev;
++ int rev, size;
+ uint16_t offset = 0, check_offset;
+
+ if (!rdev->bios)
+@@ -156,174 +156,106 @@ static uint16_t combios_get_table_offset
+ switch (table) {
+ /* absolute offset tables */
+ case COMBIOS_ASIC_INIT_1_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0xc);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0xc;
+ break;
+ case COMBIOS_BIOS_SUPPORT_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x14);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x14;
+ break;
+ case COMBIOS_DAC_PROGRAMMING_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x2a);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x2a;
+ break;
+ case COMBIOS_MAX_COLOR_DEPTH_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x2c);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x2c;
+ break;
+ case COMBIOS_CRTC_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x2e);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x2e;
+ break;
+ case COMBIOS_PLL_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x30);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x30;
+ break;
+ case COMBIOS_TV_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x32);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x32;
+ break;
+ case COMBIOS_DFP_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x34);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x34;
+ break;
+ case COMBIOS_HW_CONFIG_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x36);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x36;
+ break;
+ case COMBIOS_MULTIMEDIA_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x38);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x38;
+ break;
+ case COMBIOS_TV_STD_PATCH_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x3e);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x3e;
+ break;
+ case COMBIOS_LCD_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x40);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x40;
+ break;
+ case COMBIOS_MOBILE_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x42);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x42;
+ break;
+ case COMBIOS_PLL_INIT_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x46);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x46;
+ break;
+ case COMBIOS_MEM_CONFIG_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x48);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x48;
+ break;
+ case COMBIOS_SAVE_MASK_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x4a);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x4a;
+ break;
+ case COMBIOS_HARDCODED_EDID_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x4c);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x4c;
+ break;
+ case COMBIOS_ASIC_INIT_2_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x4e);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x4e;
+ break;
+ case COMBIOS_CONNECTOR_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x50);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x50;
+ break;
+ case COMBIOS_DYN_CLK_1_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x52);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x52;
+ break;
+ case COMBIOS_RESERVED_MEM_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x54);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x54;
+ break;
+ case COMBIOS_EXT_TMDS_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x58);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x58;
+ break;
+ case COMBIOS_MEM_CLK_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x5a);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x5a;
+ break;
+ case COMBIOS_EXT_DAC_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x5c);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x5c;
+ break;
+ case COMBIOS_MISC_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x5e);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x5e;
+ break;
+ case COMBIOS_CRT_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x60);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x60;
+ break;
+ case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x62);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x62;
+ break;
+ case COMBIOS_COMPONENT_VIDEO_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x64);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x64;
+ break;
+ case COMBIOS_FAN_SPEED_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x66);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x66;
+ break;
+ case COMBIOS_OVERDRIVE_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x68);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x68;
+ break;
+ case COMBIOS_OEM_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x6a);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x6a;
+ break;
+ case COMBIOS_DYN_CLK_2_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x6c);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x6c;
+ break;
+ case COMBIOS_POWER_CONNECTOR_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x6e);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x6e;
+ break;
+ case COMBIOS_I2C_INFO_TABLE:
+- check_offset = RBIOS16(rdev->bios_header_start + 0x70);
+- if (check_offset)
+- offset = check_offset;
++ check_offset = 0x70;
+ break;
+ /* relative offset tables */
+ case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */
+@@ -439,11 +371,16 @@ static uint16_t combios_get_table_offset
+ }
+ break;
+ default:
++ check_offset = 0;
+ break;
+ }
+
+- return offset;
++ size = RBIOS8(rdev->bios_header_start + 0x6);
++ /* check absolute offset tables */
++ if (table < COMBIOS_ASIC_INIT_3_TABLE && check_offset && check_offset < size)
++ offset = RBIOS16(rdev->bios_header_start + check_offset);
+
++ return offset;
+ }
+
+ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
--- /dev/null
+From 34be8c9af7b8728465963740fc11136ae90dfc36 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexander.deucher@amd.com>
+Date: Thu, 18 Jul 2013 11:13:53 -0400
+Subject: drm/radeon: fix endian issues with DP handling (v3)
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+commit 34be8c9af7b8728465963740fc11136ae90dfc36 upstream.
+
+The atom interpreter expects data in LE format, so
+swap the message buffer as apprioriate.
+
+v2: properly handle non-dw aligned byte counts.
+v3: properly handle remainder
+
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: Dong He <hedonghust@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/radeon/atombios_dp.c | 43 +++++++++++++++++++++++++++++++----
+ 1 file changed, 39 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/atombios_dp.c
++++ b/drivers/gpu/drm/radeon/atombios_dp.c
+@@ -45,6 +45,41 @@ static char *pre_emph_names[] = {
+ };
+
+ /***** radeon AUX functions *****/
++
++/* Atom needs data in little endian format
++ * so swap as appropriate when copying data to
++ * or from atom. Note that atom operates on
++ * dw units.
++ */
++static void radeon_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
++{
++#ifdef __BIG_ENDIAN
++ u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
++ u32 *dst32, *src32;
++ int i;
++
++ memcpy(src_tmp, src, num_bytes);
++ src32 = (u32 *)src_tmp;
++ dst32 = (u32 *)dst_tmp;
++ if (to_le) {
++ for (i = 0; i < ((num_bytes + 3) / 4); i++)
++ dst32[i] = cpu_to_le32(src32[i]);
++ memcpy(dst, dst_tmp, num_bytes);
++ } else {
++ u8 dws = num_bytes & ~3;
++ for (i = 0; i < ((num_bytes + 3) / 4); i++)
++ dst32[i] = le32_to_cpu(src32[i]);
++ memcpy(dst, dst_tmp, dws);
++ if (num_bytes % 4) {
++ for (i = 0; i < (num_bytes % 4); i++)
++ dst[dws+i] = dst_tmp[dws+i];
++ }
++ }
++#else
++ memcpy(dst, src, num_bytes);
++#endif
++}
++
+ union aux_channel_transaction {
+ PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
+ PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
+@@ -66,10 +101,10 @@ static int radeon_process_aux_ch(struct
+
+ base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
+
+- memcpy(base, send, send_bytes);
++ radeon_copy_swap(base, send, send_bytes, true);
+
+- args.v1.lpAuxRequest = 0 + 4;
+- args.v1.lpDataOut = 16 + 4;
++ args.v1.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
++ args.v1.lpDataOut = cpu_to_le16((u16)(16 + 4));
+ args.v1.ucDataOutLen = 0;
+ args.v1.ucChannelID = chan->rec.i2c_id;
+ args.v1.ucDelay = delay / 10;
+@@ -103,7 +138,7 @@ static int radeon_process_aux_ch(struct
+ recv_bytes = recv_size;
+
+ if (recv && recv_size)
+- memcpy(recv, base + 16, recv_bytes);
++ radeon_copy_swap(recv, base + 16, recv_bytes, false);
+
+ return recv_bytes;
+ }