summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/radeon_combios.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c
index bb8d0b27..56116463 100644
--- a/linux-core/radeon_combios.c
+++ b/linux-core/radeon_combios.c
@@ -1016,3 +1016,258 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
return true;
}
+static void combios_parse_mmio_table(struct drm_device *dev, uint16_t offset)
+{
+ struct drm_radeon_private *dev_priv = dev->dev_private;
+
+ if (offset) {
+ while (radeon_bios16(dev_priv, offset)) {
+ uint16_t cmd = ((radeon_bios16(dev_priv, offset) & 0xe000) >> 13);
+ uint32_t addr = (radeon_bios16(dev_priv, offset) & 0x1fff);
+ uint32_t val, and_mask, or_mask;
+ uint32_t tmp;
+
+ offset += 2;
+ switch (cmd) {
+ case 0:
+ val = radeon_bios32(dev_priv, offset);
+ offset += 4;
+ RADEON_WRITE(addr, val);
+ break;
+ case 1:
+ val = radeon_bios32(dev_priv, offset);
+ offset += 4;
+ RADEON_WRITE(addr, val);
+ break;
+ case 2:
+ and_mask = radeon_bios32(dev_priv, offset);
+ offset += 4;
+ or_mask = radeon_bios32(dev_priv, offset);
+ offset += 4;
+ tmp = RADEON_READ(addr);
+ tmp &= and_mask;
+ tmp |= or_mask;
+ RADEON_WRITE(addr, tmp);
+ break;
+ case 3:
+ and_mask = radeon_bios32(dev_priv, offset);
+ offset += 4;
+ or_mask = radeon_bios32(dev_priv, offset);
+ offset += 4;
+ tmp = RADEON_READ(addr);
+ tmp &= and_mask;
+ tmp |= or_mask;
+ RADEON_WRITE(addr, tmp);
+ break;
+ case 4:
+ val = radeon_bios16(dev_priv, offset);
+ offset += 2;
+ udelay(val);
+ break;
+ case 5:
+ val = radeon_bios16(dev_priv, offset);
+ offset += 2;
+ switch (addr) {
+ case 8:
+ while (val--) {
+ if (!(RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL) &
+ RADEON_MC_BUSY))
+ break;
+ }
+ break;
+ case 9:
+ while (val--) {
+ if ((RADEON_READ(RADEON_MC_STATUS) &
+ RADEON_MC_IDLE))
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset)
+{
+ struct drm_radeon_private *dev_priv = dev->dev_private;
+
+ if (offset) {
+ while (radeon_bios8(dev_priv, offset)) {
+ uint8_t cmd = ((radeon_bios8(dev_priv, offset) & 0xc0) >> 6);
+ uint8_t addr = (radeon_bios8(dev_priv, offset) & 0x3f);
+ uint32_t val, shift, tmp;
+ uint32_t and_mask, or_mask;
+
+ offset++;
+ switch (cmd) {
+ case 0:
+ val = radeon_bios32(dev_priv, offset);
+ offset += 4;
+ RADEON_WRITE_PLL(dev_priv, addr, val);
+ break;
+ case 1:
+ shift = radeon_bios8(dev_priv, offset) * 8;
+ offset++;
+ and_mask = radeon_bios8(dev_priv, offset) << shift;
+ and_mask |= ~(0xff << shift);
+ offset++;
+ or_mask = radeon_bios8(dev_priv, offset) << shift;
+ offset++;
+ tmp = RADEON_READ_PLL(dev_priv, addr);
+ tmp &= and_mask;
+ tmp |= or_mask;
+ RADEON_WRITE_PLL(dev_priv, addr, tmp);
+ break;
+ case 2:
+ case 3:
+ tmp = 1000;
+ switch (addr) {
+ case 1:
+ udelay(150);
+ break;
+ case 2:
+ udelay(1000);
+ break;
+ case 3:
+ while (tmp--) {
+ if (!(RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL) &
+ RADEON_MC_BUSY))
+ break;
+ }
+ break;
+ case 4:
+ while (tmp--) {
+ if (RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL) &
+ RADEON_DLL_READY)
+ break;
+ }
+ break;
+ case 5:
+ tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL);
+ if (tmp & RADEON_CG_NO1_DEBUG_0) {
+#if 0
+ uint32_t mclk_cntl = RADEON_READ_PLL(RADEON_MCLK_CNTL);
+ mclk_cntl &= 0xffff0000;
+ //mclk_cntl |= 0x00001111; /* ??? */
+ RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, mclk_cntl);
+ udelay(10000);
+#endif
+ RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL,
+ tmp & ~RADEON_CG_NO1_DEBUG_0);
+ udelay(10000);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static void combios_parse_ram_reset_table(struct drm_device *dev, uint16_t offset)
+{
+ struct drm_radeon_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
+ if (offset) {
+ uint8_t val = radeon_bios8(dev_priv, offset);
+ while (val != 0xff) {
+ offset++;
+
+ if (val == 0x0f) {
+ uint32_t channel_complete_mask;
+
+ if (radeon_is_r300(dev_priv))
+ channel_complete_mask = R300_MEM_PWRUP_COMPLETE;
+ else
+ channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE;
+ tmp = 20000;
+ while (tmp--) {
+ if ((RADEON_READ(RADEON_MEM_STR_CNTL) &
+ channel_complete_mask) ==
+ channel_complete_mask)
+ break;
+ }
+ } else {
+ uint32_t or_mask = radeon_bios16(dev_priv, offset);
+ offset += 2;
+
+ tmp = RADEON_READ(RADEON_MEM_SDRAM_MODE_REG);
+ tmp &= RADEON_SDRAM_MODE_MASK;
+ tmp |= or_mask;
+ RADEON_WRITE(RADEON_MEM_SDRAM_MODE_REG, tmp);
+
+ or_mask = val << 24;
+ tmp = RADEON_READ(RADEON_MEM_SDRAM_MODE_REG);
+ tmp &= RADEON_B3MEM_RESET_MASK;
+ tmp |= or_mask;
+ RADEON_WRITE(RADEON_MEM_SDRAM_MODE_REG, tmp);
+ }
+ val = radeon_bios8(dev_priv, offset);
+ }
+ }
+}
+
+void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable)
+{
+ uint16_t dyn_clk_info = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
+
+ if (dyn_clk_info)
+ combios_parse_pll_table(dev, dyn_clk_info);
+}
+
+void radeon_combios_asic_init(struct drm_device *dev)
+{
+ uint16_t table;
+
+ /* ASIC INIT 1 */
+ table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_1_TABLE);
+ if (table)
+ combios_parse_mmio_table(dev, table);
+
+ /* PLL INIT */
+ table = combios_get_table_offset(dev, COMBIOS_PLL_INIT_TABLE);
+ if (table)
+ combios_parse_pll_table(dev, table);
+
+ /* ASIC INIT 2 */
+ table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_2_TABLE);
+ if (table)
+ combios_parse_mmio_table(dev, table);
+
+ /* ASIC INIT 4 */
+ table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_4_TABLE);
+ if (table)
+ combios_parse_mmio_table(dev, table);
+
+ /* RAM RESET */
+ table = combios_get_table_offset(dev, COMBIOS_RAM_RESET_TABLE);
+ if (table)
+ combios_parse_ram_reset_table(dev, table);
+
+ /* ASIC INIT 3 */
+ table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_3_TABLE);
+ if (table)
+ combios_parse_mmio_table(dev, table);
+
+ /* DYN CLK 1 */
+ table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
+ if (table)
+ combios_parse_pll_table(dev, table);
+
+ /* ASIC INIT 5 */
+ table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_5_TABLE);
+ if (table)
+ combios_parse_mmio_table(dev, table);
+
+}