Skip to contentSkip to conversation

radeon drm-next patches

PATCH In review [email protected] 10 participants 142 messages Jun 26, 2013 – Jun 29, 2013 Page 1 of 3

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover radeon drm-next patches

From: Alex Deucher <[email protected]>

These are the radeon patches for 3.11. Some of these patches are huge so, it might be easier to review things here:
http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip

I'll send a formal pull in request in the next day or two.

Highlights of this series:
- DPM support (Dynamic Power Management) for r6xx-SI
- Support for CIK (Sea Islands): modesetting, 3D, compute, UVD
- ASPM support for R6xx-SI

Since this is the initial public DPM code, it's still disabled by default until we get more community testing. Pass dpm=1 to the radeon module to enable it.

Alex Deucher (164):
drm/radeon: fix AVI infoframe generation
drm/radeon: add backlight quirk for hybrid mac drm/radeon: add a reset work handler
drm/radeon: add CIK chip families
drm/radeon: add DCE8 macro for CIK
drm/radeon: adapt to PCI BAR changes on CIK drm/radeon: add gpu init support for CIK (v9) drm/radeon: Add support for CIK GPU reset (v2) drm/radeon: add support for MC/VM setup on CIK (v6) drm/radeon/cik: stop page faults from hanging the system (v2) drm/radeon: add initial ucode loading for CIK (v5) drm/radeon: add support mc ucode loading on CIK (v2) drm/radeon: Add CP init for CIK (v7)
drm/radeon: add IB and fence dispatch functions for CIK gfx (v7) drm/radeon: add ring and IB tests for CIK (v3) drm/radeon: implement async vm_flush for the CP (v7) drm/radeon: Add support for RLC init on CIK (v4) drm/radeon: add support for interrupts on CIK (v5) drm/radeon/cik: log and handle VM page fault interrupts drm/radeon/cik: add support for sDMA dma engines (v8) drm/radeon: implement async vm_flush for the sDMA (v6) drm/radeon/cik: add support for doing async VM pt updates (v5) drm/radeon/cik: fill in startup/shutdown callbacks (v4) drm/radeon: upstream ObjectID.h updates (v2) drm/radeon: upstream atombios.h updates (v2) drm/radeon: atombios power table updates (v2) drm/radeon: handle the integrated thermal controller on CI drm/radeon: update power state parsing for CI drm/radeon/dce8: add support for display watermark setup drm/radeon/cik: add hw cursor support (v2) drm/radeon/dce8: properly handle interlaced timing drm/radeon/dce8: crtc_set_base updates drm/radeon/atom: add DCE8 encoder support drm/radeon/atom: add support for new DVO tables drm/radeon: update DISPCLK programming for DCE8 drm/radeon: add support pll selection for DCE8 (v4) drm/radeon: Handle PPLL0 powerdown on DCE8
drm/radeon: use frac fb div on DCE8
drm/radeon: add SS override support for KB/KV drm/radeon: Update radeon_info_ioctl for CIK (v2) drm/radeon: add get_gpu_clock_counter() callback for cik drm/radeon: update CIK soft reset
drm/radeon: add indirect register accessors for SMC registers drm/radeon: add get_xclk() callback for CIK drm/radeon/cik: add pcie_port indirect register accessors drm/radeon: update radeon_atom_get_clock_dividers() for SI drm/radeon: update radeon_atom_get_clock_dividers for CIK drm/radeon/cik: add srbm_select function
drm/radeon: use callbacks for ring pointer handling drm/radeon: implement simple doorbell page allocator drm/radeon/cik: Add support for compute queues (v2) drm/radeon/cik: switch to type3 nop packet for compute rings drm/radeon: fix up ring functions for compute rings drm/radeon/cik: add support for compute interrupts drm/radeon/cik: add support for golden register init drm/radeon: add radeon_asic struct for CIK (v11) drm/radeon: add cik tile mode array query
drm/radeon: add current Bonaire PCI ids
drm/radeon: add current KB pci ids
drm/radeon/kms: add accessors for RCU indirect space drm/radeon/evergreen: add indirect register accessors for CG
registers
drm/radeon: make get_temperature functions a callback drm/radeon: add support for thermal sensor on tn drm/radeon/kms: move ucode defines to a separate header drm/radeon: properly set up the RLC on ON/LN/TN (v3) drm/radeon/kms: add atom helper functions for dpm (v3) drm/radeon/kms: add new asic struct for rv6xx (v3) drm/radeon/kms: add common dpm infrastructure drm/radeon/kms: fix up rs780/rs880 display watermark calc for dpm drm/radeon/kms: fix up 6xx/7xx display watermark calc for dpm drm/radeon/kms: fix up dce4/5 display watermark calc for dpm drm/radeon/kms: fix up dce6 display watermark calc for dpm drm/radeon/kms: add common r600 dpm functions drm/radeon/kms: add dpm support for rs780/rs880 drm/radeon/kms: add dpm support for rv6xx drm/radeon/kms: add dpm support for rv7xx (v2) drm/radeon/kms: add dpm support for evergreen (v2) drm/radeon/kms: add dpm support for btc (v2) drm/radeon/kms: add dpm support for sumo asics drm/radeon/kms: add dpm support for trinity asics drm/radeon/dpm: let atom control display phy powergating drm/radeon: add dpm UVD handling for r7xx asics drm/radeon: add dpm UVD handling for evergreen/btc asics drm/radeon: add dpm UVD handling for sumo asics drm/radeon: add dpm UVD handling for TN asics (v2) drm/radeon/kms: enable UVD as needed (v9) drm/radeon/dpm: add helpers for extended power tables (v2) drm/radeon/dpm: track whether we are on AC or battery drm/radeon/dpm: fixup dynamic state adjust for sumo drm/radeon/dpm: fixup dynamic state adjust for TN drm/radeon/dpm: fixup dynamic state adjust for btc (v2) drm/radeon/kms: add dpm support for cayman drm/radeon/cayman: update tdp limits in set_power_state drm/radeon/dpm/rs780: restructure code drm/radeon/dpm/rv6xx: restructure code drm/radeon/dpm/rv7xx: restructure code drm/radeon/dpm/evergreen: restructure code drm/radeon/dpm/btc: restructure code drm/radeon/dpm/cayman: restructure code drm/radeon/dpm/sumo: restructure code drm/radeon/dpm/tn: restructure code
drm/radeon/dpm: add new pre/post_set_power_state callbacks drm/radeon/dpm: add pre/post_set_power_state callbacks (6xx-eg) drm/radeon/dpm: add pre/post_set_power_state callback (sumo) drm/radeon/dpm: add pre/post_set_power_state callback (TN) drm/radeon/dpm: add pre/post_set_power_state callback (BTC) drm/radeon/dpm: add pre/post_set_power_state callback (cayman) drm/radeon/dpm: remove broken dyn state remnants drm/radeon: add missing UVD clock set in cayman dpm code drm/radeon/dpm: remove local sumo_get_xclk() drm/radeon: implement apci perf request drm/radeon/atom: add helper to calcuate mpll params drm/radeon: update radeon_atom_is_voltage_gpio() for SI drm/radeon: update radeon_atom_get_voltage_table() for SI drm/radeon: implement pcie gen2/3 support for SI drm/radeon: add accessors of pif_phy indirect register space drm/radeon: add support for ASPM on evergreen asics drm/radeon: add support for ASPM on SI asics (v2) drm/radeon: enable additional power gating features on trinity drm/radeon: update rlc programming sequence on SI drm/radeon: add atom get leakage vddc function drm/radeon: add indirect accessors for UVD CTX registers drm/radeon: initialize save/restore buffer for pg on verde drm/radeon: add clearstate init for verde power gating drm/radeon: implement clock and power gating for SI drm/radeon/dpm: add an enum for pcie gen selection drm/radeon/dpm: pull in phase shedding limits from atom drm/radeon/dpm: endian fixes for extended power tables drm/radeon/dpm: pull in ppm info from atom drm/radeon/dpm: save some display parameters for DPM drm/radeon: minor sid.h cleanup
drm: add some additional fixed point helpers (v2) drm/radeon/dpm/cayman: use new fixed point functions drm/radeon: fix some memory leaks in extended table parsing drm/radeon/dpm: validate voltages against dispclk requirements drm/radeon: update radeon_atombios_get_default_voltages for mvdd drm/radeon/dpm: add pcie gen helper function drm/radeon: fix typo in atom voltage table handling (6xx-ni) drm/radeon: fix typo in atom voltage table handling (si+) drm/radeon/atom: fix voltage table parsing drm/radeon/dpm/ni: properly catch errors in dpm setup drm/radeon/dpm/btc: properly catch errors in dpm setup drm/radeon/dpm/evergreen: properly catch errors in dpm setup drm/radeon/dpm/sumo: properly catch errors in dpm setup drm/radeon/dpm/trinity: properly catch errors in dpm setup drm/radeon/dpm/r7xx: properly catch errors in dpm setup drm/radeon/dpm/r6xx: properly catch errors in dpm setup drm/radeon/dpm/rs780: properly catch errors in dpm setup drm/radeon: add SI to r600_is_internal_thermal_sensor() drm/radeon: switch SI to use radeon_ucode.h drm/radeon/kms: add dpm support for SI (v3) drm/radeon/dpm: add dpm_enable failure output (7xx-ni) drm/radeon/dpm: add dpm_enable failure output (si) drm/radeon/dpm: add dpm_set_power_state failure output (7xx-ni) drm/radeon/dpm: add dpm_set_power_state failure output (si) drm/radeon/dpm: fix typo in setting uvd clock drm/radeon/si: fix typo in function name
drm/radeon: fix typo in cik_select_se_sh()
drm/radeon: fix typo in ni_print_power_state drm/radeon/dpm: add support for setting UVD clock on rs780 drm/radeon/dpm: add support for setting UVD clock on rv6xx drm/radeon/dpm: fix UVD clock setting on cayman drm/radeon/dpm: fix UVD clock setting on SI drm/radeon: fix endian issues in atombios dpm code

Christian König (1):
drm/radeon: add UVD support for CIK (v3)

 drivers/gpu/drm/radeon/Makefile               |    5 +-
 drivers/gpu/drm/radeon/ObjectID.h             |   40 +
 drivers/gpu/drm/radeon/atombios.h             |  547 ++-
 drivers/gpu/drm/radeon/atombios_crtc.c        |   88 +-
 drivers/gpu/drm/radeon/atombios_encoders.c    |   51 +-
 drivers/gpu/drm/radeon/btc_dpm.c              | 2731 ++++++++++
 drivers/gpu/drm/radeon/btc_dpm.h              |   57 +
 drivers/gpu/drm/radeon/btcd.h                 |  181 +
 drivers/gpu/drm/radeon/cik.c                  | 6995 +++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cik_blit_shaders.c     |  246 +
 drivers/gpu/drm/radeon/cik_blit_shaders.h     |   32 +
 drivers/gpu/drm/radeon/cik_reg.h              |  147 +
 drivers/gpu/drm/radeon/cikd.h                 | 1297 +++++
 drivers/gpu/drm/radeon/clearstate_cayman.h    | 1081 ++++
 drivers/gpu/drm/radeon/clearstate_defs.h      |   44 +
 drivers/gpu/drm/radeon/clearstate_evergreen.h | 1080 ++++
 drivers/gpu/drm/radeon/clearstate_si.h        |  941 ++++
 drivers/gpu/drm/radeon/cypress_dpm.c          | 2170 ++++++++
 drivers/gpu/drm/radeon/cypress_dpm.h          |  160 +
 drivers/gpu/drm/radeon/evergreen.c            |  644 +++-
 drivers/gpu/drm/radeon/evergreen_hdmi.c       |   11 +-
 drivers/gpu/drm/radeon/evergreen_reg.h        |   12 +
 drivers/gpu/drm/radeon/evergreen_smc.h        |   67 +
 drivers/gpu/drm/radeon/evergreend.h           |  389 ++-
 drivers/gpu/drm/radeon/ni.c                   |  198 +-
 drivers/gpu/drm/radeon/ni_dpm.c               | 4288 +++++++++++++++
 drivers/gpu/drm/radeon/ni_dpm.h               |  248 +
 drivers/gpu/drm/radeon/nid.h                  |  561 ++
 drivers/gpu/drm/radeon/nislands_smc.h         |  329 ++
 drivers/gpu/drm/radeon/ppsmc.h                |  110 +
 drivers/gpu/drm/radeon/r600.c                 |  147 +-
 drivers/gpu/drm/radeon/r600_dpm.c             | 1024 ++++
 drivers/gpu/drm/radeon/r600_dpm.h             |  226 +
 drivers/gpu/drm/radeon/r600_hdmi.c            |   11 +-
 drivers/gpu/drm/radeon/r600_reg.h             |    6 +
 drivers/gpu/drm/radeon/r600d.h                |  232 +-
 drivers/gpu/drm/radeon/radeon.h               |  517 ++-
 drivers/gpu/drm/radeon/radeon_acpi.c          |  145 +
 drivers/gpu/drm/radeon/radeon_asic.c          |  524 ++-
 drivers/gpu/drm/radeon/radeon_asic.h          |  166 +
 drivers/gpu/drm/radeon/radeon_atombios.c      |  880 +++-
 drivers/gpu/drm/radeon/radeon_cs.c            |    1 +
 drivers/gpu/drm/radeon/radeon_cursor.c        |   10 +-
 drivers/gpu/drm/radeon/radeon_device.c        |  106 +-
 drivers/gpu/drm/radeon/radeon_display.c       |   21 +-
 drivers/gpu/drm/radeon/radeon_drv.c           |    7 +-
 drivers/gpu/drm/radeon/radeon_family.h        |    3 +
 drivers/gpu/drm/radeon/radeon_irq_kms.c       |   20 +
 drivers/gpu/drm/radeon/radeon_kms.c           |   41 +-
 drivers/gpu/drm/radeon/radeon_mode.h          |   93 +
 drivers/gpu/drm/radeon/radeon_pm.c            |  610 ++-
 drivers/gpu/drm/radeon/radeon_reg.h           |    1 +
 drivers/gpu/drm/radeon/radeon_ring.c          |   55 +-
 drivers/gpu/drm/radeon/radeon_ucode.h         |  129 +
 drivers/gpu/drm/radeon/radeon_uvd.c           |   32 +-
 drivers/gpu/drm/radeon/rs690.c                |  291 +-
 drivers/gpu/drm/radeon/rs780_dpm.c            |  963 ++++
 drivers/gpu/drm/radeon/rs780_dpm.h            |  109 +
 drivers/gpu/drm/radeon/rs780d.h               |  168 +
 drivers/gpu/drm/radeon/rv515.c                |  224 +-
 drivers/gpu/drm/radeon/rv6xx_dpm.c            | 2059 ++++++++
 drivers/gpu/drm/radeon/rv6xx_dpm.h            |   95 +
 drivers/gpu/drm/radeon/rv6xxd.h               |  246 +
 drivers/gpu/drm/radeon/rv730_dpm.c            |  508 ++
 drivers/gpu/drm/radeon/rv730d.h               |  165 +
 drivers/gpu/drm/radeon/rv740_dpm.c            |  416 ++
 drivers/gpu/drm/radeon/rv740d.h               |  117 +
 drivers/gpu/drm/radeon/rv770_dpm.c            | 2446 +++++++++
 drivers/gpu/drm/radeon/rv770_dpm.h            |  287 +
 drivers/gpu/drm/radeon/rv770_smc.c            |  621 +++
 drivers/gpu/drm/radeon/rv770_smc.h            |  209 +
 drivers/gpu/drm/radeon/rv770d.h               |  279 +-
 drivers/gpu/drm/radeon/si.c                   | 1337 +++++-
 drivers/gpu/drm/radeon/si_dpm.c               | 6369 ++++++++++++++++++++++
 drivers/gpu/drm/radeon/si_dpm.h               |  227 +
 drivers/gpu/drm/radeon/si_smc.c               |  284 +
 drivers/gpu/drm/radeon/sid.h                  |  599 ++-
 drivers/gpu/drm/radeon/sislands_smc.h         |  397 ++
 drivers/gpu/drm/radeon/sumo_dpm.c             | 1801 +++++++
 drivers/gpu/drm/radeon/sumo_dpm.h             |  220 +
 drivers/gpu/drm/radeon/sumo_smc.c             |  222 +
 drivers/gpu/drm/radeon/sumod.h                |  372 ++
 drivers/gpu/drm/radeon/trinity_dpm.c          | 1887 +++++++
 drivers/gpu/drm/radeon/trinity_dpm.h          |  131 +
 drivers/gpu/drm/radeon/trinity_smc.c          |  115 +
 drivers/gpu/drm/radeon/trinityd.h             |  228 +
 include/drm/drm_fixed.h                       |   96 +
 include/drm/drm_pciids.h                      |   24 +
 88 files changed, 52708 insertions(+), 561 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/btc_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/btc_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/btcd.h
 create mode 100644 drivers/gpu/drm/radeon/cik.c
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.c
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.h
 create mode 100644 drivers/gpu/drm/radeon/cik_reg.h
 create mode 100644 drivers/gpu/drm/radeon/cikd.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_cayman.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_defs.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_evergreen.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_si.h
 create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/evergreen_smc.h
 create mode 100644 drivers/gpu/drm/radeon/ni_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/ni_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/nislands_smc.h
 create mode 100644 drivers/gpu/drm/radeon/ppsmc.h
 create mode 100644 drivers/gpu/drm/radeon/r600_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/r600_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/radeon_ucode.h
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rs780d.h
 create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rv6xxd.h
 create mode 100644 drivers/gpu/drm/radeon/rv730_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv730d.h
 create mode 100644 drivers/gpu/drm/radeon/rv740_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv740d.h
 create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rv770_smc.c
 create mode 100644 drivers/gpu/drm/radeon/rv770_smc.h
 create mode 100644 drivers/gpu/drm/radeon/si_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/si_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/si_smc.c
 create mode 100644 drivers/gpu/drm/radeon/sislands_smc.h
 create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/sumo_smc.c
 create mode 100644 drivers/gpu/drm/radeon/sumod.h
 create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/trinity_smc.c
 create mode 100644 drivers/gpu/drm/radeon/trinityd.h
Signature · 6 lines
1.7.7.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#1 lore raw

PATCH 1/165 drm/radeon: fix AVI infoframe generation

From: Alex Deucher <[email protected]>

- remove adding 2 to checksum, this is incorrect.

This was incorrectly introduced in:
92db7f6c860b8190571a9dc1fcbc16d003422fe8
http://lists.freedesktop.org/archives/dri-devel/2011-December/017717.html
However, the off by 2 was due to adding the version twice. From the examples in the URL above:

[Rafał Miłecki][RV620] fglrx:

0x7454: 00 A8 5E 79     R600_HDMI_VIDEOINFOFRAME_0
0x7458: 00 28 00 10     R600_HDMI_VIDEOINFOFRAME_1
0x745C: 00 48 00 28     R600_HDMI_VIDEOINFOFRAME_2
0x7460: 02 00 00 48     R600_HDMI_VIDEOINFOFRAME_3

===================
(0x82 + 0x2 + 0xD) + 0x1F8 = 0x289
-0x289 = 0x77

However, the payload sum is not 0x1f8, it's 0x1f6. 00 + A8 + 5E + 00 +
00 + 28 + 00 + 10 +
00 + 48 + 00 + 28 +
00 + 48 =
0x1f6

Bits 25:24 of HDMI_VIDEOINFOFRAME_3 are the packet version, not part of the payload. So the total would be:
(0x82 + 0x2 + 0xD) + 0x1f6 = 0x287
-0x287 = 0x79

- properly emit the AVI infoframe version. This was not being emitted previous which is probably what caused the issue above.

This should fix blank screen when HDMI audio is enabled on certain monitors.

---
 drivers/gpu/drm/radeon/evergreen_hdmi.c |   11 ++---------
 drivers/gpu/drm/radeon/r600_hdmi.c      |   11 ++---------
 2 files changed, 4 insertions(+), 18 deletions(-)
drivers/gpu/drm/radeon/evergreen_hdmi.c +2 -9
index ed7c8a7..b9c6f76 100644
@@ -128,14 +128,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 	uint32_t offset = dig->afmt->offset;
 	uint8_t *frame = buffer + 3;
-
-	/* Our header values (type, version, length) should be alright, Intel
-	 * is using the same. Checksum function also seems to be OK, it works
-	 * fine for audio infoframe. However calculated value is always lower
-	 * by 2 in comparison to fglrx. It breaks displaying anything in case
-	 * of TVs that strictly check the checksum. Hack it manually here to
-	 * workaround this issue. */
-	frame[0x0] += 2;
+	uint8_t *header = buffer;
 
 	WREG32(AFMT_AVI_INFO0 + offset,
 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -144,7 +137,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	WREG32(AFMT_AVI_INFO2 + offset,
 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
 	WREG32(AFMT_AVI_INFO3 + offset,
-		frame[0xC] | (frame[0xD] << 8));
+		frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
 }
 
 static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
drivers/gpu/drm/radeon/r600_hdmi.c +2 -9
index 456750a..e73b2a7 100644
@@ -133,14 +133,7 @@ static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 	uint32_t offset = dig->afmt->offset;
 	uint8_t *frame = buffer + 3;
-
-	/* Our header values (type, version, length) should be alright, Intel
-	 * is using the same. Checksum function also seems to be OK, it works
-	 * fine for audio infoframe. However calculated value is always lower
-	 * by 2 in comparison to fglrx. It breaks displaying anything in case
-	 * of TVs that strictly check the checksum. Hack it manually here to
-	 * workaround this issue. */
-	frame[0x0] += 2;
+	uint8_t *header = buffer;
 
 	WREG32(HDMI0_AVI_INFO0 + offset,
 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -149,7 +142,7 @@ static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	WREG32(HDMI0_AVI_INFO2 + offset,
 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
 	WREG32(HDMI0_AVI_INFO3 + offset,
-		frame[0xC] | (frame[0xD] << 8));
+		frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
 }
 
 /*
Signature · 1 line
1.7.7.5
#2 lore raw

PATCH 2/165 drm/radeon: add backlight quirk for hybrid mac

In reply to [email protected]

From: Alex Deucher <[email protected]>

Mac laptops with multiple GPUs apparently use the gmux driver for backlight control. Don't register a radeon backlight interface. We may need to add other pci ids for other hybrid mac laptops.

Fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=65377

---
 drivers/gpu/drm/radeon/atombios_encoders.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/atombios_encoders.c +7 -0
index 8406c82..4120d35 100644
@@ -186,6 +186,13 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
 	u8 backlight_level;
 	char bl_name[16];
 
+	/* Mac laptops with multiple GPUs use the gmux driver for backlight
+	 * so don't register a backlight device
+	 */
+	if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
+	    (rdev->pdev->device == 0x6741))
+		return;
+
 	if (!radeon_encoder->enc_priv)
 		return;
 
Signature · 1 line
1.7.7.5
#3 lore raw

PATCH 3/165 drm/radeon: add a reset work handler

In reply to [email protected]

From: Alex Deucher <[email protected]>

New asics support non-privileged IBs. This allows us to skip IB checking in the driver since the hardware will check the command buffers for us. When using non-privileged IBs, if the CP encounters an illegal register in the command stream, it will halt and generate an interrupt. The CP needs to be reset to continue. For now just do a full GPU reset when this happens.

---
 drivers/gpu/drm/radeon/radeon.h         |    1 +
 drivers/gpu/drm/radeon/radeon_irq_kms.c |   18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/radeon.h +1 -0
index 142ce6c..f5fccbb 100644
@@ -1691,6 +1691,7 @@ struct radeon_device {
 	struct si_rlc rlc;
 	struct work_struct hotplug_work;
 	struct work_struct audio_work;
+	struct work_struct reset_work;
 	int num_crtc; /* number of crtcs */
 	struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
 	bool audio_enabled;
drivers/gpu/drm/radeon/radeon_irq_kms.c +18 -0
index 5a99d43..dbffeca 100644
@@ -82,6 +82,23 @@ static void radeon_hotplug_work_func(struct work_struct *work)
 }
 
 /**
+ * radeon_irq_reset_work_func - execute gpu reset
+ *
+ * @work: work struct
+ *
+ * Execute scheduled gpu reset (cayman+).
+ * This function is called when the irq handler
+ * thinks we need a gpu reset.
+ */
+static void radeon_irq_reset_work_func(struct work_struct *work)
+{
+	struct radeon_device *rdev = container_of(work, struct radeon_device,
+						  reset_work);
+
+	radeon_gpu_reset(rdev);
+}
+
+/**
  * radeon_driver_irq_preinstall_kms - drm irq preinstall callback
  *
  * @dev: drm dev pointer
@@ -243,6 +260,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
 
 	INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
 	INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
+	INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);
 
 	spin_lock_init(&rdev->irq.lock);
 	r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
Signature · 1 line
1.7.7.5
#4 lore raw

PATCH 4/165 drm/radeon: add CIK chip families

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/radeon_device.c |    3 +++
 drivers/gpu/drm/radeon/radeon_family.h |    3 +++
 2 files changed, 6 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/radeon_device.c +3 -0
index b0dc0b6..c24056b 100644
@@ -95,6 +95,9 @@ static const char radeon_family_name[][16] = {
 	"VERDE",
 	"OLAND",
 	"HAINAN",
+	"BONAIRE",
+	"KAVERI",
+	"KABINI",
 	"LAST",
 };
 
drivers/gpu/drm/radeon/radeon_family.h +3 -0
index 36e9803..3c82890 100644
@@ -93,6 +93,9 @@ enum radeon_family {
 	CHIP_VERDE,
 	CHIP_OLAND,
 	CHIP_HAINAN,
+	CHIP_BONAIRE,
+	CHIP_KAVERI,
+	CHIP_KABINI,
 	CHIP_LAST,
 };
 
Signature · 1 line
1.7.7.5
#5 lore raw

PATCH 5/165 drm/radeon: add DCE8 macro for CIK

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/radeon.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/radeon.h +1 -0
index f5fccbb..b50a786 100644
@@ -1841,6 +1841,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
 			     (rdev->flags & RADEON_IS_IGP))
 #define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND))
 #define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN))
+#define ASIC_IS_DCE8(rdev) ((rdev->family >= CHIP_BONAIRE))
 
 /*
  * BIOS helpers.
Signature · 1 line
1.7.7.5
#6 lore raw

PATCH 6/165 drm/radeon: adapt to PCI BAR changes on CIK

In reply to [email protected]

From: Alex Deucher <[email protected]>

register BAR is now at PCI BAR 5.

---
 drivers/gpu/drm/radeon/radeon_device.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)
drivers/gpu/drm/radeon/radeon_device.c +7 -2
index c24056b..4e97ff7 100644
@@ -1148,8 +1148,13 @@ int radeon_device_init(struct radeon_device *rdev,
 	/* Registers mapping */
 	/* TODO: block userspace mapping of io register */
 	spin_lock_init(&rdev->mmio_idx_lock);
-	rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
-	rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
+	if (rdev->family >= CHIP_BONAIRE) {
+		rdev->rmmio_base = pci_resource_start(rdev->pdev, 5);
+		rdev->rmmio_size = pci_resource_len(rdev->pdev, 5);
+	} else {
+		rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
+		rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
+	}
 	rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);
 	if (rdev->rmmio == NULL) {
 		return -ENOMEM;
Signature · 1 line
1.7.7.5
#7 lore raw

PATCH 7/165 drm/radeon: add gpu init support for CIK (v9)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: tiling fixes
v3: more tiling fixes
v4: more tiling fixes
v5: additional register init
v6: rebase
v7: fix gb_addr_config for KV/KB
v8: drop wip KV bits for now, add missing config reg
v9: fix cu count on Bonaire

---
 drivers/gpu/drm/radeon/Makefile |    2 +-
 drivers/gpu/drm/radeon/cik.c    | 1192 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h   |  253 +++++++++
 drivers/gpu/drm/radeon/radeon.h |   30 +
 4 files changed, 1476 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/cik.c
 create mode 100644 drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/Makefile +1 -1
index 86c5e36..88d0601 100644
@@ -76,7 +76,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
-	si_blit_shaders.o radeon_prime.o radeon_uvd.o
+	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
drivers/gpu/drm/radeon/cik.c new file +1192 -0

1,192 lines not on this page · raw message

drivers/gpu/drm/radeon/cikd.h new file +253 -0

253 lines not on this page · raw message

drivers/gpu/drm/radeon/radeon.h +30 -0
index b50a786..b1a2230 100644
@@ -1505,6 +1505,35 @@ struct si_asic {
 	uint32_t tile_mode_array[32];
 };
 
+struct cik_asic {
+	unsigned max_shader_engines;
+	unsigned max_tile_pipes;
+	unsigned max_cu_per_sh;
+	unsigned max_sh_per_se;
+	unsigned max_backends_per_se;
+	unsigned max_texture_channel_caches;
+	unsigned max_gprs;
+	unsigned max_gs_threads;
+	unsigned max_hw_contexts;
+	unsigned sc_prim_fifo_size_frontend;
+	unsigned sc_prim_fifo_size_backend;
+	unsigned sc_hiz_tile_fifo_size;
+	unsigned sc_earlyz_tile_fifo_size;
+
+	unsigned num_tile_pipes;
+	unsigned num_backends_per_se;
+	unsigned backend_disable_mask_per_asic;
+	unsigned backend_map;
+	unsigned num_texture_channel_caches;
+	unsigned mem_max_burst_length_bytes;
+	unsigned mem_row_size_in_kb;
+	unsigned shader_engine_tile_size;
+	unsigned num_gpus;
+	unsigned multi_gpu_tile_size;
+
+	unsigned tile_config;
+};
+
 union radeon_asic_config {
 	struct r300_asic	r300;
 	struct r100_asic	r100;
@@ -1513,6 +1542,7 @@ union radeon_asic_config {
 	struct evergreen_asic	evergreen;
 	struct cayman_asic	cayman;
 	struct si_asic		si;
+	struct cik_asic		cik;
 };
 
 /*
Signature · 1 line
1.7.7.5
#8 lore raw

PATCH 8/165 drm/radeon: Add support for CIK GPU reset (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: split soft reset into compute and gfx. Still need to make reset more fine grained, but this should be a start.

---
 drivers/gpu/drm/radeon/cik.c  |  197 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   80 +++++++++++++++++
 2 files changed, 277 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +197 -0
index 28f68dc..e448ae2 100644
@@ -27,9 +27,13 @@
 #include <linux/module.h>
 #include "drmP.h"
 #include "radeon.h"
+#include "radeon_asic.h"
 #include "cikd.h"
 #include "atom.h"
 
+extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+
 /*
  * Core functions
  */
@@ -1190,3 +1194,196 @@ static void cik_gpu_init(struct radeon_device *rdev)
 	udelay(50);
 }
 
+/**
+ * cik_gpu_is_lockup - check if the 3D engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the 3D engine is locked up (CIK).
+ * Returns true if the engine is locked, false if not.
+ */
+bool cik_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	u32 srbm_status, srbm_status2;
+	u32 grbm_status, grbm_status2;
+	u32 grbm_status_se0, grbm_status_se1, grbm_status_se2, grbm_status_se3;
+
+	srbm_status = RREG32(SRBM_STATUS);
+	srbm_status2 = RREG32(SRBM_STATUS2);
+	grbm_status = RREG32(GRBM_STATUS);
+	grbm_status2 = RREG32(GRBM_STATUS2);
+	grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
+	grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
+	grbm_status_se2 = RREG32(GRBM_STATUS_SE2);
+	grbm_status_se3 = RREG32(GRBM_STATUS_SE3);
+	if (!(grbm_status & GUI_ACTIVE)) {
+		radeon_ring_lockup_update(ring);
+		return false;
+	}
+	/* force CP activities */
+	radeon_ring_force_activity(rdev, ring);
+	return radeon_ring_test_lockup(rdev, ring);
+}
+
+/**
+ * cik_gfx_gpu_soft_reset - soft reset the 3D engine and CPG
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the GFX engine and CPG blocks (CIK).
+ * XXX: deal with reseting RLC and CPF
+ * Returns 0 for success.
+ */
+static int cik_gfx_gpu_soft_reset(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 grbm_reset = 0;
+
+	if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+		return 0;
+
+	dev_info(rdev->dev, "GPU GFX softreset \n");
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Disable CP parsing/prefetching */
+	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+	/* reset all the gfx block and all CPG blocks */
+	grbm_reset = SOFT_RESET_CPG | SOFT_RESET_GFX;
+
+	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
+	WREG32(GRBM_SOFT_RESET, grbm_reset);
+	(void)RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(GRBM_SOFT_RESET, 0);
+	(void)RREG32(GRBM_SOFT_RESET);
+	/* Wait a little for things to settle down */
+	udelay(50);
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_resume(rdev, &save);
+	return 0;
+}
+
+/**
+ * cik_compute_gpu_soft_reset - soft reset CPC
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the CPC blocks (CIK).
+ * XXX: deal with reseting RLC and CPF
+ * Returns 0 for success.
+ */
+static int cik_compute_gpu_soft_reset(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 grbm_reset = 0;
+
+	dev_info(rdev->dev, "GPU compute softreset \n");
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Disable CP parsing/prefetching */
+	WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
+
+	/* reset all the CPC blocks */
+	grbm_reset = SOFT_RESET_CPG;
+
+	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
+	WREG32(GRBM_SOFT_RESET, grbm_reset);
+	(void)RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(GRBM_SOFT_RESET, 0);
+	(void)RREG32(GRBM_SOFT_RESET);
+	/* Wait a little for things to settle down */
+	udelay(50);
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_resume(rdev, &save);
+	return 0;
+}
+
+/**
+ * cik_asic_reset - soft reset compute and gfx
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the CPC blocks (CIK).
+ * XXX: make this more fine grained and only reset
+ * what is necessary.
+ * Returns 0 for success.
+ */
+int cik_asic_reset(struct radeon_device *rdev)
+{
+	int r;
+
+	r = cik_compute_gpu_soft_reset(rdev);
+	if (r)
+		dev_info(rdev->dev, "Compute reset failed!\n");
+
+	return cik_gfx_gpu_soft_reset(rdev);
+}
drivers/gpu/drm/radeon/cikd.h +80 -0

92 lines not on this page · raw message

Signature · 1 line
1.7.7.5
#9 lore raw

PATCH 9/165 drm/radeon: add support for MC/VM setup on CIK (v6)

In reply to [email protected]

From: Alex Deucher <[email protected]>

The vm callbacks are the same as the SI ones right now (same regs and bits). We could share the SI variants, and I may yet do that, but I figured I would add CIK specific ones for now in case we need to change anything.

V2: add documentation, minor fixes.
V3: integrate vram offset fixes for APUs
V4: enable 2 level VM PTs
V5: index SH_MEM_* regs properly
V6: add ib_parse()

---
 drivers/gpu/drm/radeon/cik.c  |  361 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |  125 ++++++++++++++
 drivers/gpu/drm/radeon/si.c   |    4 +-
 3 files changed, 488 insertions(+), 2 deletions(-)
drivers/gpu/drm/radeon/cik.c +361 -0
index e448ae2..a4e1b95 100644
@@ -33,6 +33,7 @@
 
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 
 /*
  * Core functions
@@ -1387,3 +1388,363 @@ int cik_asic_reset(struct radeon_device *rdev)
 
 	return cik_gfx_gpu_soft_reset(rdev);
 }
+
+/* MC */
+/**
+ * cik_mc_program - program the GPU memory controller
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set the location of vram, gart, and AGP in the GPU's
+ * physical address space (CIK).
+ */
+static void cik_mc_program(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 tmp;
+	int i, j;
+
+	/* Initialize HDP */
+	for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+		WREG32((0x2c14 + j), 0x00000000);
+		WREG32((0x2c18 + j), 0x00000000);
+		WREG32((0x2c1c + j), 0x00000000);
+		WREG32((0x2c20 + j), 0x00000000);
+		WREG32((0x2c24 + j), 0x00000000);
+	}
+	WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
+
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Lockout access through VGA aperture*/
+	WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
+	/* Update configuration */
+	WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+	       rdev->mc.vram_start >> 12);
+	WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+	       rdev->mc.vram_end >> 12);
+	WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
+	       rdev->vram_scratch.gpu_addr >> 12);
+	tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
+	tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
+	WREG32(MC_VM_FB_LOCATION, tmp);
+	/* XXX double check these! */
+	WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
+	WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30));
+	WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF);
+	WREG32(MC_VM_AGP_BASE, 0);
+	WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
+	WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	evergreen_mc_resume(rdev, &save);
+	/* we need to own VRAM, so turn off the VGA renderer here
+	 * to stop it overwriting our objects */
+	rv515_vga_render_disable(rdev);
+}
+
+/**
+ * cik_mc_init - initialize the memory controller driver params
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Look up the amount of vram, vram width, and decide how to place
+ * vram and gart within the GPU's physical address space (CIK).
+ * Returns 0 for success.
+ */
+static int cik_mc_init(struct radeon_device *rdev)
+{
+	u32 tmp;
+	int chansize, numchan;
+
+	/* Get VRAM informations */
+	rdev->mc.vram_is_ddr = true;
+	tmp = RREG32(MC_ARB_RAMCFG);
+	if (tmp & CHANSIZE_MASK) {
+		chansize = 64;
+	} else {
+		chansize = 32;
+	}
+	tmp = RREG32(MC_SHARED_CHMAP);
+	switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+	case 0:
+	default:
+		numchan = 1;
+		break;
+	case 1:
+		numchan = 2;
+		break;
+	case 2:
+		numchan = 4;
+		break;
+	case 3:
+		numchan = 8;
+		break;
+	case 4:
+		numchan = 3;
+		break;
+	case 5:
+		numchan = 6;
+		break;
+	case 6:
+		numchan = 10;
+		break;
+	case 7:
+		numchan = 12;
+		break;
+	case 8:
+		numchan = 16;
+		break;
+	}
+	rdev->mc.vram_width = numchan * chansize;
+	/* Could aper size report 0 ? */
+	rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+	rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
+	/* size in MB on si */
+	rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+	rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+	rdev->mc.visible_vram_size = rdev->mc.aper_size;
+	si_vram_gtt_location(rdev, &rdev->mc);
+	radeon_update_bandwidth_info(rdev);
+
+	return 0;
+}
+
+/*
+ * GART
+ * VMID 0 is the physical GPU addresses as used by the kernel.
+ * VMIDs 1-15 are used for userspace clients and are handled
+ * by the radeon vm/hsa code.
+ */
+/**
+ * cik_pcie_gart_tlb_flush - gart tlb flush callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Flush the TLB for the VMID 0 page table (CIK).
+ */
+void cik_pcie_gart_tlb_flush(struct radeon_device *rdev)
+{
+	/* flush hdp cache */
+	WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0);
+
+	/* bits 0-15 are the VM contexts0-15 */
+	WREG32(VM_INVALIDATE_REQUEST, 0x1);
+}
+
+/**
+ * cik_pcie_gart_enable - gart enable
+ *
+ * @rdev: radeon_device pointer
+ *
+ * This sets up the TLBs, programs the page tables for VMID0,
+ * sets up the hw for VMIDs 1-15 which are allocated on
+ * demand, and sets up the global locations for the LDS, GDS,
+ * and GPUVM for FSA64 clients (CIK).
+ * Returns 0 for success, errors for failure.
+ */
+static int cik_pcie_gart_enable(struct radeon_device *rdev)
+{
+	int r, i;
+
+	if (rdev->gart.robj == NULL) {
+		dev_err(rdev->dev, "No VRAM object for PCIE GART.\n");
+		return -EINVAL;
+	}
+	r = radeon_gart_table_vram_pin(rdev);
+	if (r)
+		return r;
+	radeon_gart_restore(rdev);
+	/* Setup TLB control */
+	WREG32(MC_VM_MX_L1_TLB_CNTL,
+	       (0xA << 7) |
+	       ENABLE_L1_TLB |
+	       SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+	       ENABLE_ADVANCED_DRIVER_MODEL |
+	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+	/* Setup L2 cache */
+	WREG32(VM_L2_CNTL, ENABLE_L2_CACHE |
+	       ENABLE_L2_FRAGMENT_PROCESSING |
+	       ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+	       EFFECTIVE_L2_QUEUE_SIZE(7) |
+	       CONTEXT1_IDENTITY_ACCESS_MODE(1));
+	WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
+	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+	       L2_CACHE_BIGK_FRAGMENT_SIZE(6));
+	/* setup context0 */
+	WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
+	WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
+	WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
+	WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
+			(u32)(rdev->dummy_page.addr >> 12));
+	WREG32(VM_CONTEXT0_CNTL2, 0);
+	WREG32(VM_CONTEXT0_CNTL, (ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+				  RANGE_PROTECTION_FAULT_ENABLE_DEFAULT));
+
+	WREG32(0x15D4, 0);
+	WREG32(0x15D8, 0);
+	WREG32(0x15DC, 0);
+
+	/* empty context1-15 */
+	/* FIXME start with 4G, once using 2 level pt switch to full
+	 * vm size space
+	 */
+	/* set vm size, must be a multiple of 4 */
+	WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
+	WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
+	for (i = 1; i < 16; i++) {
+		if (i < 8)
+			WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
+			       rdev->gart.table_addr >> 12);
+		else
+			WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2),
+			       rdev->gart.table_addr >> 12);
+	}
+
+	/* enable context1-15 */
+	WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
+	       (u32)(rdev->dummy_page.addr >> 12));
+	WREG32(VM_CONTEXT1_CNTL2, 0);
+	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
+				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
+
+	/* TC cache setup ??? */
+	WREG32(TC_CFG_L1_LOAD_POLICY0, 0);
+	WREG32(TC_CFG_L1_LOAD_POLICY1, 0);
+	WREG32(TC_CFG_L1_STORE_POLICY, 0);
+
+	WREG32(TC_CFG_L2_LOAD_POLICY0, 0);
+	WREG32(TC_CFG_L2_LOAD_POLICY1, 0);
+	WREG32(TC_CFG_L2_STORE_POLICY0, 0);
+	WREG32(TC_CFG_L2_STORE_POLICY1, 0);
+	WREG32(TC_CFG_L2_ATOMIC_POLICY, 0);
+
+	WREG32(TC_CFG_L1_VOLATILE, 0);
+	WREG32(TC_CFG_L2_VOLATILE, 0);
+
+	if (rdev->family == CHIP_KAVERI) {
+		u32 tmp = RREG32(CHUB_CONTROL);
+		tmp &= ~BYPASS_VM;
+		WREG32(CHUB_CONTROL, tmp);
+	}
+
+	/* XXX SH_MEM regs */
+	/* where to put LDS, scratch, GPUVM in FSA64 space */
+	for (i = 0; i < 16; i++) {
+		WREG32(SRBM_GFX_CNTL, VMID(i));
+		WREG32(SH_MEM_CONFIG, 0);
+		WREG32(SH_MEM_APE1_BASE, 1);
+		WREG32(SH_MEM_APE1_LIMIT, 0);
+		WREG32(SH_MEM_BASES, 0);
+	}
+	WREG32(SRBM_GFX_CNTL, 0);
+
+	cik_pcie_gart_tlb_flush(rdev);
+	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
+		 (unsigned)(rdev->mc.gtt_size >> 20),
+		 (unsigned long long)rdev->gart.table_addr);
+	rdev->gart.ready = true;
+	return 0;
+}
+
+/**
+ * cik_pcie_gart_disable - gart disable
+ *
+ * @rdev: radeon_device pointer
+ *
+ * This disables all VM page table (CIK).
+ */
+static void cik_pcie_gart_disable(struct radeon_device *rdev)
+{
+	/* Disable all tables */
+	WREG32(VM_CONTEXT0_CNTL, 0);
+	WREG32(VM_CONTEXT1_CNTL, 0);
+	/* Setup TLB control */
+	WREG32(MC_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+	/* Setup L2 cache */
+	WREG32(VM_L2_CNTL,
+	       ENABLE_L2_FRAGMENT_PROCESSING |
+	       ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+	       EFFECTIVE_L2_QUEUE_SIZE(7) |
+	       CONTEXT1_IDENTITY_ACCESS_MODE(1));
+	WREG32(VM_L2_CNTL2, 0);
+	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+	       L2_CACHE_BIGK_FRAGMENT_SIZE(6));
+	radeon_gart_table_vram_unpin(rdev);
+}
+
+/**
+ * cik_pcie_gart_fini - vm fini callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tears down the driver GART/VM setup (CIK).
+ */
+static void cik_pcie_gart_fini(struct radeon_device *rdev)
+{
+	cik_pcie_gart_disable(rdev);
+	radeon_gart_table_vram_free(rdev);
+	radeon_gart_fini(rdev);
+}
+
+/* vm parser */
+/**
+ * cik_ib_parse - vm ib_parse callback
+ *
+ * @rdev: radeon_device pointer
+ * @ib: indirect buffer pointer
+ *
+ * CIK uses hw IB checking so this is a nop (CIK).
+ */
+int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+	return 0;
+}
+
+/*
+ * vm
+ * VMID 0 is the physical GPU addresses as used by the kernel.
+ * VMIDs 1-15 are used for userspace clients and are handled
+ * by the radeon vm/hsa code.
+ */
+/**
+ * cik_vm_init - cik vm init callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Inits cik specific vm parameters (number of VMs, base of vram for
+ * VMIDs 1-15) (CIK).
+ * Returns 0 for success.
+ */
+int cik_vm_init(struct radeon_device *rdev)
+{
+	/* number of VMs */
+	rdev->vm_manager.nvm = 16;
+	/* base offset of vram pages */
+	if (rdev->flags & RADEON_IS_IGP) {
+		u64 tmp = RREG32(MC_VM_FB_OFFSET);
+		tmp <<= 22;
+		rdev->vm_manager.vram_base_offset = tmp;
+	} else
+		rdev->vm_manager.vram_base_offset = 0;
+
+	return 0;
+}
+
+/**
+ * cik_vm_fini - cik vm fini callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down any asic specific VM setup (CIK).
+ */
+void cik_vm_fini(struct radeon_device *rdev)
+{
+}
+
drivers/gpu/drm/radeon/cikd.h +125 -0

163 lines not on this page · raw message

drivers/gpu/drm/radeon/si.c +2 -2
index a1b0da6..813a8a9 100644
@@ -3535,8 +3535,8 @@ static void si_mc_program(struct radeon_device *rdev)
 	}
 }
 
-static void si_vram_gtt_location(struct radeon_device *rdev,
-				 struct radeon_mc *mc)
+void si_vram_gtt_location(struct radeon_device *rdev,
+			  struct radeon_mc *mc)
 {
 	if (mc->mc_vram_size > 0xFFC0000000ULL) {
 		/* leave room for at least 1024M GTT */
Signature · 1 line
1.7.7.5
#10 lore raw

PATCH 10/165 drm/radeon/cik: stop page faults from hanging the system (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Redirect invalid memory accesses to the default page instead of locking up the memory controller.

v2: rebase on top of 2 level PTs

---
 drivers/gpu/drm/radeon/cik.c  |   15 +++++++++++++--
 drivers/gpu/drm/radeon/cikd.h |   11 +++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)
drivers/gpu/drm/radeon/cik.c +13 -2
index a4e1b95..28a7531 100644
@@ -1608,9 +1608,20 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 	/* enable context1-15 */
 	WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
 	       (u32)(rdev->dummy_page.addr >> 12));
-	WREG32(VM_CONTEXT1_CNTL2, 0);
+	WREG32(VM_CONTEXT1_CNTL2, 4);
 	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
-				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
+				RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+				DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+				PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				PDE0_PROTECTION_FAULT_ENABLE_DEFAULT |
+				VALID_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				VALID_PROTECTION_FAULT_ENABLE_DEFAULT |
+				READ_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				READ_PROTECTION_FAULT_ENABLE_DEFAULT |
+				WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				WRITE_PROTECTION_FAULT_ENABLE_DEFAULT);
 
 	/* TC cache setup ??? */
 	WREG32(TC_CFG_L1_LOAD_POLICY0, 0);
drivers/gpu/drm/radeon/cikd.h +11 -0
index 071a781..0dab9c5 100644
@@ -68,7 +68,18 @@
 #define VM_CONTEXT0_CNTL				0x1410
 #define		ENABLE_CONTEXT					(1 << 0)
 #define		PAGE_TABLE_DEPTH(x)				(((x) & 3) << 1)
+#define		RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 3)
 #define		RANGE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 4)
+#define		DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT	(1 << 6)
+#define		DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT	(1 << 7)
+#define		PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 9)
+#define		PDE0_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 10)
+#define		VALID_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 12)
+#define		VALID_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 13)
+#define		READ_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 15)
+#define		READ_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 16)
+#define		WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 18)
+#define		WRITE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 19)
 #define VM_CONTEXT1_CNTL				0x1414
 #define VM_CONTEXT0_CNTL2				0x1430
 #define VM_CONTEXT1_CNTL2				0x1434
Signature · 1 line
1.7.7.5
#11 lore raw

PATCH 11/165 drm/radeon: add initial ucode loading for CIK (v5)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Currently the driver required 6 sets of ucode:
1. pfp - pre-fetch parser, part of the GFX CP
2. me - micro engine, part of the GFX CP
3. ce - constant engine, part of the GFX CP
4. rlc - interrupt, etc. controller
5. mc - memory controller (discrete cards only)
6. mec - compute engines, part of Compute CP

V2: add documentation
V3: update MC ucode
V4: rebase
V5: update mc ucode

---
 drivers/gpu/drm/radeon/cik.c    |  180 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon.h |    1 +
 2 files changed, 181 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +180 -0
index 28a7531..36e0fc9 100644
@@ -31,10 +31,190 @@
 #include "cikd.h"
 #include "atom.h"
 
+/* GFX */
+#define CIK_PFP_UCODE_SIZE 2144
+#define CIK_ME_UCODE_SIZE 2144
+#define CIK_CE_UCODE_SIZE 2144
+/* compute */
+#define CIK_MEC_UCODE_SIZE 4192
+/* interrupts */
+#define BONAIRE_RLC_UCODE_SIZE 2048
+#define KB_RLC_UCODE_SIZE 2560
+#define KV_RLC_UCODE_SIZE 2560
+/* gddr controller */
+#define CIK_MC_UCODE_SIZE 7866
+
+MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_me.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_ce.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_mec.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_mc.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");
+MODULE_FIRMWARE("radeon/KAVERI_pfp.bin");
+MODULE_FIRMWARE("radeon/KAVERI_me.bin");
+MODULE_FIRMWARE("radeon/KAVERI_ce.bin");
+MODULE_FIRMWARE("radeon/KAVERI_mec.bin");
+MODULE_FIRMWARE("radeon/KAVERI_rlc.bin");
+MODULE_FIRMWARE("radeon/KABINI_pfp.bin");
+MODULE_FIRMWARE("radeon/KABINI_me.bin");
+MODULE_FIRMWARE("radeon/KABINI_ce.bin");
+MODULE_FIRMWARE("radeon/KABINI_mec.bin");
+MODULE_FIRMWARE("radeon/KABINI_rlc.bin");
+
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 
+/**
+ * cik_init_microcode - load ucode images from disk
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Use the firmware interface to load the ucode images into
+ * the driver (not loaded into hw).
+ * Returns 0 on success, error on failure.
+ */
+static int cik_init_microcode(struct radeon_device *rdev)
+{
+	struct platform_device *pdev;
+	const char *chip_name;
+	size_t pfp_req_size, me_req_size, ce_req_size,
+		mec_req_size, rlc_req_size, mc_req_size;
+	char fw_name[30];
+	int err;
+
+	DRM_DEBUG("\n");
+
+	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
+	err = IS_ERR(pdev);
+	if (err) {
+		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
+		return -EINVAL;
+	}
+
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+		chip_name = "BONAIRE";
+		pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+		me_req_size = CIK_ME_UCODE_SIZE * 4;
+		ce_req_size = CIK_CE_UCODE_SIZE * 4;
+		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4;
+		mc_req_size = CIK_MC_UCODE_SIZE * 4;
+		break;
+	case CHIP_KAVERI:
+		chip_name = "KAVERI";
+		pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+		me_req_size = CIK_ME_UCODE_SIZE * 4;
+		ce_req_size = CIK_CE_UCODE_SIZE * 4;
+		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+		rlc_req_size = KV_RLC_UCODE_SIZE * 4;
+		break;
+	case CHIP_KABINI:
+		chip_name = "KABINI";
+		pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+		me_req_size = CIK_ME_UCODE_SIZE * 4;
+		ce_req_size = CIK_CE_UCODE_SIZE * 4;
+		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+		rlc_req_size = KB_RLC_UCODE_SIZE * 4;
+		break;
+	default: BUG();
+	}
+
+	DRM_INFO("Loading %s Microcode\n", chip_name);
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
+	err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->pfp_fw->size != pfp_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->pfp_fw->size, fw_name);
+		err = -EINVAL;
+		goto out;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
+	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->me_fw->size != me_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->me_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name);
+	err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->ce_fw->size != ce_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->ce_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name);
+	err = request_firmware(&rdev->mec_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->mec_fw->size != mec_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->mec_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name);
+	err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->rlc_fw->size != rlc_req_size) {
+		printk(KERN_ERR
+		       "cik_rlc: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->rlc_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	/* No MC ucode on APUs */
+	if (!(rdev->flags & RADEON_IS_IGP)) {
+		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+		err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+		if (err)
+			goto out;
+		if (rdev->mc_fw->size != mc_req_size) {
+			printk(KERN_ERR
+			       "cik_mc: Bogus length %zu in firmware \"%s\"\n",
+			       rdev->mc_fw->size, fw_name);
+			err = -EINVAL;
+		}
+	}
+
+out:
+	platform_device_unregister(pdev);
+
+	if (err) {
+		if (err != -EINVAL)
+			printk(KERN_ERR
+			       "cik_cp: Failed to load firmware \"%s\"\n",
+			       fw_name);
+		release_firmware(rdev->pfp_fw);
+		rdev->pfp_fw = NULL;
+		release_firmware(rdev->me_fw);
+		rdev->me_fw = NULL;
+		release_firmware(rdev->ce_fw);
+		rdev->ce_fw = NULL;
+		release_firmware(rdev->rlc_fw);
+		rdev->rlc_fw = NULL;
+		release_firmware(rdev->mc_fw);
+		rdev->mc_fw = NULL;
+	}
+	return err;
+}
+
 /*
  * Core functions
  */
drivers/gpu/drm/radeon/radeon.h +1 -0
index b1a2230..1c06c47 100644
@@ -1714,6 +1714,7 @@ struct radeon_device {
 	const struct firmware *mc_fw;	/* NI MC firmware */
 	const struct firmware *ce_fw;	/* SI CE firmware */
 	const struct firmware *uvd_fw;	/* UVD firmware */
+	const struct firmware *mec_fw;	/* CIK MEC firmware */
 	struct r600_blit r600_blit;
 	struct r600_vram_scratch vram_scratch;
 	int msi_enabled; /* msi enabled */
Signature · 1 line
1.7.7.5
#12 lore raw

PATCH 12/165 drm/radeon: add support mc ucode loading on CIK (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Load the GDDR5 ucode and train the links.

v2: update ucode

---
 drivers/gpu/drm/radeon/cik.c  |  116 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   16 ++++++
 2 files changed, 132 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +116 -0
index 36e0fc9..8eec582 100644
@@ -65,6 +65,122 @@ extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_sa
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 
+#define BONAIRE_IO_MC_REGS_SIZE 36
+
+static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
+{
+	{0x00000070, 0x04400000},
+	{0x00000071, 0x80c01803},
+	{0x00000072, 0x00004004},
+	{0x00000073, 0x00000100},
+	{0x00000074, 0x00ff0000},
+	{0x00000075, 0x34000000},
+	{0x00000076, 0x08000014},
+	{0x00000077, 0x00cc08ec},
+	{0x00000078, 0x00000400},
+	{0x00000079, 0x00000000},
+	{0x0000007a, 0x04090000},
+	{0x0000007c, 0x00000000},
+	{0x0000007e, 0x4408a8e8},
+	{0x0000007f, 0x00000304},
+	{0x00000080, 0x00000000},
+	{0x00000082, 0x00000001},
+	{0x00000083, 0x00000002},
+	{0x00000084, 0xf3e4f400},
+	{0x00000085, 0x052024e3},
+	{0x00000087, 0x00000000},
+	{0x00000088, 0x01000000},
+	{0x0000008a, 0x1c0a0000},
+	{0x0000008b, 0xff010000},
+	{0x0000008d, 0xffffefff},
+	{0x0000008e, 0xfff3efff},
+	{0x0000008f, 0xfff3efbf},
+	{0x00000092, 0xf7ffffff},
+	{0x00000093, 0xffffff7f},
+	{0x00000095, 0x00101101},
+	{0x00000096, 0x00000fff},
+	{0x00000097, 0x00116fff},
+	{0x00000098, 0x60010000},
+	{0x00000099, 0x10010000},
+	{0x0000009a, 0x00006000},
+	{0x0000009b, 0x00001000},
+	{0x0000009f, 0x00b48000}
+};
+
+/* ucode loading */
+/**
+ * ci_mc_load_microcode - load MC ucode into the hw
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Load the GDDR MC ucode into the hw (CIK).
+ * Returns 0 on success, error on failure.
+ */
+static int ci_mc_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	u32 running, blackout = 0;
+	u32 *io_mc_regs;
+	int i, ucode_size, regs_size;
+
+	if (!rdev->mc_fw)
+		return -EINVAL;
+
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+	default:
+		io_mc_regs = (u32 *)&bonaire_io_mc_regs;
+		ucode_size = CIK_MC_UCODE_SIZE;
+		regs_size = BONAIRE_IO_MC_REGS_SIZE;
+		break;
+	}
+
+	running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
+
+	if (running == 0) {
+		if (running) {
+			blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
+			WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
+		}
+
+		/* reset the engine and set to writable */
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
+
+		/* load mc io regs */
+		for (i = 0; i < regs_size; i++) {
+			WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]);
+			WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]);
+		}
+		/* load the MC ucode */
+		fw_data = (const __be32 *)rdev->mc_fw->data;
+		for (i = 0; i < ucode_size; i++)
+			WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++));
+
+		/* put the engine back into the active state */
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000004);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000001);
+
+		/* wait for training to complete */
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D0)
+				break;
+			udelay(1);
+		}
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D1)
+				break;
+			udelay(1);
+		}
+
+		if (running)
+			WREG32(MC_SHARED_BLACKOUT_CNTL, blackout);
+	}
+
+	return 0;
+}
+
 /**
  * cik_init_microcode - load ucode images from disk
  *
drivers/gpu/drm/radeon/cikd.h +16 -0
index 0dab9c5..2300ae0 100644
@@ -139,6 +139,8 @@
 #define		ENABLE_ADVANCED_DRIVER_MODEL			(1 << 6)
 #define	MC_VM_FB_OFFSET					0x2068
 
+#define MC_SHARED_BLACKOUT_CNTL           		0x20ac
+
 #define	MC_ARB_RAMCFG					0x2760
 #define		NOOFBANK_SHIFT					0
 #define		NOOFBANK_MASK					0x00000003
@@ -153,6 +155,20 @@
 #define		NOOFGROUPS_SHIFT				12
 #define		NOOFGROUPS_MASK					0x00001000
 
+#define MC_SEQ_SUP_CNTL           			0x28c8
+#define		RUN_MASK      				(1 << 0)
+#define MC_SEQ_SUP_PGM           			0x28cc
+
+#define	MC_SEQ_TRAIN_WAKEUP_CNTL			0x28e8
+#define		TRAIN_DONE_D0      			(1 << 30)
+#define		TRAIN_DONE_D1      			(1 << 31)
+
+#define MC_IO_PAD_CNTL_D0           			0x29d0
+#define		MEM_FALL_OUT_CMD      			(1 << 8)
+
+#define MC_SEQ_IO_DEBUG_INDEX           		0x2a44
+#define MC_SEQ_IO_DEBUG_DATA           			0x2a48
+
 #define	HDP_HOST_PATH_CNTL				0x2C00
 #define	HDP_NONSURFACE_BASE				0x2C04
 #define	HDP_NONSURFACE_INFO				0x2C08
Signature · 1 line
1.7.7.5
#13 lore raw

PATCH 13/165 drm/radeon: Add CP init for CIK (v7)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Sets up the GFX ring and loads ucode for GFX and Compute.

Todo:
- handle compute queue setup.

v2: add documentation
v3: integrate with latest reset changes
v4: additional init fixes
v5: scratch reg write back no longer supported on CIK
v6: properly set CP_RB0_BASE_HI
v7: rebase

---
 drivers/gpu/drm/radeon/Makefile           |    2 +-
 drivers/gpu/drm/radeon/cik.c              |  395 +++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cik_blit_shaders.c |  246 ++++++++++++++++++
 drivers/gpu/drm/radeon/cik_blit_shaders.h |   32 +++
 drivers/gpu/drm/radeon/cikd.h             |  222 ++++++++++++++++
 drivers/gpu/drm/radeon/radeon_cs.c        |    4 +-
 6 files changed, 899 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.c
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.h
drivers/gpu/drm/radeon/Makefile +1 -1
index 88d0601..292fd25 100644
@@ -76,7 +76,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
-	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o
+	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
drivers/gpu/drm/radeon/cik.c +395 -0

407 lines not on this page · raw message

drivers/gpu/drm/radeon/cik_blit_shaders.c new file +246 -0

246 lines not on this page · raw message

drivers/gpu/drm/radeon/cik_blit_shaders.h new file +32 -0
new file mode 100644
index 0000000..dfe7314
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CIK_BLIT_SHADERS_H
+#define CIK_BLIT_SHADERS_H
+
+extern const u32 cik_default_state[];
+
+extern const u32 cik_default_size;
+
+#endif
drivers/gpu/drm/radeon/cikd.h +222 -0

249 lines not on this page · raw message

drivers/gpu/drm/radeon/radeon_cs.c +3 -1
index 7e265a5..cf71734 100644
@@ -121,7 +121,9 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
 		p->ring = RADEON_RING_TYPE_GFX_INDEX;
 		break;
 	case RADEON_CS_RING_COMPUTE:
-		if (p->rdev->family >= CHIP_TAHITI) {
+		if (p->rdev->family >= CHIP_BONAIRE)
+			p->ring = RADEON_RING_TYPE_GFX_INDEX;
+		else if (p->rdev->family >= CHIP_TAHITI) {
 			if (p->priority > 0)
 				p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
 			else
Signature · 1 line
1.7.7.5
#14 lore raw

PATCH 14/165 drm/radeon: add IB and fence dispatch functions for CIK gfx (v7)

In reply to [email protected]

From: Alex Deucher <[email protected]>

For gfx ring only. Compute is still todo.

v2: add documentation
v3: update to latest reset changes, integrate emit update patch.
v4: fix count on wait_reg_mem for HDP flush
v5: use old hdp flush method for fence
v6: set valid bit for IB
v7: cleanup for release

---
 drivers/gpu/drm/radeon/cik.c  |  134 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |  120 +++++++++++++++++++++++++++++++++++-
 2 files changed, 251 insertions(+), 3 deletions(-)
drivers/gpu/drm/radeon/cik.c +134 -0
index 5712526..0b9c3c9 100644
@@ -1493,6 +1493,140 @@ static void cik_gpu_init(struct radeon_device *rdev)
 }
 
 /*
+ * GPU scratch registers helpers function.
+ */
+/**
+ * cik_scratch_init - setup driver info for CP scratch regs
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the number and offset of the CP scratch registers.
+ * NOTE: use of CP scratch registers is a legacy inferface and
+ * is not used by default on newer asics (r6xx+).  On newer asics,
+ * memory buffers are used for fences rather than scratch regs.
+ */
+static void cik_scratch_init(struct radeon_device *rdev)
+{
+	int i;
+
+	rdev->scratch.num_reg = 7;
+	rdev->scratch.reg_base = SCRATCH_REG0;
+	for (i = 0; i < rdev->scratch.num_reg; i++) {
+		rdev->scratch.free[i] = true;
+		rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
+	}
+}
+
+/**
+ * cik_fence_ring_emit - emit a fence on the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Emits a fence sequnce number on the gfx ring and flushes
+ * GPU caches.
+ */
+void cik_fence_ring_emit(struct radeon_device *rdev,
+			 struct radeon_fence *fence)
+{
+	struct radeon_ring *ring = &rdev->ring[fence->ring];
+	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+	/* EVENT_WRITE_EOP - flush caches, send int */
+	radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+	radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+				 EOP_TC_ACTION_EN |
+				 EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+				 EVENT_INDEX(5)));
+	radeon_ring_write(ring, addr & 0xfffffffc);
+	radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | DATA_SEL(1) | INT_SEL(2));
+	radeon_ring_write(ring, fence->seq);
+	radeon_ring_write(ring, 0);
+	/* HDP flush */
+	/* We should be using the new WAIT_REG_MEM special op packet here
+	 * but it causes the CP to hang
+	 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 0);
+}
+
+void cik_semaphore_ring_emit(struct radeon_device *rdev,
+			     struct radeon_ring *ring,
+			     struct radeon_semaphore *semaphore,
+			     bool emit_wait)
+{
+	uint64_t addr = semaphore->gpu_addr;
+	unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
+
+	radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1));
+	radeon_ring_write(ring, addr & 0xffffffff);
+	radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel);
+}
+
+/*
+ * IB stuff
+ */
+/**
+ * cik_ring_ib_execute - emit an IB (Indirect Buffer) on the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ * @ib: radeon indirect buffer object
+ *
+ * Emits an DE (drawing engine) or CE (constant engine) IB
+ * on the gfx ring.  IBs are usually generated by userspace
+ * acceleration drivers and submitted to the kernel for
+ * sheduling on the ring.  This function schedules the IB
+ * on the gfx ring for execution by the GPU.
+ */
+void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+	struct radeon_ring *ring = &rdev->ring[ib->ring];
+	u32 header, control = INDIRECT_BUFFER_VALID;
+
+	if (ib->is_const_ib) {
+		/* set switch buffer packet before const IB */
+		radeon_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+		radeon_ring_write(ring, 0);
+
+		header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
+	} else {
+		u32 next_rptr;
+		if (ring->rptr_save_reg) {
+			next_rptr = ring->wptr + 3 + 4;
+			radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
+			radeon_ring_write(ring, ((ring->rptr_save_reg -
+						  PACKET3_SET_UCONFIG_REG_START) >> 2));
+			radeon_ring_write(ring, next_rptr);
+		} else if (rdev->wb.enabled) {
+			next_rptr = ring->wptr + 5 + 4;
+			radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+			radeon_ring_write(ring, WRITE_DATA_DST_SEL(1));
+			radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+			radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+			radeon_ring_write(ring, next_rptr);
+		}
+
+		header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+	}
+
+	control |= ib->length_dw |
+		(ib->vm ? (ib->vm->id << 24) : 0);
+
+	radeon_ring_write(ring, header);
+	radeon_ring_write(ring,
+#ifdef __BIG_ENDIAN
+			  (2 << 0) |
+#endif
+			  (ib->gpu_addr & 0xFFFFFFFC));
+	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+	radeon_ring_write(ring, control);
+}
+
+/*
  * CP.
  * On CIK, gfx and compute now have independant command processors.
  *
drivers/gpu/drm/radeon/cikd.h +117 -3

170 lines not on this page · raw message

Signature · 1 line
1.7.7.5
#15 lore raw

PATCH 15/165 drm/radeon: add ring and IB tests for CIK (v3)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: add documenation
v3: update the latest ib changes

---
 drivers/gpu/drm/radeon/cik.c |  114 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 114 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +114 -0
index 0b9c3c9..0cf04f3 100644
@@ -1518,6 +1518,57 @@ static void cik_scratch_init(struct radeon_device *rdev)
 }
 
 /**
+ * cik_ring_test - basic gfx ring test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Allocate a scratch register and write to it using the gfx ring (CIK).
+ * Provides a basic gfx ring test to verify that the ring is working.
+ * Used by cik_cp_gfx_resume();
+ * Returns 0 on success, error on failure.
+ */
+int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	uint32_t scratch;
+	uint32_t tmp = 0;
+	unsigned i;
+	int r;
+
+	r = radeon_scratch_get(rdev, &scratch);
+	if (r) {
+		DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r);
+		return r;
+	}
+	WREG32(scratch, 0xCAFEDEAD);
+	r = radeon_ring_lock(rdev, ring, 3);
+	if (r) {
+		DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", ring->idx, r);
+		radeon_scratch_free(rdev, scratch);
+		return r;
+	}
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
+	radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
+	radeon_ring_write(ring, 0xDEADBEEF);
+	radeon_ring_unlock_commit(rdev, ring);
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = RREG32(scratch);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+	} else {
+		DRM_ERROR("radeon: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
+			  ring->idx, scratch, tmp);
+		r = -EINVAL;
+	}
+	radeon_scratch_free(rdev, scratch);
+	return r;
+}
+
+/**
  * cik_fence_ring_emit - emit a fence on the gfx ring
  *
  * @rdev: radeon_device pointer
@@ -1626,6 +1677,69 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 	radeon_ring_write(ring, control);
 }
 
+/**
+ * cik_ib_test - basic gfx ring IB test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Allocate an IB and execute it on the gfx ring (CIK).
+ * Provides a basic gfx ring test to verify that IBs are working.
+ * Returns 0 on success, error on failure.
+ */
+int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	struct radeon_ib ib;
+	uint32_t scratch;
+	uint32_t tmp = 0;
+	unsigned i;
+	int r;
+
+	r = radeon_scratch_get(rdev, &scratch);
+	if (r) {
+		DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r);
+		return r;
+	}
+	WREG32(scratch, 0xCAFEDEAD);
+	r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
+	if (r) {
+		DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+		return r;
+	}
+	ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
+	ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2);
+	ib.ptr[2] = 0xDEADBEEF;
+	ib.length_dw = 3;
+	r = radeon_ib_schedule(rdev, &ib, NULL);
+	if (r) {
+		radeon_scratch_free(rdev, scratch);
+		radeon_ib_free(rdev, &ib);
+		DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+		return r;
+	}
+	r = radeon_fence_wait(ib.fence, false);
+	if (r) {
+		DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+		return r;
+	}
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = RREG32(scratch);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
+	} else {
+		DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n",
+			  scratch, tmp);
+		r = -EINVAL;
+	}
+	radeon_scratch_free(rdev, scratch);
+	radeon_ib_free(rdev, &ib);
+	return r;
+}
+
 /*
  * CP.
  * On CIK, gfx and compute now have independant command processors.
Signature · 1 line
1.7.7.5
#16 lore raw

PATCH 16/165 drm/radeon: implement async vm_flush for the CP (v7)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Update the page table base address and flush the
VM TLB using the CP.

v2: update for 2 level PTs
v3: use new packet for invalidate
v4: update SH_MEM* regs when flushing the VM
v5: add pfp sync, go back to old style vm TLB invalidate
v6: fix hdp flush packet count
v7: use old style HDP flush

---
 drivers/gpu/drm/radeon/cik.c |   79 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 79 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +79 -0
index 0cf04f3..ba242eb 100644
@@ -2698,3 +2698,82 @@ void cik_vm_fini(struct radeon_device *rdev)
 {
 }
 
+/**
+ * cik_vm_flush - cik vm flush using the CP
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using the CP (CIK).
+ */
+void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+{
+	struct radeon_ring *ring = &rdev->ring[ridx];
+
+	if (vm == NULL)
+		return;
+
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	if (vm->id < 8) {
+		radeon_ring_write(ring,
+				  (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+	} else {
+		radeon_ring_write(ring,
+				  (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+	}
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+
+	/* update SH_MEM_* regs */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, VMID(vm->id));
+
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, SH_MEM_BASES >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, 0); /* SH_MEM_BASES */
+	radeon_ring_write(ring, 0); /* SH_MEM_CONFIG */
+	radeon_ring_write(ring, 1); /* SH_MEM_APE1_BASE */
+	radeon_ring_write(ring, 0); /* SH_MEM_APE1_LIMIT */
+
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, VMID(0));
+
+	/* HDP flush */
+	/* We should be using the WAIT_REG_MEM packet here like in
+	 * cik_fence_ring_emit(), but it causes the CP to hang in this
+	 * context...
+	 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 0);
+
+	/* bits 0-15 are the VM contexts0-15 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 1 << vm->id);
+
+	/* sync PFP to ME, otherwise we might get invalid PFP reads */
+	radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+	radeon_ring_write(ring, 0x0);
+}
+
Signature · 1 line
1.7.7.5
#17 lore raw

PATCH 17/165 drm/radeon: Add support for RLC init on CIK (v4)

In reply to [email protected]

From: Alex Deucher <[email protected]>

RLC handles the interrupt controller and other tasks on the GPU.

v2: add documentation
v3: update programming sequence
v4: additional setup

---
 drivers/gpu/drm/radeon/cik.c  |  142 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   47 ++++++++++++++
 2 files changed, 189 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +142 -0
index ba242eb..a44ede6 100644
@@ -2777,3 +2777,145 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 	radeon_ring_write(ring, 0x0);
 }
 
+/*
+ * RLC
+ * The RLC is a multi-purpose microengine that handles a
+ * variety of functions, the most important of which is
+ * the interrupt controller.
+ */
+/**
+ * cik_rlc_stop - stop the RLC ME
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Halt the RLC ME (MicroEngine) (CIK).
+ */
+static void cik_rlc_stop(struct radeon_device *rdev)
+{
+	int i, j, k;
+	u32 mask, tmp;
+
+	tmp = RREG32(CP_INT_CNTL_RING0);
+	tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	WREG32(CP_INT_CNTL_RING0, tmp);
+
+	RREG32(CB_CGTT_SCLK_CTRL);
+	RREG32(CB_CGTT_SCLK_CTRL);
+	RREG32(CB_CGTT_SCLK_CTRL);
+	RREG32(CB_CGTT_SCLK_CTRL);
+
+	tmp = RREG32(RLC_CGCG_CGLS_CTRL) & 0xfffffffc;
+	WREG32(RLC_CGCG_CGLS_CTRL, tmp);
+
+	WREG32(RLC_CNTL, 0);
+
+	for (i = 0; i < rdev->config.cik.max_shader_engines; i++) {
+		for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) {
+			cik_select_se_sh(rdev, i, j);
+			for (k = 0; k < rdev->usec_timeout; k++) {
+				if (RREG32(RLC_SERDES_CU_MASTER_BUSY) == 0)
+					break;
+				udelay(1);
+			}
+		}
+	}
+	cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+
+	mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY;
+	for (k = 0; k < rdev->usec_timeout; k++) {
+		if ((RREG32(RLC_SERDES_NONCU_MASTER_BUSY) & mask) == 0)
+			break;
+		udelay(1);
+	}
+}
+
+/**
+ * cik_rlc_start - start the RLC ME
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Unhalt the RLC ME (MicroEngine) (CIK).
+ */
+static void cik_rlc_start(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	WREG32(RLC_CNTL, RLC_ENABLE);
+
+	tmp = RREG32(CP_INT_CNTL_RING0);
+	tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	WREG32(CP_INT_CNTL_RING0, tmp);
+
+	udelay(50);
+}
+
+/**
+ * cik_rlc_resume - setup the RLC hw
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Initialize the RLC registers, load the ucode,
+ * and start the RLC (CIK).
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_rlc_resume(struct radeon_device *rdev)
+{
+	u32 i, size;
+	u32 clear_state_info[3];
+	const __be32 *fw_data;
+
+	if (!rdev->rlc_fw)
+		return -EINVAL;
+
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+	default:
+		size = BONAIRE_RLC_UCODE_SIZE;
+		break;
+	case CHIP_KAVERI:
+		size = KV_RLC_UCODE_SIZE;
+		break;
+	case CHIP_KABINI:
+		size = KB_RLC_UCODE_SIZE;
+		break;
+	}
+
+	cik_rlc_stop(rdev);
+
+	WREG32(GRBM_SOFT_RESET, SOFT_RESET_RLC);
+	RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(GRBM_SOFT_RESET, 0);
+	RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+
+	WREG32(RLC_LB_CNTR_INIT, 0);
+	WREG32(RLC_LB_CNTR_MAX, 0x00008000);
+
+	cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+	WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
+	WREG32(RLC_LB_PARAMS, 0x00600408);
+	WREG32(RLC_LB_CNTL, 0x80000004);
+
+	WREG32(RLC_MC_CNTL, 0);
+	WREG32(RLC_UCODE_CNTL, 0);
+
+	fw_data = (const __be32 *)rdev->rlc_fw->data;
+		WREG32(RLC_GPM_UCODE_ADDR, 0);
+	for (i = 0; i < size; i++)
+		WREG32(RLC_GPM_UCODE_DATA, be32_to_cpup(fw_data++));
+	WREG32(RLC_GPM_UCODE_ADDR, 0);
+
+	/* XXX */
+	clear_state_info[0] = 0;//upper_32_bits(rdev->rlc.save_restore_gpu_addr);
+	clear_state_info[1] = 0;//rdev->rlc.save_restore_gpu_addr;
+	clear_state_info[2] = 0;//cik_default_size;
+	WREG32(RLC_GPM_SCRATCH_ADDR, 0x3d);
+	for (i = 0; i < 3; i++)
+		WREG32(RLC_GPM_SCRATCH_DATA, clear_state_info[i]);
+	WREG32(RLC_DRIVER_DMA_STATUS, 0);
+
+	cik_rlc_start(rdev);
+
+	return 0;
+}
drivers/gpu/drm/radeon/cikd.h +47 -0

63 lines not on this page · raw message

Signature · 1 line
1.7.7.5
#18 lore raw

PATCH 18/165 drm/radeon: add support for interrupts on CIK (v5)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Todo:
- handle interrupts for compute queues

v2: add documentation
v3: update to latest reset code
v4: update to latest illegal CP handling
v5: fix missing break in interrupt handler switch statement

---
 drivers/gpu/drm/radeon/cik.c    |  840 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h   |  170 ++++++++
 drivers/gpu/drm/radeon/radeon.h |   11 +
 3 files changed, 1021 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +840 -0
index a44ede6..72c7e83 100644
@@ -62,6 +62,8 @@ MODULE_FIRMWARE("radeon/KABINI_ce.bin");
 MODULE_FIRMWARE("radeon/KABINI_mec.bin");
 MODULE_FIRMWARE("radeon/KABINI_rlc.bin");
 
+extern int r600_ih_ring_alloc(struct radeon_device *rdev);
+extern void r600_ih_ring_fini(struct radeon_device *rdev);
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
@@ -2919,3 +2921,841 @@ static int cik_rlc_resume(struct radeon_device *rdev)
 
 	return 0;
 }
+
+/*
+ * Interrupts
+ * Starting with r6xx, interrupts are handled via a ring buffer.
+ * Ring buffers are areas of GPU accessible memory that the GPU
+ * writes interrupt vectors into and the host reads vectors out of.
+ * There is a rptr (read pointer) that determines where the
+ * host is currently reading, and a wptr (write pointer)
+ * which determines where the GPU has written.  When the
+ * pointers are equal, the ring is idle.  When the GPU
+ * writes vectors to the ring buffer, it increments the
+ * wptr.  When there is an interrupt, the host then starts
+ * fetching commands and processing them until the pointers are
+ * equal again at which point it updates the rptr.
+ */
+
+/**
+ * cik_enable_interrupts - Enable the interrupt ring buffer
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable the interrupt ring buffer (CIK).
+ */
+static void cik_enable_interrupts(struct radeon_device *rdev)
+{
+	u32 ih_cntl = RREG32(IH_CNTL);
+	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+
+	ih_cntl |= ENABLE_INTR;
+	ih_rb_cntl |= IH_RB_ENABLE;
+	WREG32(IH_CNTL, ih_cntl);
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+	rdev->ih.enabled = true;
+}
+
+/**
+ * cik_disable_interrupts - Disable the interrupt ring buffer
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable the interrupt ring buffer (CIK).
+ */
+static void cik_disable_interrupts(struct radeon_device *rdev)
+{
+	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+	u32 ih_cntl = RREG32(IH_CNTL);
+
+	ih_rb_cntl &= ~IH_RB_ENABLE;
+	ih_cntl &= ~ENABLE_INTR;
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+	WREG32(IH_CNTL, ih_cntl);
+	/* set rptr, wptr to 0 */
+	WREG32(IH_RB_RPTR, 0);
+	WREG32(IH_RB_WPTR, 0);
+	rdev->ih.enabled = false;
+	rdev->ih.rptr = 0;
+}
+
+/**
+ * cik_disable_interrupt_state - Disable all interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Clear all interrupt enable bits used by the driver (CIK).
+ */
+static void cik_disable_interrupt_state(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	/* gfx ring */
+	WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	/* compute queues */
+	WREG32(CP_ME1_PIPE0_INT_CNTL, 0);
+	WREG32(CP_ME1_PIPE1_INT_CNTL, 0);
+	WREG32(CP_ME1_PIPE2_INT_CNTL, 0);
+	WREG32(CP_ME1_PIPE3_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE0_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE1_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE2_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE3_INT_CNTL, 0);
+	/* grbm */
+	WREG32(GRBM_INT_CNTL, 0);
+	/* vline/vblank, etc. */
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+	if (rdev->num_crtc >= 4) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+	}
+
+	/* dac hotplug */
+	WREG32(DAC_AUTODETECT_INT_CONTROL, 0);
+
+	/* digital hotplug */
+	tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD1_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD2_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD3_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD4_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD5_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD6_INT_CONTROL, tmp);
+
+}
+
+/**
+ * cik_irq_init - init and enable the interrupt ring
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Allocate a ring buffer for the interrupt controller,
+ * enable the RLC, disable interrupts, enable the IH
+ * ring buffer and enable it (CIK).
+ * Called at device load and reume.
+ * Returns 0 for success, errors for failure.
+ */
+static int cik_irq_init(struct radeon_device *rdev)
+{
+	int ret = 0;
+	int rb_bufsz;
+	u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
+
+	/* allocate ring */
+	ret = r600_ih_ring_alloc(rdev);
+	if (ret)
+		return ret;
+
+	/* disable irqs */
+	cik_disable_interrupts(rdev);
+
+	/* init rlc */
+	ret = cik_rlc_resume(rdev);
+	if (ret) {
+		r600_ih_ring_fini(rdev);
+		return ret;
+	}
+
+	/* setup interrupt control */
+	/* XXX this should actually be a bus address, not an MC address. same on older asics */
+	WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8);
+	interrupt_cntl = RREG32(INTERRUPT_CNTL);
+	/* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi
+	 * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN
+	 */
+	interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
+	/* IH_REQ_NONSNOOP_EN=1 if ring is in non-cacheable memory, e.g., vram */
+	interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
+	WREG32(INTERRUPT_CNTL, interrupt_cntl);
+
+	WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8);
+	rb_bufsz = drm_order(rdev->ih.ring_size / 4);
+
+	ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
+		      IH_WPTR_OVERFLOW_CLEAR |
+		      (rb_bufsz << 1));
+
+	if (rdev->wb.enabled)
+		ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;
+
+	/* set the writeback address whether it's enabled or not */
+	WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF);
+
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+
+	/* set rptr, wptr to 0 */
+	WREG32(IH_RB_RPTR, 0);
+	WREG32(IH_RB_WPTR, 0);
+
+	/* Default settings for IH_CNTL (disabled at first) */
+	ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0);
+	/* RPTR_REARM only works if msi's are enabled */
+	if (rdev->msi_enabled)
+		ih_cntl |= RPTR_REARM;
+	WREG32(IH_CNTL, ih_cntl);
+
+	/* force the active interrupt state to all disabled */
+	cik_disable_interrupt_state(rdev);
+
+	pci_set_master(rdev->pdev);
+
+	/* enable irqs */
+	cik_enable_interrupts(rdev);
+
+	return ret;
+}
+
+/**
+ * cik_irq_set - enable/disable interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable interrupt sources on the GPU (vblanks, hpd,
+ * etc.) (CIK).
+ * Returns 0 for success, errors for failure.
+ */
+int cik_irq_set(struct radeon_device *rdev)
+{
+	u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE |
+		PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
+	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
+	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
+	u32 grbm_int_cntl = 0;
+
+	if (!rdev->irq.installed) {
+		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
+		return -EINVAL;
+	}
+	/* don't enable anything if the ih is disabled */
+	if (!rdev->ih.enabled) {
+		cik_disable_interrupts(rdev);
+		/* force the active interrupt state to all disabled */
+		cik_disable_interrupt_state(rdev);
+		return 0;
+	}
+
+	hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+
+	/* enable CP interrupts on all rings */
+	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
+		DRM_DEBUG("cik_irq_set: sw int gfx\n");
+		cp_int_cntl |= TIME_STAMP_INT_ENABLE;
+	}
+	/* TODO: compute queues! */
+	/* CP_ME[1-2]_PIPE[0-3]_INT_CNTL */
+
+	if (rdev->irq.crtc_vblank_int[0] ||
+	    atomic_read(&rdev->irq.pflip[0])) {
+		DRM_DEBUG("cik_irq_set: vblank 0\n");
+		crtc1 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[1] ||
+	    atomic_read(&rdev->irq.pflip[1])) {
+		DRM_DEBUG("cik_irq_set: vblank 1\n");
+		crtc2 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[2] ||
+	    atomic_read(&rdev->irq.pflip[2])) {
+		DRM_DEBUG("cik_irq_set: vblank 2\n");
+		crtc3 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[3] ||
+	    atomic_read(&rdev->irq.pflip[3])) {
+		DRM_DEBUG("cik_irq_set: vblank 3\n");
+		crtc4 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[4] ||
+	    atomic_read(&rdev->irq.pflip[4])) {
+		DRM_DEBUG("cik_irq_set: vblank 4\n");
+		crtc5 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[5] ||
+	    atomic_read(&rdev->irq.pflip[5])) {
+		DRM_DEBUG("cik_irq_set: vblank 5\n");
+		crtc6 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.hpd[0]) {
+		DRM_DEBUG("cik_irq_set: hpd 1\n");
+		hpd1 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[1]) {
+		DRM_DEBUG("cik_irq_set: hpd 2\n");
+		hpd2 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[2]) {
+		DRM_DEBUG("cik_irq_set: hpd 3\n");
+		hpd3 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[3]) {
+		DRM_DEBUG("cik_irq_set: hpd 4\n");
+		hpd4 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[4]) {
+		DRM_DEBUG("cik_irq_set: hpd 5\n");
+		hpd5 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[5]) {
+		DRM_DEBUG("cik_irq_set: hpd 6\n");
+		hpd6 |= DC_HPDx_INT_EN;
+	}
+
+	WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+
+	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
+
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
+	if (rdev->num_crtc >= 4) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
+	}
+
+	WREG32(DC_HPD1_INT_CONTROL, hpd1);
+	WREG32(DC_HPD2_INT_CONTROL, hpd2);
+	WREG32(DC_HPD3_INT_CONTROL, hpd3);
+	WREG32(DC_HPD4_INT_CONTROL, hpd4);
+	WREG32(DC_HPD5_INT_CONTROL, hpd5);
+	WREG32(DC_HPD6_INT_CONTROL, hpd6);
+
+	return 0;
+}
+
+/**
+ * cik_irq_ack - ack interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Ack interrupt sources on the GPU (vblanks, hpd,
+ * etc.) (CIK).  Certain interrupts sources are sw
+ * generated and do not require an explicit ack.
+ */
+static inline void cik_irq_ack(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	rdev->irq.stat_regs.cik.disp_int = RREG32(DISP_INTERRUPT_STATUS);
+	rdev->irq.stat_regs.cik.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
+	rdev->irq.stat_regs.cik.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
+	rdev->irq.stat_regs.cik.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
+	rdev->irq.stat_regs.cik.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
+	rdev->irq.stat_regs.cik.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
+	rdev->irq.stat_regs.cik.disp_int_cont6 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE6);
+
+	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)
+		WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
+	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT)
+		WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
+	if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
+		WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
+	if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT)
+		WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
+
+	if (rdev->num_crtc >= 4) {
+		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
+	}
+
+	if (rdev->num_crtc >= 6) {
+		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
+	}
+
+	if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) {
+		tmp = RREG32(DC_HPD1_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD1_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) {
+		tmp = RREG32(DC_HPD2_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD2_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+		tmp = RREG32(DC_HPD3_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD3_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+		tmp = RREG32(DC_HPD4_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD4_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD5_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD6_INT_CONTROL, tmp);
+	}
+}
+
+/**
+ * cik_irq_disable - disable interrupts
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts on the hw (CIK).
+ */
+static void cik_irq_disable(struct radeon_device *rdev)
+{
+	cik_disable_interrupts(rdev);
+	/* Wait and acknowledge irq */
+	mdelay(1);
+	cik_irq_ack(rdev);
+	cik_disable_interrupt_state(rdev);
+}
+
+/**
+ * cik_irq_disable - disable interrupts for suspend
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts and stop the RLC (CIK).
+ * Used for suspend.
+ */
+static void cik_irq_suspend(struct radeon_device *rdev)
+{
+	cik_irq_disable(rdev);
+	cik_rlc_stop(rdev);
+}
+
+/**
+ * cik_irq_fini - tear down interrupt support
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts on the hw and free the IH ring
+ * buffer (CIK).
+ * Used for driver unload.
+ */
+static void cik_irq_fini(struct radeon_device *rdev)
+{
+	cik_irq_suspend(rdev);
+	r600_ih_ring_fini(rdev);
+}
+
+/**
+ * cik_get_ih_wptr - get the IH ring buffer wptr
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Get the IH ring buffer wptr from either the register
+ * or the writeback memory buffer (CIK).  Also check for
+ * ring buffer overflow and deal with it.
+ * Used by cik_irq_process().
+ * Returns the value of the wptr.
+ */
+static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
+{
+	u32 wptr, tmp;
+
+	if (rdev->wb.enabled)
+		wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]);
+	else
+		wptr = RREG32(IH_RB_WPTR);
+
+	if (wptr & RB_OVERFLOW) {
+		/* When a ring buffer overflow happen start parsing interrupt
+		 * from the last not overwritten vector (wptr + 16). Hopefully
+		 * this should allow us to catchup.
+		 */
+		dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n",
+			wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask);
+		rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
+		tmp = RREG32(IH_RB_CNTL);
+		tmp |= IH_WPTR_OVERFLOW_CLEAR;
+		WREG32(IH_RB_CNTL, tmp);
+	}
+	return (wptr & rdev->ih.ptr_mask);
+}
+
+/*        CIK IV Ring
+ * Each IV ring entry is 128 bits:
+ * [7:0]    - interrupt source id
+ * [31:8]   - reserved
+ * [59:32]  - interrupt source data
+ * [63:60]  - reserved
+ * [71:64]  - RINGID: ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0]
+ *            QUEUE_ID - for compute, which of the 8 queues owned by the dispatcher
+ *                     - for gfx, hw shader state (0=PS...5=LS, 6=CS)
+ *            ME_ID - 0 = gfx, 1 = first 4 CS pipes, 2 = second 4 CS pipes
+ *            PIPE_ID - ME0 0=3D
+ *                    - ME1&2 compute dispatcher (4 pipes each)
+ * [79:72]  - VMID
+ * [95:80]  - PASID
+ * [127:96] - reserved
+ */
+/**
+ * cik_irq_process - interrupt handler
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Interrupt hander (CIK).  Walk the IH ring,
+ * ack interrupts and schedule work to handle
+ * interrupt events.
+ * Returns irq process return code.
+ */
+int cik_irq_process(struct radeon_device *rdev)
+{
+	u32 wptr;
+	u32 rptr;
+	u32 src_id, src_data, ring_id;
+	u8 me_id, pipe_id, queue_id;
+	u32 ring_index;
+	bool queue_hotplug = false;
+	bool queue_reset = false;
+
+	if (!rdev->ih.enabled || rdev->shutdown)
+		return IRQ_NONE;
+
+	wptr = cik_get_ih_wptr(rdev);
+
+restart_ih:
+	/* is somebody else already processing irqs? */
+	if (atomic_xchg(&rdev->ih.lock, 1))
+		return IRQ_NONE;
+
+	rptr = rdev->ih.rptr;
+	DRM_DEBUG("cik_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
+
+	/* Order reading of wptr vs. reading of IH ring data */
+	rmb();
+
+	/* display interrupts */
+	cik_irq_ack(rdev);
+
+	while (rptr != wptr) {
+		/* wptr/rptr are in bytes! */
+		ring_index = rptr / 4;
+		src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+		src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
+		ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
+		/* XXX check the bitfield order! */
+		me_id = (ring_id & 0x60) >> 5;
+		pipe_id = (ring_id & 0x18) >> 3;
+		queue_id = (ring_id & 0x7) >> 0;
+
+		switch (src_id) {
+		case 1: /* D1 vblank/vline */
+			switch (src_data) {
+			case 0: /* D1 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[0]) {
+						drm_handle_vblank(rdev->ddev, 0);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[0]))
+						radeon_crtc_handle_flip(rdev, 0);
+					rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D1 vblank\n");
+				}
+				break;
+			case 1: /* D1 vline */
+				if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D1 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 2: /* D2 vblank/vline */
+			switch (src_data) {
+			case 0: /* D2 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[1]) {
+						drm_handle_vblank(rdev->ddev, 1);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[1]))
+						radeon_crtc_handle_flip(rdev, 1);
+					rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D2 vblank\n");
+				}
+				break;
+			case 1: /* D2 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D2 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 3: /* D3 vblank/vline */
+			switch (src_data) {
+			case 0: /* D3 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[2]) {
+						drm_handle_vblank(rdev->ddev, 2);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[2]))
+						radeon_crtc_handle_flip(rdev, 2);
+					rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D3 vblank\n");
+				}
+				break;
+			case 1: /* D3 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D3 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 4: /* D4 vblank/vline */
+			switch (src_data) {
+			case 0: /* D4 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[3]) {
+						drm_handle_vblank(rdev->ddev, 3);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[3]))
+						radeon_crtc_handle_flip(rdev, 3);
+					rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D4 vblank\n");
+				}
+				break;
+			case 1: /* D4 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D4 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 5: /* D5 vblank/vline */
+			switch (src_data) {
+			case 0: /* D5 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[4]) {
+						drm_handle_vblank(rdev->ddev, 4);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[4]))
+						radeon_crtc_handle_flip(rdev, 4);
+					rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D5 vblank\n");
+				}
+				break;
+			case 1: /* D5 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D5 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 6: /* D6 vblank/vline */
+			switch (src_data) {
+			case 0: /* D6 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[5]) {
+						drm_handle_vblank(rdev->ddev, 5);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[5]))
+						radeon_crtc_handle_flip(rdev, 5);
+					rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D6 vblank\n");
+				}
+				break;
+			case 1: /* D6 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D6 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 42: /* HPD hotplug */
+			switch (src_data) {
+			case 0:
+				if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD1\n");
+				}
+				break;
+			case 1:
+				if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD2\n");
+				}
+				break;
+			case 2:
+				if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD3\n");
+				}
+				break;
+			case 3:
+				if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD4\n");
+				}
+				break;
+			case 4:
+				if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD5\n");
+				}
+				break;
+			case 5:
+				if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD6\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 176: /* GFX RB CP_INT */
+		case 177: /* GFX IB CP_INT */
+			radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+			break;
+		case 181: /* CP EOP event */
+			DRM_DEBUG("IH: CP EOP\n");
+			switch (me_id) {
+			case 0:
+				radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+				break;
+			case 1:
+				/* XXX compute */
+				break;
+			case 2:
+				/* XXX compute */
+				break;
+			}
+			break;
+		case 184: /* CP Privileged reg access */
+			DRM_ERROR("Illegal register access in command stream\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x60) >> 5;
+			pipe_id = (ring_id & 0x18) >> 3;
+			queue_id = (ring_id & 0x7) >> 0;
+			switch (me_id) {
+			case 0:
+				/* This results in a full GPU reset, but all we need to do is soft
+				 * reset the CP for gfx
+				 */
+				queue_reset = true;
+				break;
+			case 1:
+				/* XXX compute */
+				break;
+			case 2:
+				/* XXX compute */
+				break;
+			}
+			break;
+		case 185: /* CP Privileged inst */
+			DRM_ERROR("Illegal instruction in command stream\n");
+			switch (me_id) {
+			case 0:
+				/* This results in a full GPU reset, but all we need to do is soft
+				 * reset the CP for gfx
+				 */
+				queue_reset = true;
+				break;
+			case 1:
+				/* XXX compute */
+				break;
+			case 2:
+				/* XXX compute */
+				break;
+			}
+			break;
+		case 233: /* GUI IDLE */
+			DRM_DEBUG("IH: GUI idle\n");
+			break;
+		default:
+			DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+			break;
+		}
+
+		/* wptr/rptr are in bytes! */
+		rptr += 16;
+		rptr &= rdev->ih.ptr_mask;
+	}
+	if (queue_hotplug)
+		schedule_work(&rdev->hotplug_work);
+	if (queue_reset)
+		schedule_work(&rdev->reset_work);
+	rdev->ih.rptr = rptr;
+	WREG32(IH_RB_RPTR, rdev->ih.rptr);
+	atomic_set(&rdev->ih.lock, 0);
+
+	/* make sure wptr hasn't changed while processing */
+	wptr = cik_get_ih_wptr(rdev);
+	if (wptr != rptr)
+		goto restart_ih;
+
+	return IRQ_HANDLED;
+}
drivers/gpu/drm/radeon/cikd.h +170 -0

196 lines not on this page · raw message

drivers/gpu/drm/radeon/radeon.h +11 -0
index 1c06c47..e09157b 100644
@@ -600,10 +600,21 @@ struct evergreen_irq_stat_regs {
 	u32 afmt_status6;
 };
 
+struct cik_irq_stat_regs {
+	u32 disp_int;
+	u32 disp_int_cont;
+	u32 disp_int_cont2;
+	u32 disp_int_cont3;
+	u32 disp_int_cont4;
+	u32 disp_int_cont5;
+	u32 disp_int_cont6;
+};
+
 union radeon_irq_stat_regs {
 	struct r500_irq_stat_regs r500;
 	struct r600_irq_stat_regs r600;
 	struct evergreen_irq_stat_regs evergreen;
+	struct cik_irq_stat_regs cik;
 };
 
 #define RADEON_MAX_HPD_PINS 6
Signature · 1 line
1.7.7.5
#19 lore raw

PATCH 19/165 drm/radeon/cik: log and handle VM page fault interrupts

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/cik.c  |   10 ++++++++++
 drivers/gpu/drm/radeon/cikd.h |    4 ++++
 2 files changed, 14 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +10 -0
index 72c7e83..b70f017 100644
@@ -3676,6 +3676,16 @@ restart_ih:
 				break;
 			}
 			break;
+		case 146:
+		case 147:
+			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
+			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
+				RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+				RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+			/* reset addr and status */
+			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
+			break;
 		case 176: /* GFX RB CP_INT */
 		case 177: /* GFX IB CP_INT */
 			radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
drivers/gpu/drm/radeon/cikd.h +4 -0
index a282168..cc4f28e 100644
@@ -95,6 +95,10 @@
 #define VM_INVALIDATE_REQUEST				0x1478
 #define VM_INVALIDATE_RESPONSE				0x147c
 
+#define	VM_CONTEXT1_PROTECTION_FAULT_STATUS		0x14DC
+
+#define	VM_CONTEXT1_PROTECTION_FAULT_ADDR		0x14FC
+
 #define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR	0x1518
 #define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR	0x151c
 
Signature · 1 line
1.7.7.5
#20 lore raw

PATCH 20/165 drm/radeon/cik: add support for sDMA dma engines (v8)

In reply to [email protected]

From: Alex Deucher <[email protected]>

CIK has new asynchronous DMA engines called sDMA (system DMA). Each engine supports 1 ring buffer for kernel and gfx and 2 userspace queues for compute.

TODO: fill in the compute setup.

v2: update to the latest reset code
v3: remove ib_parse
v4: fix copy_dma()
v5: drop WIP compute sDMA queues
v6: rebase
v7: endian fixes for IB
v8: cleanup for release

---
 drivers/gpu/drm/radeon/cik.c    |  745 ++++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/cikd.h   |  130 +++++++
 drivers/gpu/drm/radeon/radeon.h |    1 +
 3 files changed, 870 insertions(+), 6 deletions(-)
drivers/gpu/drm/radeon/cik.c +739 -6
index b70f017..931169e 100644
@@ -44,6 +44,9 @@
 #define KV_RLC_UCODE_SIZE 2560
 /* gddr controller */
 #define CIK_MC_UCODE_SIZE 7866
+/* sdma */
+#define CIK_SDMA_UCODE_SIZE 1050
+#define CIK_SDMA_UCODE_VERSION 64
 
 MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_me.bin");
@@ -51,16 +54,19 @@ MODULE_FIRMWARE("radeon/BONAIRE_ce.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_mec.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_mc.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_sdma.bin");
 MODULE_FIRMWARE("radeon/KAVERI_pfp.bin");
 MODULE_FIRMWARE("radeon/KAVERI_me.bin");
 MODULE_FIRMWARE("radeon/KAVERI_ce.bin");
 MODULE_FIRMWARE("radeon/KAVERI_mec.bin");
 MODULE_FIRMWARE("radeon/KAVERI_rlc.bin");
+MODULE_FIRMWARE("radeon/KAVERI_sdma.bin");
 MODULE_FIRMWARE("radeon/KABINI_pfp.bin");
 MODULE_FIRMWARE("radeon/KABINI_me.bin");
 MODULE_FIRMWARE("radeon/KABINI_ce.bin");
 MODULE_FIRMWARE("radeon/KABINI_mec.bin");
 MODULE_FIRMWARE("radeon/KABINI_rlc.bin");
+MODULE_FIRMWARE("radeon/KABINI_sdma.bin");
 
 extern int r600_ih_ring_alloc(struct radeon_device *rdev);
 extern void r600_ih_ring_fini(struct radeon_device *rdev);
@@ -198,7 +204,8 @@ static int cik_init_microcode(struct radeon_device *rdev)
 	struct platform_device *pdev;
 	const char *chip_name;
 	size_t pfp_req_size, me_req_size, ce_req_size,
-		mec_req_size, rlc_req_size, mc_req_size;
+		mec_req_size, rlc_req_size, mc_req_size,
+		sdma_req_size;
 	char fw_name[30];
 	int err;
 
@@ -220,6 +227,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
 		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4;
 		mc_req_size = CIK_MC_UCODE_SIZE * 4;
+		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
 		break;
 	case CHIP_KAVERI:
 		chip_name = "KAVERI";
@@ -228,6 +236,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		ce_req_size = CIK_CE_UCODE_SIZE * 4;
 		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
 		rlc_req_size = KV_RLC_UCODE_SIZE * 4;
+		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
 		break;
 	case CHIP_KABINI:
 		chip_name = "KABINI";
@@ -236,6 +245,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		ce_req_size = CIK_CE_UCODE_SIZE * 4;
 		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
 		rlc_req_size = KB_RLC_UCODE_SIZE * 4;
+		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
 		break;
 	default: BUG();
 	}
@@ -298,6 +308,17 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		err = -EINVAL;
 	}
 
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name);
+	err = request_firmware(&rdev->sdma_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->sdma_fw->size != sdma_req_size) {
+		printk(KERN_ERR
+		       "cik_sdma: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->sdma_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
 	/* No MC ucode on APUs */
 	if (!(rdev->flags & RADEON_IS_IGP)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
@@ -1425,6 +1446,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
 	WREG32(GB_ADDR_CONFIG, gb_addr_config);
 	WREG32(HDP_ADDR_CONFIG, gb_addr_config);
 	WREG32(DMIF_ADDR_CALC, gb_addr_config);
+	WREG32(SDMA0_TILING_CONFIG + SDMA0_REGISTER_OFFSET, gb_addr_config & 0x70);
+	WREG32(SDMA0_TILING_CONFIG + SDMA1_REGISTER_OFFSET, gb_addr_config & 0x70);
 
 	cik_tiling_mode_table_init(rdev);
 
@@ -2136,6 +2159,578 @@ static int cik_cp_resume(struct radeon_device *rdev)
 	return 0;
 }
 
+/*
+ * sDMA - System DMA
+ * Starting with CIK, the GPU has new asynchronous
+ * DMA engines.  These engines are used for compute
+ * and gfx.  There are two DMA engines (SDMA0, SDMA1)
+ * and each one supports 1 ring buffer used for gfx
+ * and 2 queues used for compute.
+ *
+ * The programming model is very similar to the CP
+ * (ring buffer, IBs, etc.), but sDMA has it's own
+ * packet format that is different from the PM4 format
+ * used by the CP. sDMA supports copying data, writing
+ * embedded data, solid fills, and a number of other
+ * things.  It also has support for tiling/detiling of
+ * buffers.
+ */
+/**
+ * cik_sdma_ring_ib_execute - Schedule an IB on the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @ib: IB object to schedule
+ *
+ * Schedule an IB in the DMA ring (CIK).
+ */
+void cik_sdma_ring_ib_execute(struct radeon_device *rdev,
+			      struct radeon_ib *ib)
+{
+	struct radeon_ring *ring = &rdev->ring[ib->ring];
+	u32 extra_bits = (ib->vm ? ib->vm->id : 0) & 0xf;
+
+	if (rdev->wb.enabled) {
+		u32 next_rptr = ring->wptr + 5;
+		while ((next_rptr & 7) != 4)
+			next_rptr++;
+		next_rptr += 4;
+		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+		radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+		radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+		radeon_ring_write(ring, 1); /* number of DWs to follow */
+		radeon_ring_write(ring, next_rptr);
+	}
+
+	/* IB packet must end on a 8 DW boundary */
+	while ((ring->wptr & 7) != 4)
+		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits));
+	radeon_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */
+	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xffffffff);
+	radeon_ring_write(ring, ib->length_dw);
+
+}
+
+/**
+ * cik_sdma_fence_ring_emit - emit a fence on the DMA ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Add a DMA fence packet to the ring to write
+ * the fence seq number and DMA trap packet to generate
+ * an interrupt if needed (CIK).
+ */
+void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
+			      struct radeon_fence *fence)
+{
+	struct radeon_ring *ring = &rdev->ring[fence->ring];
+	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+	u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+			  SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+	u32 ref_and_mask;
+
+	if (fence->ring == R600_RING_TYPE_DMA_INDEX)
+		ref_and_mask = SDMA0;
+	else
+		ref_and_mask = SDMA1;
+
+	/* write the fence */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0));
+	radeon_ring_write(ring, addr & 0xffffffff);
+	radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+	radeon_ring_write(ring, fence->seq);
+	/* generate an interrupt */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0));
+	/* flush HDP */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
+	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
+	radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
+	radeon_ring_write(ring, ref_and_mask); /* MASK */
+	radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+}
+
+/**
+ * cik_sdma_semaphore_ring_emit - emit a semaphore on the dma ring
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ * @semaphore: radeon semaphore object
+ * @emit_wait: wait or signal semaphore
+ *
+ * Add a DMA semaphore packet to the ring wait on or signal
+ * other rings (CIK).
+ */
+void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
+				  struct radeon_ring *ring,
+				  struct radeon_semaphore *semaphore,
+				  bool emit_wait)
+{
+	u64 addr = semaphore->gpu_addr;
+	u32 extra_bits = emit_wait ? 0 : SDMA_SEMAPHORE_EXTRA_S;
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SEMAPHORE, 0, extra_bits));
+	radeon_ring_write(ring, addr & 0xfffffff8);
+	radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+}
+
+/**
+ * cik_sdma_gfx_stop - stop the gfx async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the gfx async dma ring buffers (CIK).
+ */
+static void cik_sdma_gfx_stop(struct radeon_device *rdev)
+{
+	u32 rb_cntl, reg_offset;
+	int i;
+
+	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			reg_offset = SDMA0_REGISTER_OFFSET;
+		else
+			reg_offset = SDMA1_REGISTER_OFFSET;
+		rb_cntl = RREG32(SDMA0_GFX_RB_CNTL + reg_offset);
+		rb_cntl &= ~SDMA_RB_ENABLE;
+		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
+		WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
+	}
+}
+
+/**
+ * cik_sdma_rlc_stop - stop the compute async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the compute async dma queues (CIK).
+ */
+static void cik_sdma_rlc_stop(struct radeon_device *rdev)
+{
+	/* XXX todo */
+}
+
+/**
+ * cik_sdma_enable - stop the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable/disable the DMA MEs.
+ *
+ * Halt or unhalt the async dma engines (CIK).
+ */
+static void cik_sdma_enable(struct radeon_device *rdev, bool enable)
+{
+	u32 me_cntl, reg_offset;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			reg_offset = SDMA0_REGISTER_OFFSET;
+		else
+			reg_offset = SDMA1_REGISTER_OFFSET;
+		me_cntl = RREG32(SDMA0_ME_CNTL + reg_offset);
+		if (enable)
+			me_cntl &= ~SDMA_HALT;
+		else
+			me_cntl |= SDMA_HALT;
+		WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl);
+	}
+}
+
+/**
+ * cik_sdma_gfx_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the gfx DMA ring buffers and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_gfx_resume(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	u32 rb_cntl, ib_cntl;
+	u32 rb_bufsz;
+	u32 reg_offset, wb_offset;
+	int i, r;
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0) {
+			ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+			reg_offset = SDMA0_REGISTER_OFFSET;
+			wb_offset = R600_WB_DMA_RPTR_OFFSET;
+		} else {
+			ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+			reg_offset = SDMA1_REGISTER_OFFSET;
+			wb_offset = CAYMAN_WB_DMA1_RPTR_OFFSET;
+		}
+
+		WREG32(SDMA0_SEM_INCOMPLETE_TIMER_CNTL + reg_offset, 0);
+		WREG32(SDMA0_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0);
+
+		/* Set ring buffer size in dwords */
+		rb_bufsz = drm_order(ring->ring_size / 4);
+		rb_cntl = rb_bufsz << 1;
+#ifdef __BIG_ENDIAN
+		rb_cntl |= SDMA_RB_SWAP_ENABLE | SDMA_RPTR_WRITEBACK_SWAP_ENABLE;
+#endif
+		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
+
+		/* Initialize the ring buffer's read and write pointers */
+		WREG32(SDMA0_GFX_RB_RPTR + reg_offset, 0);
+		WREG32(SDMA0_GFX_RB_WPTR + reg_offset, 0);
+
+		/* set the wb address whether it's enabled or not */
+		WREG32(SDMA0_GFX_RB_RPTR_ADDR_HI + reg_offset,
+		       upper_32_bits(rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+		WREG32(SDMA0_GFX_RB_RPTR_ADDR_LO + reg_offset,
+		       ((rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC));
+
+		if (rdev->wb.enabled)
+			rb_cntl |= SDMA_RPTR_WRITEBACK_ENABLE;
+
+		WREG32(SDMA0_GFX_RB_BASE + reg_offset, ring->gpu_addr >> 8);
+		WREG32(SDMA0_GFX_RB_BASE_HI + reg_offset, ring->gpu_addr >> 40);
+
+		ring->wptr = 0;
+		WREG32(SDMA0_GFX_RB_WPTR + reg_offset, ring->wptr << 2);
+
+		ring->rptr = RREG32(SDMA0_GFX_RB_RPTR + reg_offset) >> 2;
+
+		/* enable DMA RB */
+		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl | SDMA_RB_ENABLE);
+
+		ib_cntl = SDMA_IB_ENABLE;
+#ifdef __BIG_ENDIAN
+		ib_cntl |= SDMA_IB_SWAP_ENABLE;
+#endif
+		/* enable DMA IBs */
+		WREG32(SDMA0_GFX_IB_CNTL + reg_offset, ib_cntl);
+
+		ring->ready = true;
+
+		r = radeon_ring_test(rdev, ring->idx, ring);
+		if (r) {
+			ring->ready = false;
+			return r;
+		}
+	}
+
+	radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+
+	return 0;
+}
+
+/**
+ * cik_sdma_rlc_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the compute DMA queues and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_rlc_resume(struct radeon_device *rdev)
+{
+	/* XXX todo */
+	return 0;
+}
+
+/**
+ * cik_sdma_load_microcode - load the sDMA ME ucode
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Loads the sDMA0/1 ucode.
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_sdma_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	int i;
+
+	if (!rdev->sdma_fw)
+		return -EINVAL;
+
+	/* stop the gfx rings and rlc compute queues */
+	cik_sdma_gfx_stop(rdev);
+	cik_sdma_rlc_stop(rdev);
+
+	/* halt the MEs */
+	cik_sdma_enable(rdev, false);
+
+	/* sdma0 */
+	fw_data = (const __be32 *)rdev->sdma_fw->data;
+	WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0);
+	for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++)
+		WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, be32_to_cpup(fw_data++));
+	WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION);
+
+	/* sdma1 */
+	fw_data = (const __be32 *)rdev->sdma_fw->data;
+	WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0);
+	for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++)
+		WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, be32_to_cpup(fw_data++));
+	WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION);
+
+	WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0);
+	WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0);
+	return 0;
+}
+
+/**
+ * cik_sdma_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the DMA engines and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Reset dma */
+	WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1);
+	RREG32(SRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(SRBM_SOFT_RESET, 0);
+	RREG32(SRBM_SOFT_RESET);
+
+	r = cik_sdma_load_microcode(rdev);
+	if (r)
+		return r;
+
+	/* unhalt the MEs */
+	cik_sdma_enable(rdev, true);
+
+	/* start the gfx rings and rlc compute queues */
+	r = cik_sdma_gfx_resume(rdev);
+	if (r)
+		return r;
+	r = cik_sdma_rlc_resume(rdev);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+/**
+ * cik_sdma_fini - tear down the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the async dma engines and free the rings (CIK).
+ */
+static void cik_sdma_fini(struct radeon_device *rdev)
+{
+	/* stop the gfx rings and rlc compute queues */
+	cik_sdma_gfx_stop(rdev);
+	cik_sdma_rlc_stop(rdev);
+	/* halt the MEs */
+	cik_sdma_enable(rdev, false);
+	radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
+	radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]);
+	/* XXX - compute dma queue tear down */
+}
+
+/**
+ * cik_copy_dma - copy pages using the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @src_offset: src GPU address
+ * @dst_offset: dst GPU address
+ * @num_gpu_pages: number of GPU pages to xfer
+ * @fence: radeon fence object
+ *
+ * Copy GPU paging using the DMA engine (CIK).
+ * Used by the radeon ttm implementation to move pages if
+ * registered as the asic copy callback.
+ */
+int cik_copy_dma(struct radeon_device *rdev,
+		 uint64_t src_offset, uint64_t dst_offset,
+		 unsigned num_gpu_pages,
+		 struct radeon_fence **fence)
+{
+	struct radeon_semaphore *sem = NULL;
+	int ring_index = rdev->asic->copy.dma_ring_index;
+	struct radeon_ring *ring = &rdev->ring[ring_index];
+	u32 size_in_bytes, cur_size_in_bytes;
+	int i, num_loops;
+	int r = 0;
+
+	r = radeon_semaphore_create(rdev, &sem);
+	if (r) {
+		DRM_ERROR("radeon: moving bo (%d).\n", r);
+		return r;
+	}
+
+	size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
+	num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
+	r = radeon_ring_lock(rdev, ring, num_loops * 7 + 14);
+	if (r) {
+		DRM_ERROR("radeon: moving bo (%d).\n", r);
+		radeon_semaphore_free(rdev, &sem, NULL);
+		return r;
+	}
+
+	if (radeon_fence_need_sync(*fence, ring->idx)) {
+		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
+					    ring->idx);
+		radeon_fence_note_sync(*fence, ring->idx);
+	} else {
+		radeon_semaphore_free(rdev, &sem, NULL);
+	}
+
+	for (i = 0; i < num_loops; i++) {
+		cur_size_in_bytes = size_in_bytes;
+		if (cur_size_in_bytes > 0x1fffff)
+			cur_size_in_bytes = 0x1fffff;
+		size_in_bytes -= cur_size_in_bytes;
+		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0));
+		radeon_ring_write(ring, cur_size_in_bytes);
+		radeon_ring_write(ring, 0); /* src/dst endian swap */
+		radeon_ring_write(ring, src_offset & 0xffffffff);
+		radeon_ring_write(ring, upper_32_bits(src_offset) & 0xffffffff);
+		radeon_ring_write(ring, dst_offset & 0xfffffffc);
+		radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xffffffff);
+		src_offset += cur_size_in_bytes;
+		dst_offset += cur_size_in_bytes;
+	}
+
+	r = radeon_fence_emit(rdev, fence, ring->idx);
+	if (r) {
+		radeon_ring_unlock_undo(rdev, ring);
+		return r;
+	}
+
+	radeon_ring_unlock_commit(rdev, ring);
+	radeon_semaphore_free(rdev, &sem, *fence);
+
+	return r;
+}
+
+/**
+ * cik_sdma_ring_test - simple async dma engine test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Test the DMA engine by writing using it to write an
+ * value to memory. (CIK).
+ * Returns 0 for success, error for failure.
+ */
+int cik_sdma_ring_test(struct radeon_device *rdev,
+		       struct radeon_ring *ring)
+{
+	unsigned i;
+	int r;
+	void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
+	u32 tmp;
+
+	if (!ptr) {
+		DRM_ERROR("invalid vram scratch pointer\n");
+		return -EINVAL;
+	}
+
+	tmp = 0xCAFEDEAD;
+	writel(tmp, ptr);
+
+	r = radeon_ring_lock(rdev, ring, 4);
+	if (r) {
+		DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r);
+		return r;
+	}
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+	radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc);
+	radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff);
+	radeon_ring_write(ring, 1); /* number of DWs to follow */
+	radeon_ring_write(ring, 0xDEADBEEF);
+	radeon_ring_unlock_commit(rdev, ring);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = readl(ptr);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+	} else {
+		DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
+			  ring->idx, tmp);
+		r = -EINVAL;
+	}
+	return r;
+}
+
+/**
+ * cik_sdma_ib_test - test an IB on the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Test a simple IB in the DMA ring (CIK).
+ * Returns 0 on success, error on failure.
+ */
+int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	struct radeon_ib ib;
+	unsigned i;
+	int r;
+	void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
+	u32 tmp = 0;
+
+	if (!ptr) {
+		DRM_ERROR("invalid vram scratch pointer\n");
+		return -EINVAL;
+	}
+
+	tmp = 0xCAFEDEAD;
+	writel(tmp, ptr);
+
+	r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
+	if (r) {
+		DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+		return r;
+	}
+
+	ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+	ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc;
+	ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff;
+	ib.ptr[3] = 1;
+	ib.ptr[4] = 0xDEADBEEF;
+	ib.length_dw = 5;
+
+	r = radeon_ib_schedule(rdev, &ib, NULL);
+	if (r) {
+		radeon_ib_free(rdev, &ib);
+		DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+		return r;
+	}
+	r = radeon_fence_wait(ib.fence, false);
+	if (r) {
+		DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+		return r;
+	}
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = readl(ptr);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
+	} else {
+		DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp);
+		r = -EINVAL;
+	}
+	radeon_ib_free(rdev, &ib);
+	return r;
+}
+
 /**
  * cik_gpu_is_lockup - check if the 3D engine is locked up
  *
@@ -2330,6 +2925,32 @@ int cik_asic_reset(struct radeon_device *rdev)
 	return cik_gfx_gpu_soft_reset(rdev);
 }
 
+/**
+ * cik_sdma_is_lockup - Check if the DMA engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the async DMA engine is locked up (CIK).
+ * Returns true if the engine appears to be locked up, false if not.
+ */
+bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	u32 dma_status_reg;
+
+	if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+	else
+		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
+	if (dma_status_reg & SDMA_IDLE) {
+		radeon_ring_lockup_update(ring);
+		return false;
+	}
+	/* force ring activities */
+	radeon_ring_force_activity(rdev, ring);
+	return radeon_ring_test_lockup(rdev, ring);
+}
+
 /* MC */
 /**
  * cik_mc_program - program the GPU memory controller
@@ -2588,10 +3209,17 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 	/* where to put LDS, scratch, GPUVM in FSA64 space */
 	for (i = 0; i < 16; i++) {
 		WREG32(SRBM_GFX_CNTL, VMID(i));
+		/* CP and shaders */
 		WREG32(SH_MEM_CONFIG, 0);
 		WREG32(SH_MEM_APE1_BASE, 1);
 		WREG32(SH_MEM_APE1_LIMIT, 0);
 		WREG32(SH_MEM_BASES, 0);
+		/* SDMA GFX */
+		WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA0_REGISTER_OFFSET, 0);
+		WREG32(SDMA0_GFX_APE1_CNTL + SDMA0_REGISTER_OFFSET, 0);
+		WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA1_REGISTER_OFFSET, 0);
+		WREG32(SDMA0_GFX_APE1_CNTL + SDMA1_REGISTER_OFFSET, 0);
+		/* XXX SDMA RLC - todo */
 	}
 	WREG32(SRBM_GFX_CNTL, 0);
 
@@ -2992,6 +3620,11 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)
 
 	/* gfx ring */
 	WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	/* sdma */
+	tmp = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
+	WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+	tmp = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
+	WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, tmp);
 	/* compute queues */
 	WREG32(CP_ME1_PIPE0_INT_CNTL, 0);
 	WREG32(CP_ME1_PIPE1_INT_CNTL, 0);
@@ -3132,6 +3765,7 @@ int cik_irq_set(struct radeon_device *rdev)
 	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
 	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
 	u32 grbm_int_cntl = 0;
+	u32 dma_cntl, dma_cntl1;
 
 	if (!rdev->irq.installed) {
 		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -3152,6 +3786,9 @@ int cik_irq_set(struct radeon_device *rdev)
 	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
 	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
 
+	dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
+	dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
+
 	/* enable CP interrupts on all rings */
 	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
 		DRM_DEBUG("cik_irq_set: sw int gfx\n");
@@ -3160,6 +3797,16 @@ int cik_irq_set(struct radeon_device *rdev)
 	/* TODO: compute queues! */
 	/* CP_ME[1-2]_PIPE[0-3]_INT_CNTL */
 
+	if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
+		DRM_DEBUG("cik_irq_set: sw int dma\n");
+		dma_cntl |= TRAP_ENABLE;
+	}
+
+	if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_DMA1_INDEX])) {
+		DRM_DEBUG("cik_irq_set: sw int dma1\n");
+		dma_cntl1 |= TRAP_ENABLE;
+	}
+
 	if (rdev->irq.crtc_vblank_int[0] ||
 	    atomic_read(&rdev->irq.pflip[0])) {
 		DRM_DEBUG("cik_irq_set: vblank 0\n");
@@ -3217,6 +3864,9 @@ int cik_irq_set(struct radeon_device *rdev)
 
 	WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
 
+	WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl);
+	WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1);
+
 	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
 
 	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
@@ -3410,12 +4060,18 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
  * [31:8]   - reserved
  * [59:32]  - interrupt source data
  * [63:60]  - reserved
- * [71:64]  - RINGID: ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0]
+ * [71:64]  - RINGID
+ *            CP:
+ *            ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0]
  *            QUEUE_ID - for compute, which of the 8 queues owned by the dispatcher
  *                     - for gfx, hw shader state (0=PS...5=LS, 6=CS)
  *            ME_ID - 0 = gfx, 1 = first 4 CS pipes, 2 = second 4 CS pipes
  *            PIPE_ID - ME0 0=3D
  *                    - ME1&2 compute dispatcher (4 pipes each)
+ *            SDMA:
+ *            INSTANCE_ID [1:0], QUEUE_ID[1:0]
+ *            INSTANCE_ID - 0 = sdma0, 1 = sdma1
+ *            QUEUE_ID - 0 = gfx, 1 = rlc0, 2 = rlc1
  * [79:72]  - VMID
  * [95:80]  - PASID
  * [127:96] - reserved
@@ -3465,10 +4121,6 @@ restart_ih:
 		src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
 		src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
 		ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
-		/* XXX check the bitfield order! */
-		me_id = (ring_id & 0x60) >> 5;
-		pipe_id = (ring_id & 0x18) >> 3;
-		queue_id = (ring_id & 0x7) >> 0;
 
 		switch (src_id) {
 		case 1: /* D1 vblank/vline */
@@ -3692,6 +4344,10 @@ restart_ih:
 			break;
 		case 181: /* CP EOP event */
 			DRM_DEBUG("IH: CP EOP\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x60) >> 5;
+			pipe_id = (ring_id & 0x18) >> 3;
+			queue_id = (ring_id & 0x7) >> 0;
 			switch (me_id) {
 			case 0:
 				radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
@@ -3727,6 +4383,10 @@ restart_ih:
 			break;
 		case 185: /* CP Privileged inst */
 			DRM_ERROR("Illegal instruction in command stream\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x60) >> 5;
+			pipe_id = (ring_id & 0x18) >> 3;
+			queue_id = (ring_id & 0x7) >> 0;
 			switch (me_id) {
 			case 0:
 				/* This results in a full GPU reset, but all we need to do is soft
@@ -3742,6 +4402,79 @@ restart_ih:
 				break;
 			}
 			break;
+		case 224: /* SDMA trap event */
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x3) >> 0;
+			queue_id = (ring_id & 0xc) >> 2;
+			DRM_DEBUG("IH: SDMA trap\n");
+			switch (me_id) {
+			case 0:
+				switch (queue_id) {
+				case 0:
+					radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
+					break;
+				case 1:
+					/* XXX compute */
+					break;
+				case 2:
+					/* XXX compute */
+					break;
+				}
+				break;
+			case 1:
+				switch (queue_id) {
+				case 0:
+					radeon_fence_process(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+					break;
+				case 1:
+					/* XXX compute */
+					break;
+				case 2:
+					/* XXX compute */
+					break;
+				}
+				break;
+			}
+			break;
+		case 241: /* SDMA Privileged inst */
+		case 247: /* SDMA Privileged inst */
+			DRM_ERROR("Illegal instruction in SDMA command stream\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x3) >> 0;
+			queue_id = (ring_id & 0xc) >> 2;
+			switch (me_id) {
+			case 0:
+				switch (queue_id) {
+				case 0:
+					queue_reset = true;
+					break;
+				case 1:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				case 2:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				}
+				break;
+			case 1:
+				switch (queue_id) {
+				case 0:
+					queue_reset = true;
+					break;
+				case 1:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				case 2:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				}
+				break;
+			}
+			break;
 		case 233: /* GUI IDLE */
 			DRM_DEBUG("IH: GUI idle\n");
 			break;
drivers/gpu/drm/radeon/cikd.h +130 -0

140 lines not on this page · raw message

drivers/gpu/drm/radeon/radeon.h +1 -0
index e09157b..919c4d8 100644
@@ -1726,6 +1726,7 @@ struct radeon_device {
 	const struct firmware *ce_fw;	/* SI CE firmware */
 	const struct firmware *uvd_fw;	/* UVD firmware */
 	const struct firmware *mec_fw;	/* CIK MEC firmware */
+	const struct firmware *sdma_fw;	/* CIK SDMA firmware */
 	struct r600_blit r600_blit;
 	struct r600_vram_scratch vram_scratch;
 	int msi_enabled; /* msi enabled */
Signature · 1 line
1.7.7.5
#21 lore raw

PATCH 21/165 drm/radeon: implement async vm_flush for the sDMA (v6)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Update the page table base address and flush the
VM TLB using the sDMA.

V2: update for 2 level PTs
V3: update vm flush
V4: update SH_MEM* regs
V5: switch back to old style VM TLB invalidate
V6: fix packet formatting

---
 drivers/gpu/drm/radeon/cik.c |   70 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +70 -0
index 931169e..3c18a63 100644
@@ -3407,6 +3407,76 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 	radeon_ring_write(ring, 0x0);
 }
 
+/**
+ * cik_dma_vm_flush - cik vm flush using sDMA
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using sDMA (CIK).
+ */
+void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+{
+	struct radeon_ring *ring = &rdev->ring[ridx];
+	u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+			  SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+	u32 ref_and_mask;
+
+	if (vm == NULL)
+		return;
+
+	if (ridx == R600_RING_TYPE_DMA_INDEX)
+		ref_and_mask = SDMA0;
+	else
+		ref_and_mask = SDMA1;
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	if (vm->id < 8) {
+		radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+	} else {
+		radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+	}
+	radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+
+	/* update SH_MEM_* regs */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, VMID(vm->id));
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_BASES >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_CONFIG >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_APE1_BASE >> 2);
+	radeon_ring_write(ring, 1);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_APE1_LIMIT >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, VMID(0));
+
+	/* flush HDP */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
+	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
+	radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
+	radeon_ring_write(ring, ref_and_mask); /* MASK */
+	radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+
+	/* flush TLB */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+	radeon_ring_write(ring, 1 << vm->id);
+}
+
 /*
  * RLC
  * The RLC is a multi-purpose microengine that handles a
Signature · 1 line
1.7.7.5
#22 lore raw

PATCH 22/165 drm/radeon/cik: add support for doing async VM pt updates (v5)

In reply to [email protected]

From: Alex Deucher <[email protected]>

Async page table updates using the sDMA engine. sDMA has a special packet for updating entries for contiguous pages that reduces overhead.

v2: add support for and use the CP for now.
v3: update for 2 level PTs
v4: rebase, fix DMA packet
v5: switch to using an IB

---
 drivers/gpu/drm/radeon/cik.c |  109 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 109 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +109 -0
index 3c18a63..cf1e0b1 100644
@@ -3408,6 +3408,115 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 }
 
 /**
+ * cik_vm_set_page - update the page tables using sDMA
+ *
+ * @rdev: radeon_device pointer
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @addr: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ * @flags: access flags
+ *
+ * Update the page tables using CP or sDMA (CIK).
+ */
+void cik_vm_set_page(struct radeon_device *rdev,
+		     struct radeon_ib *ib,
+		     uint64_t pe,
+		     uint64_t addr, unsigned count,
+		     uint32_t incr, uint32_t flags)
+{
+	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);
+	uint64_t value;
+	unsigned ndw;
+
+	if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) {
+		/* CP */
+		while (count) {
+			ndw = 2 + count * 2;
+			if (ndw > 0x3FFE)
+				ndw = 0x3FFE;
+
+			ib->ptr[ib->length_dw++] = PACKET3(PACKET3_WRITE_DATA, ndw);
+			ib->ptr[ib->length_dw++] = (WRITE_DATA_ENGINE_SEL(0) |
+						    WRITE_DATA_DST_SEL(1));
+			ib->ptr[ib->length_dw++] = pe;
+			ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+			for (; ndw > 2; ndw -= 2, --count, pe += 8) {
+				if (flags & RADEON_VM_PAGE_SYSTEM) {
+					value = radeon_vm_map_gart(rdev, addr);
+					value &= 0xFFFFFFFFFFFFF000ULL;
+				} else if (flags & RADEON_VM_PAGE_VALID) {
+					value = addr;
+				} else {
+					value = 0;
+				}
+				addr += incr;
+				value |= r600_flags;
+				ib->ptr[ib->length_dw++] = value;
+				ib->ptr[ib->length_dw++] = upper_32_bits(value);
+			}
+		}
+	} else {
+		/* DMA */
+		if (flags & RADEON_VM_PAGE_SYSTEM) {
+			while (count) {
+				ndw = count * 2;
+				if (ndw > 0xFFFFE)
+					ndw = 0xFFFFE;
+
+				/* for non-physically contiguous pages (system) */
+				ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+				ib->ptr[ib->length_dw++] = pe;
+				ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+				ib->ptr[ib->length_dw++] = ndw;
+				for (; ndw > 0; ndw -= 2, --count, pe += 8) {
+					if (flags & RADEON_VM_PAGE_SYSTEM) {
+						value = radeon_vm_map_gart(rdev, addr);
+						value &= 0xFFFFFFFFFFFFF000ULL;
+					} else if (flags & RADEON_VM_PAGE_VALID) {
+						value = addr;
+					} else {
+						value = 0;
+					}
+					addr += incr;
+					value |= r600_flags;
+					ib->ptr[ib->length_dw++] = value;
+					ib->ptr[ib->length_dw++] = upper_32_bits(value);
+				}
+			}
+		} else {
+			while (count) {
+				ndw = count;
+				if (ndw > 0x7FFFF)
+					ndw = 0x7FFFF;
+
+				if (flags & RADEON_VM_PAGE_VALID)
+					value = addr;
+				else
+					value = 0;
+				/* for physically contiguous pages (vram) */
+				ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0);
+				ib->ptr[ib->length_dw++] = pe; /* dst addr */
+				ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+				ib->ptr[ib->length_dw++] = r600_flags; /* mask */
+				ib->ptr[ib->length_dw++] = 0;
+				ib->ptr[ib->length_dw++] = value; /* value */
+				ib->ptr[ib->length_dw++] = upper_32_bits(value);
+				ib->ptr[ib->length_dw++] = incr; /* increment size */
+				ib->ptr[ib->length_dw++] = 0;
+				ib->ptr[ib->length_dw++] = ndw; /* number of entries */
+				pe += ndw * 8;
+				addr += ndw * incr;
+				count -= ndw;
+			}
+		}
+		while (ib->length_dw & 0x7)
+			ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0);
+	}
+}
+
+/**
  * cik_dma_vm_flush - cik vm flush using sDMA
  *
  * @rdev: radeon_device pointer
Signature · 1 line
1.7.7.5
#23 lore raw

PATCH 23/165 drm/radeon/cik: fill in startup/shutdown callbacks (v4)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: update to latest driver changes
v3: properly tear down vm on suspend
v4: fix up irq init ordering

---
 drivers/gpu/drm/radeon/cik.c |  340 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 340 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +340 -0
index cf1e0b1..cbc64a2 100644
@@ -73,6 +73,8 @@ extern void r600_ih_ring_fini(struct radeon_device *rdev);
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
+extern void si_rlc_fini(struct radeon_device *rdev);
+extern int si_rlc_init(struct radeon_device *rdev);
 
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
@@ -4681,3 +4683,341 @@ restart_ih:
 
 	return IRQ_HANDLED;
 }
+
+/*
+ * startup/shutdown callbacks
+ */
+/**
+ * cik_startup - program the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called by cik_init() and cik_resume().
+ * Returns 0 for success, error for failure.
+ */
+static int cik_startup(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+	} else {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
+		    !rdev->mc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+
+		r = ci_mc_load_microcode(rdev);
+		if (r) {
+			DRM_ERROR("Failed to load MC firmware!\n");
+			return r;
+		}
+	}
+
+	r = r600_vram_scratch_init(rdev);
+	if (r)
+		return r;
+
+	cik_mc_program(rdev);
+	r = cik_pcie_gart_enable(rdev);
+	if (r)
+		return r;
+	cik_gpu_init(rdev);
+
+	/* allocate rlc buffers */
+	r = si_rlc_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init rlc BOs!\n");
+		return r;
+	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
+	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	/* Enable IRQ */
+	if (!rdev->irq.installed) {
+		r = radeon_irq_kms_init(rdev);
+		if (r)
+			return r;
+	}
+
+	r = cik_irq_init(rdev);
+	if (r) {
+		DRM_ERROR("radeon: IH init failed (%d).\n", r);
+		radeon_irq_kms_fini(rdev);
+		return r;
+	}
+	cik_irq_set(rdev);
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
+			     CP_RB0_RPTR, CP_RB0_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	r = cik_cp_resume(rdev);
+	if (r)
+		return r;
+
+	r = cik_sdma_resume(rdev);
+	if (r)
+		return r;
+
+	r = radeon_ib_pool_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_vm_manager_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
+		return r;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_resume - resume the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called at resume.
+ * Returns 0 for success, error for failure.
+ */
+int cik_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+	 * posting will perform necessary task to bring back GPU into good
+	 * shape.
+	 */
+	/* post card */
+	atom_asic_init(rdev->mode_info.atom_context);
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		DRM_ERROR("cik startup failed on resume\n");
+		rdev->accel_working = false;
+		return r;
+	}
+
+	return r;
+
+}
+
+/**
+ * cik_suspend - suspend the asic
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Bring the chip into a state suitable for suspend (CIK).
+ * Called at suspend.
+ * Returns 0 for success.
+ */
+int cik_suspend(struct radeon_device *rdev)
+{
+	radeon_vm_manager_fini(rdev);
+	cik_cp_enable(rdev, false);
+	cik_sdma_enable(rdev, false);
+	cik_irq_suspend(rdev);
+	radeon_wb_disable(rdev);
+	cik_pcie_gart_disable(rdev);
+	return 0;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+/**
+ * cik_init - asic specific driver and hw init
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Setup asic specific driver variables and program the hw
+ * to a functional state (CIK).
+ * Called at driver startup.
+ * Returns 0 for success, errors for failure.
+ */
+int cik_init(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	/* Read BIOS */
+	if (!radeon_get_bios(rdev)) {
+		if (ASIC_IS_AVIVO(rdev))
+			return -EINVAL;
+	}
+	/* Must be an ATOMBIOS */
+	if (!rdev->is_atom_bios) {
+		dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
+		return -EINVAL;
+	}
+	r = radeon_atombios_init(rdev);
+	if (r)
+		return r;
+
+	/* Post card if necessary */
+	if (!radeon_card_posted(rdev)) {
+		if (!rdev->bios) {
+			dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+			return -EINVAL;
+		}
+		DRM_INFO("GPU not posted. posting now...\n");
+		atom_asic_init(rdev->mode_info.atom_context);
+	}
+	/* Initialize scratch registers */
+	cik_scratch_init(rdev);
+	/* Initialize surface registers */
+	radeon_surface_init(rdev);
+	/* Initialize clocks */
+	radeon_get_clock_info(rdev->ddev);
+
+	/* Fence driver */
+	r = radeon_fence_driver_init(rdev);
+	if (r)
+		return r;
+
+	/* initialize memory controller */
+	r = cik_mc_init(rdev);
+	if (r)
+		return r;
+	/* Memory manager */
+	r = radeon_bo_init(rdev);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	rdev->ih.ring_obj = NULL;
+	r600_ih_ring_init(rdev, 64 * 1024);
+
+	r = r600_pcie_gart_init(rdev);
+	if (r)
+		return r;
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		dev_err(rdev->dev, "disabling GPU acceleration\n");
+		cik_cp_fini(rdev);
+		cik_sdma_fini(rdev);
+		cik_irq_fini(rdev);
+		si_rlc_fini(rdev);
+		radeon_wb_fini(rdev);
+		radeon_ib_pool_fini(rdev);
+		radeon_vm_manager_fini(rdev);
+		radeon_irq_kms_fini(rdev);
+		cik_pcie_gart_fini(rdev);
+		rdev->accel_working = false;
+	}
+
+	/* Don't start up if the MC ucode is missing.
+	 * The default clocks and voltages before the MC ucode
+	 * is loaded are not suffient for advanced operations.
+	 */
+	if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
+		DRM_ERROR("radeon: MC ucode required for NI+.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_fini - asic specific driver and hw fini
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down the asic specific driver variables and program the hw
+ * to an idle state (CIK).
+ * Called at driver unload.
+ */
+void cik_fini(struct radeon_device *rdev)
+{
+	cik_cp_fini(rdev);
+	cik_sdma_fini(rdev);
+	cik_irq_fini(rdev);
+	si_rlc_fini(rdev);
+	radeon_wb_fini(rdev);
+	radeon_vm_manager_fini(rdev);
+	radeon_ib_pool_fini(rdev);
+	radeon_irq_kms_fini(rdev);
+	cik_pcie_gart_fini(rdev);
+	r600_vram_scratch_fini(rdev);
+	radeon_gem_fini(rdev);
+	radeon_fence_driver_fini(rdev);
+	radeon_bo_fini(rdev);
+	radeon_atombios_fini(rdev);
+	kfree(rdev->bios);
+	rdev->bios = NULL;
+}
Signature · 1 line
1.7.7.5
Reviewed-by on v1 23/165
#24 lore raw

Re: [PATCH 023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4)

Am 26.06.2013 15:21, schrieb [email protected]:

Quoted 7 lines

From: Alex Deucher <[email protected]>

v2: update to latest driver changes
v3: properly tear down vm on suspend
v4: fix up irq init ordering

Just a copy&paste error, but some comments are referring to cayman and r500/r700 generations.

With that fixed the patch is:

Quoted 359 lines
---
  drivers/gpu/drm/radeon/cik.c |  340 ++++++++++++++++++++++++++++++++++++++++++
  1 files changed, 340 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +340 -0
index cf1e0b1..cbc64a2 100644
@@ -73,6 +73,8 @@ extern void r600_ih_ring_fini(struct radeon_device *rdev);
  extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
  extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
  extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
+extern void si_rlc_fini(struct radeon_device *rdev);
+extern int si_rlc_init(struct radeon_device *rdev);
 
  #define BONAIRE_IO_MC_REGS_SIZE 36
 
@@ -4681,3 +4683,341 @@ restart_ih:
 
  	return IRQ_HANDLED;
  }
+
+/*
+ * startup/shutdown callbacks
+ */
+/**
+ * cik_startup - program the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called by cik_init() and cik_resume().
+ * Returns 0 for success, error for failure.
+ */
+static int cik_startup(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+	} else {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
+		    !rdev->mc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+
+		r = ci_mc_load_microcode(rdev);
+		if (r) {
+			DRM_ERROR("Failed to load MC firmware!\n");
+			return r;
+		}
+	}
+
+	r = r600_vram_scratch_init(rdev);
+	if (r)
+		return r;
+
+	cik_mc_program(rdev);
+	r = cik_pcie_gart_enable(rdev);
+	if (r)
+		return r;
+	cik_gpu_init(rdev);
+
+	/* allocate rlc buffers */
+	r = si_rlc_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init rlc BOs!\n");
+		return r;
+	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
+	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	/* Enable IRQ */
+	if (!rdev->irq.installed) {
+		r = radeon_irq_kms_init(rdev);
+		if (r)
+			return r;
+	}
+
+	r = cik_irq_init(rdev);
+	if (r) {
+		DRM_ERROR("radeon: IH init failed (%d).\n", r);
+		radeon_irq_kms_fini(rdev);
+		return r;
+	}
+	cik_irq_set(rdev);
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
+			     CP_RB0_RPTR, CP_RB0_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	r = cik_cp_resume(rdev);
+	if (r)
+		return r;
+
+	r = cik_sdma_resume(rdev);
+	if (r)
+		return r;
+
+	r = radeon_ib_pool_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_vm_manager_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
+		return r;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_resume - resume the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called at resume.
+ * Returns 0 for success, error for failure.
+ */
+int cik_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+	 * posting will perform necessary task to bring back GPU into good
+	 * shape.
+	 */
+	/* post card */
+	atom_asic_init(rdev->mode_info.atom_context);
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		DRM_ERROR("cik startup failed on resume\n");
+		rdev->accel_working = false;
+		return r;
+	}
+
+	return r;
+
+}
+
+/**
+ * cik_suspend - suspend the asic
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Bring the chip into a state suitable for suspend (CIK).
+ * Called at suspend.
+ * Returns 0 for success.
+ */
+int cik_suspend(struct radeon_device *rdev)
+{
+	radeon_vm_manager_fini(rdev);
+	cik_cp_enable(rdev, false);
+	cik_sdma_enable(rdev, false);
+	cik_irq_suspend(rdev);
+	radeon_wb_disable(rdev);
+	cik_pcie_gart_disable(rdev);
+	return 0;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+/**
+ * cik_init - asic specific driver and hw init
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Setup asic specific driver variables and program the hw
+ * to a functional state (CIK).
+ * Called at driver startup.
+ * Returns 0 for success, errors for failure.
+ */
+int cik_init(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	/* Read BIOS */
+	if (!radeon_get_bios(rdev)) {
+		if (ASIC_IS_AVIVO(rdev))
+			return -EINVAL;
+	}
+	/* Must be an ATOMBIOS */
+	if (!rdev->is_atom_bios) {
+		dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
+		return -EINVAL;
+	}
+	r = radeon_atombios_init(rdev);
+	if (r)
+		return r;
+
+	/* Post card if necessary */
+	if (!radeon_card_posted(rdev)) {
+		if (!rdev->bios) {
+			dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+			return -EINVAL;
+		}
+		DRM_INFO("GPU not posted. posting now...\n");
+		atom_asic_init(rdev->mode_info.atom_context);
+	}
+	/* Initialize scratch registers */
+	cik_scratch_init(rdev);
+	/* Initialize surface registers */
+	radeon_surface_init(rdev);
+	/* Initialize clocks */
+	radeon_get_clock_info(rdev->ddev);
+
+	/* Fence driver */
+	r = radeon_fence_driver_init(rdev);
+	if (r)
+		return r;
+
+	/* initialize memory controller */
+	r = cik_mc_init(rdev);
+	if (r)
+		return r;
+	/* Memory manager */
+	r = radeon_bo_init(rdev);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	rdev->ih.ring_obj = NULL;
+	r600_ih_ring_init(rdev, 64 * 1024);
+
+	r = r600_pcie_gart_init(rdev);
+	if (r)
+		return r;
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		dev_err(rdev->dev, "disabling GPU acceleration\n");
+		cik_cp_fini(rdev);
+		cik_sdma_fini(rdev);
+		cik_irq_fini(rdev);
+		si_rlc_fini(rdev);
+		radeon_wb_fini(rdev);
+		radeon_ib_pool_fini(rdev);
+		radeon_vm_manager_fini(rdev);
+		radeon_irq_kms_fini(rdev);
+		cik_pcie_gart_fini(rdev);
+		rdev->accel_working = false;
+	}
+
+	/* Don't start up if the MC ucode is missing.
+	 * The default clocks and voltages before the MC ucode
+	 * is loaded are not suffient for advanced operations.
+	 */
+	if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
+		DRM_ERROR("radeon: MC ucode required for NI+.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_fini - asic specific driver and hw fini
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down the asic specific driver variables and program the hw
+ * to an idle state (CIK).
+ * Called at driver unload.
+ */
+void cik_fini(struct radeon_device *rdev)
+{
+	cik_cp_fini(rdev);
+	cik_sdma_fini(rdev);
+	cik_irq_fini(rdev);
+	si_rlc_fini(rdev);
+	radeon_wb_fini(rdev);
+	radeon_vm_manager_fini(rdev);
+	radeon_ib_pool_fini(rdev);
+	radeon_irq_kms_fini(rdev);
+	cik_pcie_gart_fini(rdev);
+	r600_vram_scratch_fini(rdev);
+	radeon_gem_fini(rdev);
+	radeon_fence_driver_fini(rdev);
+	radeon_bo_fini(rdev);
+	radeon_atombios_fini(rdev);
+	kfree(rdev->bios);
+	rdev->bios = NULL;
+}
#25 lore raw

PATCH 24/165 drm/radeon: upstream ObjectID.h updates (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: further updates

---
 drivers/gpu/drm/radeon/ObjectID.h |   40 +++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/ObjectID.h +40 -0
index ca4b038..0619269 100644
@@ -69,6 +69,8 @@
 #define ENCODER_OBJECT_ID_ALMOND                  0x22
 #define ENCODER_OBJECT_ID_TRAVIS                  0x23
 #define ENCODER_OBJECT_ID_NUTMEG                  0x22
+#define ENCODER_OBJECT_ID_HDMI_ANX9805            0x26
+
 /* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */
 #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1   0x13
 #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1    0x14
@@ -86,6 +88,8 @@
 #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1        0x20
 #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2        0x21
 #define ENCODER_OBJECT_ID_INTERNAL_VCE            0x24
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY3        0x25
+#define ENCODER_OBJECT_ID_INTERNAL_AMCLK          0x27
 
 #define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO    0xFF
 
@@ -364,6 +368,14 @@
                                                  GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
                                                  ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT)
 
+#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID1         ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+                                                 ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID2         ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+                                                 ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT)
+
 #define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1    ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
                                                   GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                   ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT)
@@ -392,6 +404,10 @@
                                                   GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                   ENCODER_OBJECT_ID_INTERNAL_VCE << OBJECT_ID_SHIFT)
 
+#define ENCODER_HDMI_ANX9805_ENUM_ID1            ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+                                                  ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT)
+
 /****************************************************/
 /* Connector Object ID definition - Shared with BIOS */
 /****************************************************/
@@ -461,6 +477,14 @@
                                                  GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
 
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID5   ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID6   ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
 #define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1     ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
@@ -473,6 +497,10 @@
                                                  GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
 
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID4     ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
+
 #define CONNECTOR_VGA_ENUM_ID1                 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT)
@@ -541,6 +569,18 @@
                                                  GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
 
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID4         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID5         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID6         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
 #define CONNECTOR_HDMI_TYPE_B_ENUM_ID1         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT)
Signature · 1 line
1.7.7.5
#26 lore raw

PATCH 25/165 drm/radeon: upstream atombios.h updates (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: further updates

---
 drivers/gpu/drm/radeon/atombios.h |  486 ++++++++++++++++++++++++++++++++++---
 1 files changed, 454 insertions(+), 32 deletions(-)
drivers/gpu/drm/radeon/atombios.h +454 -32
index 0ee5737..f19d9a6 100644
@@ -74,6 +74,8 @@
 #define ATOM_PPLL2            1
 #define ATOM_DCPLL            2
 #define ATOM_PPLL0            2
+#define ATOM_PPLL3            3
+
 #define ATOM_EXT_PLL1         8
 #define ATOM_EXT_PLL2         9
 #define ATOM_EXT_CLOCK        10
@@ -259,7 +261,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
   USHORT AdjustDisplayPll;											 //Atomic Table,  used by various SW componentes. 
   USHORT AdjustMemoryController;                 //Atomic Table,  indirectly used by various SW components,called from SetMemoryClock                
   USHORT EnableASIC_StaticPwrMgt;                //Atomic Table,  only used by Bios
-  USHORT ASIC_StaticPwrMgtStatusChange;          //Obsolete ,     only used by Bios   
+  USHORT SetUniphyInstance;                      //Atomic Table,  only used by Bios   
   USHORT DAC_LoadDetection;                      //Atomic Table,  directly used by various SW components,latest version 1.2  
   USHORT LVTMAEncoderControl;                    //Atomic Table,directly used by various SW components,latest version 1.3
   USHORT HW_Misc_Operation;                      //Atomic Table,  directly used by various SW components,latest version 1.1 
@@ -271,7 +273,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
   USHORT TVEncoderControl;                       //Function Table,directly used by various SW components,latest version 1.1
   USHORT PatchMCSetting;                         //only used by BIOS
   USHORT MC_SEQ_Control;                         //only used by BIOS
-  USHORT TV1OutputControl;                       //Atomic Table,  Obsolete from Ry6xx, use DAC2 Output instead
+  USHORT Gfx_Harvesting;                         //Atomic Table,  Obsolete from Ry6xx, Now only used by BIOS for GFX harvesting
   USHORT EnableScaler;                           //Atomic Table,  used only by Bios
   USHORT BlankCRTC;                              //Atomic Table,  directly used by various SW components,latest version 1.1 
   USHORT EnableCRTC;                             //Atomic Table,  directly used by various SW components,latest version 1.1 
@@ -328,7 +330,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
 #define UNIPHYTransmitterControl			     DIG1TransmitterControl
 #define LVTMATransmitterControl				     DIG2TransmitterControl
 #define SetCRTC_DPM_State                        GetConditionalGoldenSetting
-#define SetUniphyInstance                        ASIC_StaticPwrMgtStatusChange
+#define ASIC_StaticPwrMgtStatusChange            SetUniphyInstance 
 #define HPDInterruptService                      ReadHWAssistedI2CStatus
 #define EnableVGA_Access                         GetSCLKOverMCLKRatio
 #define EnableYUV                                GetDispObjectInfo                         
@@ -338,7 +340,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
 #define TMDSAEncoderControl                      PatchMCSetting
 #define LVDSEncoderControl                       MC_SEQ_Control
 #define LCD1OutputControl                        HW_Misc_Operation
-
+#define TV1OutputControl                         Gfx_Harvesting
 
 typedef struct _ATOM_MASTER_COMMAND_TABLE
 {
@@ -478,11 +480,11 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3
 typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4
 {
 #if ATOM_BIG_ENDIAN
-  ULONG  ucPostDiv;          //return parameter: post divider which is used to program to register directly
+  ULONG  ucPostDiv:8;        //return parameter: post divider which is used to program to register directly
   ULONG  ulClock:24;         //Input= target clock, output = actual clock 
 #else
   ULONG  ulClock:24;         //Input= target clock, output = actual clock 
-  ULONG  ucPostDiv;          //return parameter: post divider which is used to program to register directly
+  ULONG  ucPostDiv:8;        //return parameter: post divider which is used to program to register directly
 #endif
 }COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4;
 
@@ -504,6 +506,32 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5
   UCHAR   ucReserved;                       
 }COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5;
 
+
+typedef struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6
+{
+  ATOM_COMPUTE_CLOCK_FREQ  ulClock;         //Input Parameter
+  ULONG   ulReserved[2];
+}COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6;
+
+//ATOM_COMPUTE_CLOCK_FREQ.ulComputeClockFlag
+#define COMPUTE_GPUCLK_INPUT_FLAG_CLK_TYPE_MASK            0x0f
+#define COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK           0x00
+#define COMPUTE_GPUCLK_INPUT_FLAG_SCLK                     0x01
+
+typedef struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6
+{
+  COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4  ulClock;         //Output Parameter: ucPostDiv=DFS divider
+  ATOM_S_MPLL_FB_DIVIDER   ulFbDiv;         //Output Parameter: PLL FB divider
+  UCHAR   ucPllRefDiv;                      //Output Parameter: PLL ref divider      
+  UCHAR   ucPllPostDiv;                     //Output Parameter: PLL post divider      
+  UCHAR   ucPllCntlFlag;                    //Output Flags: control flag
+  UCHAR   ucReserved;                       
+}COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6;
+
+//ucPllCntlFlag
+#define SPLL_CNTL_FLAG_VCO_MODE_MASK            0x03 
+
+
 // ucInputFlag
 #define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN  1   // 1-StrobeMode, 0-PerformanceMode
 
@@ -1686,6 +1714,7 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V6
 #define PIXEL_CLOCK_V6_MISC_HDMI_30BPP              0x08
 #define PIXEL_CLOCK_V6_MISC_HDMI_48BPP              0x0c
 #define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC             0x10
+#define PIXEL_CLOCK_V6_MISC_GEN_DPREFCLK            0x40
 
 typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2
 {
@@ -2102,6 +2131,17 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
 }DVO_ENCODER_CONTROL_PARAMETERS_V3;
 #define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3	DVO_ENCODER_CONTROL_PARAMETERS_V3
 
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V1_4
+{
+  USHORT usPixelClock; 
+  UCHAR  ucDVOConfig;
+  UCHAR  ucAction;														//ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT
+  UCHAR  ucBitPerColor;                       //please refer to definition of PANEL_xBIT_PER_COLOR
+  UCHAR  ucReseved[3];
+}DVO_ENCODER_CONTROL_PARAMETERS_V1_4;
+#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4	DVO_ENCODER_CONTROL_PARAMETERS_V1_4
+
+
 //ucTableFormatRevision=1
 //ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for 
 // bit1=0: non-coherent mode
@@ -2165,7 +2205,7 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
 #define SET_ASIC_VOLTAGE_MODE_SOURCE_B         0x4
 
 #define	SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE      0x0
-#define	SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL      0x1	
+#define	SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL      0x1
 #define	SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK     0x2
 
 typedef struct	_SET_VOLTAGE_PARAMETERS
@@ -2200,15 +2240,20 @@ typedef struct	_SET_VOLTAGE_PARAMETERS_V1_3
 //SET_VOLTAGE_PARAMETERS_V3.ucVoltageMode
 #define ATOM_SET_VOLTAGE                     0        //Set voltage Level
 #define ATOM_INIT_VOLTAGE_REGULATOR          3        //Init Regulator
-#define ATOM_SET_VOLTAGE_PHASE               4        //Set Vregulator Phase
-#define ATOM_GET_MAX_VOLTAGE                 6        //Get Max Voltage, not used in SetVoltageTable v1.3
-#define ATOM_GET_VOLTAGE_LEVEL               6        //Get Voltage level from vitual voltage ID
+#define ATOM_SET_VOLTAGE_PHASE               4        //Set Vregulator Phase, only for SVID/PVID regulator
+#define ATOM_GET_MAX_VOLTAGE                 6        //Get Max Voltage, not used from SetVoltageTable v1.3
+#define ATOM_GET_VOLTAGE_LEVEL               6        //Get Voltage level from vitual voltage ID, not used for SetVoltage v1.4
+#define ATOM_GET_LEAKAGE_ID                  8        //Get Leakage Voltage Id ( starting from SMU7x IP ), SetVoltage v1.4 
 
 // define vitual voltage id in usVoltageLevel
 #define ATOM_VIRTUAL_VOLTAGE_ID0             0xff01
 #define ATOM_VIRTUAL_VOLTAGE_ID1             0xff02
 #define ATOM_VIRTUAL_VOLTAGE_ID2             0xff03
 #define ATOM_VIRTUAL_VOLTAGE_ID3             0xff04
+#define ATOM_VIRTUAL_VOLTAGE_ID4             0xff05
+#define ATOM_VIRTUAL_VOLTAGE_ID5             0xff06
+#define ATOM_VIRTUAL_VOLTAGE_ID6             0xff07
+#define ATOM_VIRTUAL_VOLTAGE_ID7             0xff08
 
 typedef struct _SET_VOLTAGE_PS_ALLOCATION
 {
@@ -2628,7 +2673,8 @@ typedef struct _ATOM_FIRMWARE_INFO_V2_2
   ULONG                           ulFirmwareRevision;
   ULONG                           ulDefaultEngineClock;       //In 10Khz unit
   ULONG                           ulDefaultMemoryClock;       //In 10Khz unit
-  ULONG                           ulReserved[2];
+  ULONG                           ulSPLL_OutputFreq;          //In 10Khz unit  
+  ULONG                           ulGPUPLL_OutputFreq;        //In 10Khz unit
   ULONG                           ulReserved1;                //Was ulMaxEngineClockPLL_Output; //In 10Khz unit*
   ULONG                           ulReserved2;                //Was ulMaxMemoryClockPLL_Output; //In 10Khz unit*
   ULONG                           ulMaxPixelClockPLL_Output;  //In 10Khz unit
@@ -3813,6 +3859,12 @@ typedef struct _ATOM_GPIO_PIN_ASSIGNMENT
   UCHAR                    ucGPIO_ID;
 }ATOM_GPIO_PIN_ASSIGNMENT;
 
+//ucGPIO_ID pre-define id for multiple usage
+//from SMU7.x, if ucGPIO_ID=PP_AC_DC_SWITCH_GPIO_PINID in GPIO_LUTTable, AC/DC swithing feature is enable
+#define PP_AC_DC_SWITCH_GPIO_PINID          60
+//from SMU7.x, if ucGPIO_ID=VDDC_REGULATOR_VRHOT_GPIO_PINID in GPIO_LUTable, VRHot feature is enable
+#define VDDC_VRHOT_GPIO_PINID               61
+
 typedef struct _ATOM_GPIO_PIN_LUT
 {
   ATOM_COMMON_TABLE_HEADER  sHeader;
@@ -4074,17 +4126,19 @@ typedef struct _EXT_DISPLAY_PATH
 
 //usCaps
 #define  EXT_DISPLAY_PATH_CAPS__HBR2_DISABLE          0x01
+#define  EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN        0x02
 
 typedef  struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
 {
   ATOM_COMMON_TABLE_HEADER sHeader;
   UCHAR                    ucGuid [NUMBER_OF_UCHAR_FOR_GUID];     // a GUID is a 16 byte long string
   EXT_DISPLAY_PATH         sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries.
-  UCHAR                    ucChecksum;                            // a  simple Checksum of the sum of whole structure equal to 0x0. 
+  UCHAR                    ucChecksum;                            // a simple Checksum of the sum of whole structure equal to 0x0. 
   UCHAR                    uc3DStereoPinId;                       // use for eDP panel
   UCHAR                    ucRemoteDisplayConfig;
   UCHAR                    uceDPToLVDSRxId;
-  UCHAR                    Reserved[4];                           // for potential expansion
+  UCHAR                    ucFixDPVoltageSwing;                   // usCaps[1]=1, this indicate DP_LANE_SET value
+  UCHAR                    Reserved[3];                           // for potential expansion
 }ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO;
 
 //Related definitions, all records are different but they have a commond header
@@ -4416,6 +4470,13 @@ typedef struct _ATOM_VOLTAGE_CONTROL
 #define	VOLTAGE_CONTROL_ID_CHL822x						0x08									
 #define	VOLTAGE_CONTROL_ID_VT1586M						0x09
 #define VOLTAGE_CONTROL_ID_UP1637 						0x0A
+#define	VOLTAGE_CONTROL_ID_CHL8214            0x0B
+#define	VOLTAGE_CONTROL_ID_UP1801             0x0C
+#define	VOLTAGE_CONTROL_ID_ST6788A            0x0D
+#define VOLTAGE_CONTROL_ID_CHLIR3564SVI2      0x0E
+#define VOLTAGE_CONTROL_ID_AD527x      	      0x0F
+#define VOLTAGE_CONTROL_ID_NCP81022    	      0x10
+#define VOLTAGE_CONTROL_ID_LTC2635			  0x11
 
 typedef struct  _ATOM_VOLTAGE_OBJECT
 {
@@ -4458,6 +4519,15 @@ typedef struct _ATOM_VOLTAGE_OBJECT_HEADER_V3{
 	 USHORT		usSize;													//Size of Object	
 }ATOM_VOLTAGE_OBJECT_HEADER_V3;
 
+// ATOM_VOLTAGE_OBJECT_HEADER_V3.ucVoltageMode
+#define VOLTAGE_OBJ_GPIO_LUT                 0        //VOLTAGE and GPIO Lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_VR_I2C_INIT_SEQ          3        //VOLTAGE REGULATOR INIT sequece through I2C -> ATOM_I2C_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_PHASE_LUT                4        //Set Vregulator Phase lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_SVID2                    7        //Indicate voltage control by SVID2 ->ATOM_SVID2_VOLTAGE_OBJECT_V3
+#define	VOLTAGE_OBJ_PWRBOOST_LEAKAGE_LUT     0x10     //Powerboost Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define	VOLTAGE_OBJ_HIGH_STATE_LEAKAGE_LUT   0x11     //High voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_HIGH1_STATE_LEAKAGE_LUT  0x12     //High1 voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+
 typedef struct  _VOLTAGE_LUT_ENTRY_V2
 {
 	 ULONG		ulVoltageId;									  // The Voltage ID which is used to program GPIO register
@@ -4473,7 +4543,7 @@ typedef struct  _LEAKAGE_VOLTAGE_LUT_ENTRY_V2
 
 typedef struct  _ATOM_I2C_VOLTAGE_OBJECT_V3
 {
-   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;    // voltage mode = VOLTAGE_OBJ_VR_I2C_INIT_SEQ
    UCHAR	ucVoltageRegulatorId;					  //Indicate Voltage Regulator Id
    UCHAR    ucVoltageControlI2cLine;
    UCHAR    ucVoltageControlAddress;
@@ -4484,7 +4554,7 @@ typedef struct  _ATOM_I2C_VOLTAGE_OBJECT_V3
 
 typedef struct  _ATOM_GPIO_VOLTAGE_OBJECT_V3
 {
-   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;   
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;   // voltage mode = VOLTAGE_OBJ_GPIO_LUT or VOLTAGE_OBJ_PHASE_LUT
    UCHAR    ucVoltageGpioCntlId;         // default is 0 which indicate control through CG VID mode 
    UCHAR    ucGpioEntryNum;              // indiate the entry numbers of Votlage/Gpio value Look up table
    UCHAR    ucPhaseDelay;                // phase delay in unit of micro second
@@ -4495,7 +4565,7 @@ typedef struct  _ATOM_GPIO_VOLTAGE_OBJECT_V3
 
 typedef struct  _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
 {
-   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;    // voltage mode = 0x10/0x11/0x12
    UCHAR    ucLeakageCntlId;             // default is 0
    UCHAR    ucLeakageEntryNum;           // indicate the entry number of LeakageId/Voltage Lut table
    UCHAR    ucReserved[2];               
@@ -4503,10 +4573,26 @@ typedef struct  _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
    LEAKAGE_VOLTAGE_LUT_ENTRY_V2 asLeakageIdLut[1];   
 }ATOM_LEAKAGE_VOLTAGE_OBJECT_V3;
 
+
+typedef struct  _ATOM_SVID2_VOLTAGE_OBJECT_V3
+{
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;    // voltage mode = VOLTAGE_OBJ_SVID2
+// 14:7 – PSI0_VID
+// 6 – PSI0_EN
+// 5 – PSI1
+// 4:2 – load line slope trim. 
+// 1:0 – offset trim, 
+   USHORT   usLoadLine_PSI;    
+// GPU GPIO pin Id to SVID2 regulator VRHot pin. possible value 0~31. 0 means GPIO0, 31 means GPIO31
+   UCHAR    ucReserved[2];
+   ULONG    ulReserved;
+}ATOM_SVID2_VOLTAGE_OBJECT_V3;
+
 typedef union _ATOM_VOLTAGE_OBJECT_V3{
   ATOM_GPIO_VOLTAGE_OBJECT_V3 asGpioVoltageObj;
   ATOM_I2C_VOLTAGE_OBJECT_V3 asI2cVoltageObj;
   ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 asLeakageObj;
+  ATOM_SVID2_VOLTAGE_OBJECT_V3 asSVID2Obj;
 }ATOM_VOLTAGE_OBJECT_V3;
 
 typedef struct  _ATOM_VOLTAGE_OBJECT_INFO_V3_1
@@ -4536,6 +4622,21 @@ typedef struct  _ATOM_ASIC_PROFILING_INFO
 	ATOM_ASIC_PROFILE_VOLTAGE			asVoltage;
 }ATOM_ASIC_PROFILING_INFO;
 
+typedef struct  _ATOM_ASIC_PROFILING_INFO_V2_1
+{
+  ATOM_COMMON_TABLE_HEADER			asHeader; 
+  UCHAR  ucLeakageBinNum;                // indicate the entry number of LeakageId/Voltage Lut table
+  USHORT usLeakageBinArrayOffset;        // offset of USHORT Leakage Bin list array ( from lower LeakageId to higher) 
+
+  UCHAR  ucElbVDDC_Num;               
+  USHORT usElbVDDC_IdArrayOffset;        // offset of USHORT virtual VDDC voltage id ( 0xff01~0xff08 )
+  USHORT usElbVDDC_LevelArrayOffset;     // offset of 2 dimension voltage level USHORT array
+
+  UCHAR  ucElbVDDCI_Num;
+  USHORT usElbVDDCI_IdArrayOffset;       // offset of USHORT virtual VDDCI voltage id ( 0xff01~0xff08 )
+  USHORT usElbVDDCI_LevelArrayOffset;    // offset of 2 dimension voltage level USHORT array
+}ATOM_ASIC_PROFILING_INFO_V2_1;
+
 typedef struct _ATOM_POWER_SOURCE_OBJECT
 {
 	UCHAR	ucPwrSrcId;													// Power source
@@ -4652,6 +4753,8 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6
 #define SYS_INFO_LVDSMISC__888_BPC                                                   0x04
 #define SYS_INFO_LVDSMISC__OVERRIDE_EN                                               0x08
 #define SYS_INFO_LVDSMISC__BLON_ACTIVE_LOW                                           0x10
+// new since Trinity
+#define SYS_INFO_LVDSMISC__TRAVIS_LVDS_VOL_OVERRIDE_EN                               0x20
 
 // not used any more
 #define SYS_INFO_LVDSMISC__VSYNC_ACTIVE_LOW                                          0x04
@@ -4752,6 +4855,29 @@ typedef struct _ATOM_FUSION_SYSTEM_INFO_V1
   ATOM_INTEGRATED_SYSTEM_INFO_V6    sIntegratedSysInfo;   
   ULONG  ulPowerplayTable[128];  
 }ATOM_FUSION_SYSTEM_INFO_V1; 
+
+
+typedef struct _ATOM_TDP_CONFIG_BITS
+{
+#if ATOM_BIG_ENDIAN
+  ULONG   uReserved:2;
+  ULONG   uTDP_Value:14;  // Original TDP value in tens of milli watts
+  ULONG   uCTDP_Value:14; // Override value in tens of milli watts
+  ULONG   uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value))
+#else
+  ULONG   uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value))
+  ULONG   uCTDP_Value:14; // Override value in tens of milli watts
+  ULONG   uTDP_Value:14;  // Original TDP value in tens of milli watts
+  ULONG   uReserved:2;
+#endif
+}ATOM_TDP_CONFIG_BITS;
+
+typedef union _ATOM_TDP_CONFIG
+{
+  ATOM_TDP_CONFIG_BITS TDP_config;
+  ULONG            TDP_config_all;
+}ATOM_TDP_CONFIG;
+
 /**********************************************************************************************************************
   ATOM_FUSION_SYSTEM_INFO_V1 Description
 sIntegratedSysInfo:               refer to ATOM_INTEGRATED_SYSTEM_INFO_V6 definition.
@@ -4784,7 +4910,8 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
   UCHAR  ucMemoryType;  
   UCHAR  ucUMAChannelNumber;
   UCHAR  strVBIOSMsg[40];
-  ULONG  ulReserved[20];
+  ATOM_TDP_CONFIG  asTdpConfig;
+  ULONG  ulReserved[19];
   ATOM_AVAILABLE_SCLK_LIST   sAvail_SCLK[5];
   ULONG  ulGMCRestoreResetTime;
   ULONG  ulMinimumNClk;
@@ -4809,7 +4936,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
   USHORT GnbTdpLimit;
   USHORT usMaxLVDSPclkFreqInSingleLink;
   UCHAR  ucLvdsMisc;
-  UCHAR  ucLVDSReserved;
+  UCHAR  ucTravisLVDSVolAdjust;
   UCHAR  ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
   UCHAR  ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
   UCHAR  ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
@@ -4817,7 +4944,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
   UCHAR  ucLVDSOffToOnDelay_in4Ms;
   UCHAR  ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
   UCHAR  ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
-  UCHAR  ucLVDSReserved1;
+  UCHAR  ucMinAllowedBL_Level;
   ULONG  ulLCDBitDepthControlVal;
   ULONG  ulNbpStateMemclkFreq[4];
   USHORT usNBP2Voltage;               
@@ -4846,6 +4973,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
 #define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE                0x01
 #define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE                               0x02
 #define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT                         0x08
+#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS                               0x10
 
 /**********************************************************************************************************************
   ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description
@@ -4945,6 +5073,9 @@ ucLVDSMisc:                       [bit0] LVDS 888bit panel mode =0: LVDS 888 pan
                                   [bit2] LVDS 888bit per color mode  =0: 666 bit per color =1:888 bit per color
                                   [bit3] LVDS parameter override enable  =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
                                   [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+                                  [bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4
+ucTravisLVDSVolAdjust             When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust 
+                                  value to program Travis register LVDS_CTRL_4
 ucLVDSPwrOnSeqDIGONtoDE_in4Ms:    LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ).
                                   =0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
@@ -4964,18 +5095,241 @@ ucLVDSOffToOnDelay_in4Ms:         LVDS power down sequence time in unit of 4ms.
                                   =0 means to use VBIOS default delay which is 125 ( 500ms ).
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
 
-ucLVDSPwrOnVARY_BLtoBLON_in4Ms:   LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. 
+ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms:
+                                  LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. 
                                   =0 means to use VBIOS default delay which is 0 ( 0ms ).
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
 
-ucLVDSPwrOffBLONtoVARY_BL_in4Ms:  LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. 
+ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms:  
+                                  LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. 
                                   =0 means to use VBIOS default delay which is 0 ( 0ms ).
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
 
+ucMinAllowedBL_Level:             Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0. 
+
 ulNbpStateMemclkFreq[4]:          system memory clock frequncey in unit of 10Khz in different NB pstate. 
 
 **********************************************************************************************************************/
 
+// this IntegrateSystemInfoTable is used for Kaveri & Kabini APU
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8
+{
+  ATOM_COMMON_TABLE_HEADER   sHeader;
+  ULONG  ulBootUpEngineClock;
+  ULONG  ulDentistVCOFreq;
+  ULONG  ulBootUpUMAClock;
+  ATOM_CLK_VOLT_CAPABILITY   sDISPCLK_Voltage[4];
+  ULONG  ulBootUpReqDisplayVector;
+  ULONG  ulVBIOSMisc;
+  ULONG  ulGPUCapInfo;
+  ULONG  ulDISP_CLK2Freq;
+  USHORT usRequestedPWMFreqInHz;
+  UCHAR  ucHtcTmpLmt;
+  UCHAR  ucHtcHystLmt;
+  ULONG  ulReserved2;
+  ULONG  ulSystemConfig;            
+  ULONG  ulCPUCapInfo;
+  ULONG  ulReserved3;
+  USHORT usGPUReservedSysMemSize;
+  USHORT usExtDispConnInfoOffset;
+  USHORT usPanelRefreshRateRange;     
+  UCHAR  ucMemoryType;  
+  UCHAR  ucUMAChannelNumber;
+  UCHAR  strVBIOSMsg[40];
+  ATOM_TDP_CONFIG  asTdpConfig;
+  ULONG  ulReserved[19];
+  ATOM_AVAILABLE_SCLK_LIST   sAvail_SCLK[5];
+  ULONG  ulGMCRestoreResetTime;
+  ULONG  ulReserved4;
+  ULONG  ulIdleNClk;
+  ULONG  ulDDR_DLL_PowerUpTime;
+  ULONG  ulDDR_PLL_PowerUpTime;
+  USHORT usPCIEClkSSPercentage;
+  USHORT usPCIEClkSSType;
+  USHORT usLvdsSSPercentage;
+  USHORT usLvdsSSpreadRateIn10Hz;
+  USHORT usHDMISSPercentage;
+  USHORT usHDMISSpreadRateIn10Hz;
+  USHORT usDVISSPercentage;
+  USHORT usDVISSpreadRateIn10Hz;
+  ULONG  ulGPUReservedSysMemBaseAddrLo;
+  ULONG  ulGPUReservedSysMemBaseAddrHi;
+  ULONG  ulReserved5[3];
+  USHORT usMaxLVDSPclkFreqInSingleLink;
+  UCHAR  ucLvdsMisc;
+  UCHAR  ucTravisLVDSVolAdjust;
+  UCHAR  ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+  UCHAR  ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+  UCHAR  ucLVDSOffToOnDelay_in4Ms;
+  UCHAR  ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+  UCHAR  ucMinAllowedBL_Level;
+  ULONG  ulLCDBitDepthControlVal;
+  ULONG  ulNbpStateMemclkFreq[4];
+  ULONG  ulReserved6;               
+  ULONG  ulNbpStateNClkFreq[4];
+  USHORT usNBPStateVoltage[4];            
+  USHORT usBootUpNBVoltage;   
+  USHORT usReserved2; 
+  ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V1_8;
+
+/**********************************************************************************************************************
+  ATOM_INTEGRATED_SYSTEM_INFO_V1_8 Description
+ulBootUpEngineClock:              VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock
+ulDentistVCOFreq:                 Dentist VCO clock in 10kHz unit. 
+ulBootUpUMAClock:                 System memory boot up clock frequency in 10Khz unit. 
+sDISPCLK_Voltage:                 Report Display clock frequency requirement on GNB voltage(up to 4 voltage levels).
+ 
+ulBootUpReqDisplayVector:         VBIOS boot up display IDs, following are supported devices in Trinity projects:
+                                  ATOM_DEVICE_CRT1_SUPPORT                  0x0001
+                                  ATOM_DEVICE_DFP1_SUPPORT                  0x0008
+                                  ATOM_DEVICE_DFP6_SUPPORT                  0x0040
+                                  ATOM_DEVICE_DFP2_SUPPORT                  0x0080
+                                  ATOM_DEVICE_DFP3_SUPPORT                  0x0200
+                                  ATOM_DEVICE_DFP4_SUPPORT                  0x0400
+                                  ATOM_DEVICE_DFP5_SUPPORT                  0x0800
+                                  ATOM_DEVICE_LCD1_SUPPORT                  0x0002
+
+ulVBIOSMisc:      	              Miscellenous flags for VBIOS requirement and interface 
+                                  bit[0]=0: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is not supported by SBIOS. 
+                                        =1: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is supported by SBIOS.
+                                  bit[1]=0: INT15 callback function Get boot display( ax=4e08, bl=01h) is not supported by SBIOS
+                                        =1: INT15 callback function Get boot display( ax=4e08, bl=01h) is supported by SBIOS
+                                  bit[2]=0: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is not supported by SBIOS
+                                        =1: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is supported by SBIOS
+                                  bit[3]=0: VBIOS fast boot is disable
+                                        =1: VBIOS fast boot is enable. ( VBIOS skip display device detection in every set mode if LCD panel is connect and LID is open)
+
+ulGPUCapInfo:                     bit[0~2]= Reserved
+                                  bit[3]=0: Enable AUX HW mode detection logic
+                                        =1: Disable AUX HW mode detection logic
+                                  bit[4]=0: Disable DFS bypass feature
+                                        =1: Enable DFS bypass feature
+
+usRequestedPWMFreqInHz:           When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW). 
+                                  Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0;
+                                  
+                                  When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below:
+                                  1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use;
+                                  VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result,
+                                  Changing BL using VBIOS function is functional in both driver and non-driver present environment; 
+                                  and enabling VariBri under the driver environment from PP table is optional.
+
+                                  2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating
+                                  that BL control from GPU is expected.
+                                  VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1
+                                  Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but
+                                  it's per platform 
+                                  and enabling VariBri under the driver environment from PP table is optional.
+
+ucHtcTmpLmt:                      Refer to D18F3x64 bit[22:16], HtcTmpLmt. Threshold on value to enter HTC_active state.
+ucHtcHystLmt:                     Refer to D18F3x64 bit[27:24], HtcHystLmt. 
+                                  To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt.
+
+ulSystemConfig:                   Bit[0]=0: PCIE Power Gating Disabled 
+                                        =1: PCIE Power Gating Enabled
+                                  Bit[1]=0: DDR-DLL shut-down feature disabled.
+                                         1: DDR-DLL shut-down feature enabled.
+                                  Bit[2]=0: DDR-PLL Power down feature disabled.
+                                         1: DDR-PLL Power down feature enabled. 
+                                  Bit[3]=0: GNB DPM is disabled
+                                        =1: GNB DPM is enabled                                
+ulCPUCapInfo:                     TBD
+
+usExtDispConnInfoOffset:          Offset to sExtDispConnInfo inside the structure
+usPanelRefreshRateRange:          Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set
+                                  to indicate a range.
+                                  SUPPORTED_LCD_REFRESHRATE_30Hz          0x0004
+                                  SUPPORTED_LCD_REFRESHRATE_40Hz          0x0008
+                                  SUPPORTED_LCD_REFRESHRATE_50Hz          0x0010
+                                  SUPPORTED_LCD_REFRESHRATE_60Hz          0x0020
+
+ucMemoryType:                     [3:0]=1:DDR1;=2:DDR2;=3:DDR3;=5:GDDR5; [7:4] is reserved.
+ucUMAChannelNumber:      	        System memory channel numbers. 
+
+strVBIOSMsg[40]:                  VBIOS boot up customized message string 
+
+sAvail_SCLK[5]:                   Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high  
+
+ulGMCRestoreResetTime:            GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. 
+ulIdleNClk:                       NCLK speed while memory runs in self-refresh state, used to calculate self-refresh latency. Unit in 10kHz.
+ulDDR_DLL_PowerUpTime:            DDR PHY DLL power up time. Unit in ns.
+ulDDR_PLL_PowerUpTime:            DDR PHY PLL power up time. Unit in ns.
+
+usPCIEClkSSPercentage:            PCIE Clock Spread Spectrum Percentage in unit 0.01%; 100 mean 1%.
+usPCIEClkSSType:                  PCIE Clock Spread Spectrum Type. 0 for Down spread(default); 1 for Center spread.
+usLvdsSSPercentage:               LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting. 
+usLvdsSSpreadRateIn10Hz:          LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. 
+usHDMISSPercentage:               HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%,  =0, use VBIOS default setting. 
+usHDMISSpreadRateIn10Hz:          HDMI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
+usDVISSPercentage:                DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%,  =0, use VBIOS default setting. 
+usDVISSpreadRateIn10Hz:           DVI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
+
+usGPUReservedSysMemSize:          Reserved system memory size for ACP engine in APU GNB, units in MB. 0/2/4MB based on CMOS options, current default could be 0MB. KV only, not on KB.
+ulGPUReservedSysMemBaseAddrLo:    Low 32 bits base address to the reserved system memory. 
+ulGPUReservedSysMemBaseAddrHi:    High 32 bits base address to the reserved system memory. 
+
+usMaxLVDSPclkFreqInSingleLink:    Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz
+ucLVDSMisc:                       [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode
+                                  [bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped
+                                  [bit2] LVDS 888bit per color mode  =0: 666 bit per color =1:888 bit per color
+                                  [bit3] LVDS parameter override enable  =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
+                                  [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+                                  [bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4
+ucTravisLVDSVolAdjust             When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust 
+                                  value to program Travis register LVDS_CTRL_4
+ucLVDSPwrOnSeqDIGONtoDE_in4Ms:    
+                                  LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ).
+                                  =0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnDEtoVARY_BL_in4Ms:     
+                                  LVDS power up sequence time in unit of 4ms., time delay from DE( data enable ) active to Vary Brightness enable signal active( VARY_BL ).  
+                                  =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOffVARY_BLtoDE_in4Ms:    
+                                  LVDS power down sequence time in unit of 4ms, time delay from data enable ( DE ) signal off to LCDVCC (DIGON) off. 
+                                  =0 mean use VBIOS default delay which is 8 ( 32ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOffDEtoDIGON_in4Ms:      
+                                   LVDS power down sequence time in unit of 4ms, time delay from vary brightness enable signal( VARY_BL) off to data enable ( DE ) signal off. 
+                                  =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSOffToOnDelay_in4Ms:         
+                                  LVDS power down sequence time in unit of 4ms. Time delay from DIGON signal off to DIGON signal active. 
+                                  =0 means to use VBIOS default delay which is 125 ( 500ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms:
+                                  LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. 
+                                  =0 means to use VBIOS default delay which is 0 ( 0ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms:  
+                                  LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. 
+                                  =0 means to use VBIOS default delay which is 0 ( 0ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucMinAllowedBL_Level:             Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0. 
+
+ulLCDBitDepthControlVal:          GPU display control encoder bit dither control setting, used to program register mmFMT_BIT_DEPTH_CONTROL
+
+ulNbpStateMemclkFreq[4]:          system memory clock frequncey in unit of 10Khz in different NB P-State(P0, P1, P2 & P3).
+ulNbpStateNClkFreq[4]:            NB P-State NClk frequency in different NB P-State
+usNBPStateVoltage[4]:             NB P-State (P0/P1 & P2/P3) voltage; NBP3 refers to lowes voltage
+usBootUpNBVoltage:                NB P-State voltage during boot up before driver loaded 
+sExtDispConnInfo:                 Display connector information table provided to VBIOS
+
+**********************************************************************************************************************/
+
+// this Table is used for Kaveri/Kabini APU
+typedef struct _ATOM_FUSION_SYSTEM_INFO_V2
+{
+  ATOM_INTEGRATED_SYSTEM_INFO_V1_8    sIntegratedSysInfo;       // refer to ATOM_INTEGRATED_SYSTEM_INFO_V1_8 definition
+  ULONG                               ulPowerplayTable[128];    // Update comments here to link new powerplay table definition structure
+}ATOM_FUSION_SYSTEM_INFO_V2; 
+
+
 /**************************************************************************/
 // This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design
 //Memory SS Info Table
@@ -5026,22 +5380,24 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT
 
 //Define ucClockIndication, SW uses the IDs below to search if the SS is required/enabled on a clock branch/signal type.
 //SS is not required or enabled if a match is not found.
-#define ASIC_INTERNAL_MEMORY_SS			1
-#define ASIC_INTERNAL_ENGINE_SS			2
-#define ASIC_INTERNAL_UVD_SS        3
-#define ASIC_INTERNAL_SS_ON_TMDS    4
-#define ASIC_INTERNAL_SS_ON_HDMI    5
-#define ASIC_INTERNAL_SS_ON_LVDS    6
-#define ASIC_INTERNAL_SS_ON_DP      7
-#define ASIC_INTERNAL_SS_ON_DCPLL   8
-#define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9
-#define ASIC_INTERNAL_VCE_SS        10
+#define ASIC_INTERNAL_MEMORY_SS	         1
+#define ASIC_INTERNAL_ENGINE_SS	         2
+#define ASIC_INTERNAL_UVD_SS             3
+#define ASIC_INTERNAL_SS_ON_TMDS         4
+#define ASIC_INTERNAL_SS_ON_HDMI         5
+#define ASIC_INTERNAL_SS_ON_LVDS         6
+#define ASIC_INTERNAL_SS_ON_DP           7
+#define ASIC_INTERNAL_SS_ON_DCPLL        8
+#define ASIC_EXTERNAL_SS_ON_DP_CLOCK     9
+#define ASIC_INTERNAL_VCE_SS             10
+#define ASIC_INTERNAL_GPUPLL_SS          11
+
 
 typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2
 {
 	ULONG								ulTargetClockRange;						//For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz
                                                     //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 )
-  USHORT              usSpreadSpectrumPercentage;		//in unit of 0.01%
+  USHORT              usSpreadSpectrumPercentage;		//in unit of 0.01% or 0.001%, decided by ucSpreadSpectrumMode bit4
 	USHORT							usSpreadRateIn10Hz;						//in unit of 10Hz, modulation freq
   UCHAR               ucClockIndication;					  //Indicate which clock source needs SS
 	UCHAR								ucSpreadSpectrumMode;					//Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS
@@ -5079,6 +5435,11 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3
 	UCHAR								ucReserved[2];
 }ATOM_ASIC_SS_ASSIGNMENT_V3;
 
+//ATOM_ASIC_SS_ASSIGNMENT_V3.ucSpreadSpectrumMode
+#define SS_MODE_V3_CENTRE_SPREAD_MASK             0x01
+#define SS_MODE_V3_EXTERNAL_SS_MASK               0x02
+#define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK    0x10
+
 typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3
 {
   ATOM_COMMON_TABLE_HEADER	      sHeader; 
@@ -5719,6 +6080,7 @@ typedef struct _INDIRECT_IO_ACCESS
 #define INDIRECT_IO_PCIE           3
 #define INDIRECT_IO_PCIEP          4
 #define INDIRECT_IO_NBMISC         5
+#define INDIRECT_IO_SMU            5
 
 #define INDIRECT_IO_PLL_READ       INDIRECT_IO_PLL   | INDIRECT_READ
 #define INDIRECT_IO_PLL_WRITE      INDIRECT_IO_PLL   | INDIRECT_WRITE
@@ -5730,6 +6092,8 @@ typedef struct _INDIRECT_IO_ACCESS
 #define INDIRECT_IO_PCIEP_WRITE    INDIRECT_IO_PCIEP | INDIRECT_WRITE
 #define INDIRECT_IO_NBMISC_READ    INDIRECT_IO_NBMISC | INDIRECT_READ
 #define INDIRECT_IO_NBMISC_WRITE   INDIRECT_IO_NBMISC | INDIRECT_WRITE
+#define INDIRECT_IO_SMU_READ       INDIRECT_IO_SMU | INDIRECT_READ
+#define INDIRECT_IO_SMU_WRITE      INDIRECT_IO_SMU | INDIRECT_WRITE
 
 typedef struct _ATOM_OEM_INFO
 { 
@@ -5875,6 +6239,7 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
 #define _64Mx32             0x43
 #define _128Mx8             0x51
 #define _128Mx16            0x52
+#define _128Mx32            0x53
 #define _256Mx8             0x61
 #define _256Mx16            0x62
 
@@ -5893,6 +6258,8 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
 #define PROMOS              MOSEL
 #define KRETON              INFINEON
 #define ELIXIR              NANYA
+#define MEZZA               ELPIDA
+
 
 /////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM/////////////
 
@@ -6625,6 +6992,10 @@ typedef struct _ATOM_DISP_OUT_INFO_V3
 	ASIC_TRANSMITTER_INFO_V2  asTransmitterInfo[1];     // for alligment only
 }ATOM_DISP_OUT_INFO_V3;
 
+//ucDispCaps
+#define DISPLAY_CAPS__DP_PCLK_FROM_PPLL        0x01
+#define DISPLAY_CAPS__FORCE_DISPDEV_CONNECTED  0x02
+
 typedef enum CORE_REF_CLK_SOURCE{
   CLOCK_SRC_XTALIN=0,
   CLOCK_SRC_XO_IN=1,
@@ -6829,6 +7200,17 @@ typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_1{
   USHORT usPhyPllSettingOffset;          // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
 }DIG_TRANSMITTER_INFO_HEADER_V3_1;
 
+typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_2{  
+  ATOM_COMMON_TABLE_HEADER sHeader;  
+  USHORT usDPVsPreEmphSettingOffset;     // offset of PHY_ANALOG_SETTING_INFO * with DP Voltage Swing and Pre-Emphasis for each Link clock 
+  USHORT usPhyAnalogRegListOffset;       // offset of CLOCK_CONDITION_REGESTER_INFO* with None-DP mode Analog Setting's register Info 
+  USHORT usPhyAnalogSettingOffset;       // offset of CLOCK_CONDITION_SETTING_ENTRY* with None-DP mode Analog Setting for each link clock range
+  USHORT usPhyPllRegListOffset;          // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy Pll register Info 
+  USHORT usPhyPllSettingOffset;          // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
+  USHORT usDPSSRegListOffset;            // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy SS Pll register Info 
+  USHORT usDPSSSettingOffset;            // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy SS Pll Settings
+}DIG_TRANSMITTER_INFO_HEADER_V3_2;
+
 typedef struct _CLOCK_CONDITION_REGESTER_INFO{
   USHORT usRegisterIndex;
   UCHAR  ucStartBit;
@@ -6852,12 +7234,24 @@ typedef struct _PHY_CONDITION_REG_VAL{
   ULONG  ulRegVal;
 }PHY_CONDITION_REG_VAL;
 
+typedef struct _PHY_CONDITION_REG_VAL_V2{
+  ULONG  ulCondition;
+  UCHAR  ucCondition2;
+  ULONG  ulRegVal;
+}PHY_CONDITION_REG_VAL_V2;
+
 typedef struct _PHY_CONDITION_REG_INFO{
   USHORT usRegIndex;
   USHORT usSize;
   PHY_CONDITION_REG_VAL asRegVal[1];
 }PHY_CONDITION_REG_INFO;
 
+typedef struct _PHY_CONDITION_REG_INFO_V2{
+  USHORT usRegIndex;
+  USHORT usSize;
+  PHY_CONDITION_REG_VAL_V2 asRegVal[1];
+}PHY_CONDITION_REG_INFO_V2;
+
 typedef struct _PHY_ANALOG_SETTING_INFO{
   UCHAR  ucEncodeMode;
   UCHAR  ucPhySel;
@@ -6865,6 +7259,25 @@ typedef struct _PHY_ANALOG_SETTING_INFO{
   PHY_CONDITION_REG_INFO  asAnalogSetting[1];
 }PHY_ANALOG_SETTING_INFO;
 
+typedef struct _PHY_ANALOG_SETTING_INFO_V2{
+  UCHAR  ucEncodeMode;
+  UCHAR  ucPhySel;
+  USHORT usSize;
+  PHY_CONDITION_REG_INFO_V2  asAnalogSetting[1];
+}PHY_ANALOG_SETTING_INFO_V2;
+
+typedef struct _GFX_HAVESTING_PARAMETERS {
+  UCHAR ucGfxBlkId;                        //GFX blk id to be harvested, like CU, RB or PRIM
+  UCHAR ucReserved;                        //reserved 
+  UCHAR ucActiveUnitNumPerSH;              //requested active CU/RB/PRIM number per shader array
+  UCHAR ucMaxUnitNumPerSH;                 //max CU/RB/PRIM number per shader array   
+} GFX_HAVESTING_PARAMETERS;
+
+//ucGfxBlkId
+#define GFX_HARVESTING_CU_ID               0
+#define GFX_HARVESTING_RB_ID               1
+#define GFX_HARVESTING_PRIM_ID             2
+
 /****************************************************************************/	
 //Portion VI: Definitinos for vbios MC scratch registers that driver used
 /****************************************************************************/
@@ -6875,8 +7288,17 @@ typedef struct _PHY_ANALOG_SETTING_INFO{
 #define MC_MISC0__MEMORY_TYPE__GDDR3  0x30000000
 #define MC_MISC0__MEMORY_TYPE__GDDR4  0x40000000
 #define MC_MISC0__MEMORY_TYPE__GDDR5  0x50000000
+#define MC_MISC0__MEMORY_TYPE__HBM    0x60000000
 #define MC_MISC0__MEMORY_TYPE__DDR3   0xB0000000
 
+#define ATOM_MEM_TYPE_DDR_STRING      "DDR"
+#define ATOM_MEM_TYPE_DDR2_STRING     "DDR2"
+#define ATOM_MEM_TYPE_GDDR3_STRING    "GDDR3"
+#define ATOM_MEM_TYPE_GDDR4_STRING    "GDDR4"
+#define ATOM_MEM_TYPE_GDDR5_STRING    "GDDR5"
+#define ATOM_MEM_TYPE_HBM_STRING      "HBM"
+#define ATOM_MEM_TYPE_DDR3_STRING     "DDR3"
+
 /****************************************************************************/	
 //Portion VI: Definitinos being oboselete
 /****************************************************************************/
Signature · 6 lines
1.7.7.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#27 lore raw

PATCH 26/165 drm/radeon: atombios power table updates (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: further updates

---
 drivers/gpu/drm/radeon/atombios.h |   58 ++++++++++++++++++++++++++++++++++--
 1 files changed, 54 insertions(+), 4 deletions(-)
drivers/gpu/drm/radeon/atombios.h +54 -4
index f19d9a6..7ba9588 100644
@@ -7696,6 +7696,7 @@ typedef struct _ATOM_PPLIB_THERMALCONTROLLER
 #define ATOM_PP_THERMALCONTROLLER_NISLANDS  15
 #define ATOM_PP_THERMALCONTROLLER_SISLANDS  16
 #define ATOM_PP_THERMALCONTROLLER_LM96163   17
+#define ATOM_PP_THERMALCONTROLLER_CISLANDS  18
 
 // Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
 // We probably should reserve the bit 0x80 for this use.
@@ -7738,6 +7739,8 @@ typedef struct _ATOM_PPLIB_EXTENDEDHEADER
     // Add extra system parameters here, always adjust size to include all fields.
     USHORT  usVCETableOffset; //points to ATOM_PPLIB_VCE_Table
     USHORT  usUVDTableOffset;   //points to ATOM_PPLIB_UVD_Table
+    USHORT  usSAMUTableOffset;  //points to ATOM_PPLIB_SAMU_Table
+    USHORT  usPPMTableOffset;   //points to ATOM_PPLIB_PPM_Table
 } ATOM_PPLIB_EXTENDEDHEADER;
 
 //// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps
@@ -7759,7 +7762,7 @@ typedef struct _ATOM_PPLIB_EXTENDEDHEADER
 #define ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000                   // Does the driver control VDDCI independently from VDDC.
 #define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000               // Enable the 'regulator hot' feature.
 #define ATOM_PP_PLATFORM_CAP_BACO          0x00020000               // Does the driver supports BACO state.
-
+#define ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE   0x00040000           // Does the driver supports new CAC voltage table.
 
 typedef struct _ATOM_PPLIB_POWERPLAYTABLE
 {
@@ -7820,7 +7823,7 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE4
     USHORT                     usVddcDependencyOnMCLKOffset;
     USHORT                     usMaxClockVoltageOnDCOffset;
     USHORT                     usVddcPhaseShedLimitsTableOffset;    // Points to ATOM_PPLIB_PhaseSheddingLimits_Table
-    USHORT                     usReserved;  
+    USHORT                     usMvddDependencyOnMCLKOffset;  
 } ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4;
 
 typedef struct _ATOM_PPLIB_POWERPLAYTABLE5
@@ -7985,6 +7988,17 @@ typedef struct _ATOM_PPLIB_SI_CLOCK_INFO
 
 } ATOM_PPLIB_SI_CLOCK_INFO;
 
+typedef struct _ATOM_PPLIB_CI_CLOCK_INFO
+{
+      USHORT usEngineClockLow;
+      UCHAR  ucEngineClockHigh;
+
+      USHORT usMemoryClockLow;
+      UCHAR  ucMemoryClockHigh;
+      
+      UCHAR  ucPCIEGen;
+      USHORT usPCIELane;
+} ATOM_PPLIB_CI_CLOCK_INFO;
 
 typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
 
@@ -8102,8 +8116,8 @@ typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table
 
 typedef struct _ATOM_PPLIB_CAC_Leakage_Record
 {
-    USHORT usVddc;  // We use this field for the "fake" standardized VDDC for power calculations                                                  
-    ULONG  ulLeakageValue;
+    USHORT usVddc;  // We use this field for the "fake" standardized VDDC for power calculations; For CI and newer, we use this as the real VDDC value.
+    ULONG  ulLeakageValue;  // For CI and newer we use this as the "fake" standar VDDC value.
 }ATOM_PPLIB_CAC_Leakage_Record;
 
 typedef struct _ATOM_PPLIB_CAC_Leakage_Table
@@ -8218,6 +8232,42 @@ typedef struct _ATOM_PPLIB_UVD_Table
 //    ATOM_PPLIB_UVD_State_Table states;
 }ATOM_PPLIB_UVD_Table;
 
+
+typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Record
+{
+      USHORT usVoltage;
+      USHORT usSAMClockLow;
+      UCHAR  ucSAMClockHigh;
+}ATOM_PPLIB_SAMClk_Voltage_Limit_Record;
+
+typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Table{
+    UCHAR numEntries;
+    ATOM_PPLIB_SAMClk_Voltage_Limit_Record entries[1];
+}ATOM_PPLIB_SAMClk_Voltage_Limit_Table;
+
+typedef struct _ATOM_PPLIB_SAMU_Table
+{
+      UCHAR revid;
+      ATOM_PPLIB_SAMClk_Voltage_Limit_Table limits;
+}ATOM_PPLIB_SAMU_Table;
+
+#define ATOM_PPM_A_A    1
+#define ATOM_PPM_A_I    2
+typedef struct _ATOM_PPLIB_PPM_Table
+{
+      UCHAR  ucRevId;
+      UCHAR  ucPpmDesign;          //A+I or A+A
+      USHORT usCpuCoreNumber;
+      ULONG  ulPlatformTDP;
+      ULONG  ulSmallACPlatformTDP;
+      ULONG  ulPlatformTDC;
+      ULONG  ulSmallACPlatformTDC;
+      ULONG  ulApuTDP;
+      ULONG  ulDGpuTDP;  
+      ULONG  ulDGpuUlvPower;
+      ULONG  ulTjmax;
+} ATOM_PPLIB_PPM_Table;
+
 /**************************************************************************/
 
 
Signature · 1 line
1.7.7.5
#28 lore raw

PATCH 27/165 drm/radeon: handle the integrated thermal controller on CI

In reply to [email protected]

From: Alex Deucher <[email protected]>

No support for reading the temperature yet.

---
 drivers/gpu/drm/radeon/radeon.h          |    1 +
 drivers/gpu/drm/radeon/radeon_atombios.c |    6 ++++++
 2 files changed, 7 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/radeon.h +1 -0
index 919c4d8..04e8dbd 100644
@@ -1033,6 +1033,7 @@ enum radeon_int_thermal_type {
 	THERMAL_TYPE_SUMO,
 	THERMAL_TYPE_NI,
 	THERMAL_TYPE_SI,
+	THERMAL_TYPE_CI,
 };
 
 struct radeon_voltage {
drivers/gpu/drm/radeon/radeon_atombios.c +6 -0
index dea6f63c..cb3273b 100644
@@ -1927,6 +1927,7 @@ static const char *pp_lib_thermal_controller_names[] = {
 	"Northern Islands",
 	"Southern Islands",
 	"lm96163",
+	"Sea Islands",
 };
 
 union power_info {
@@ -2209,6 +2210,11 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
 				 (controller->ucFanParameters &
 				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 			rdev->pm.int_thermal_type = THERMAL_TYPE_SI;
+		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
+			DRM_INFO("Internal thermal controller %s fan control\n",
+				 (controller->ucFanParameters &
+				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+			rdev->pm.int_thermal_type = THERMAL_TYPE_CI;
 		} else if ((controller->ucType ==
 			    ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
 			   (controller->ucType ==
Signature · 1 line
1.7.7.5
#29 lore raw

PATCH 28/165 drm/radeon: update power state parsing for CI

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/radeon_atombios.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/radeon_atombios.c +10 -0
index cb3273b..88a55af 100644
@@ -1945,6 +1945,7 @@ union pplib_clock_info {
 	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
 	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
 	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
+	struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
 };
 
 union pplib_power_state {
@@ -2353,6 +2354,15 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
 			sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
 			rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
 		}
+	} else if (rdev->family >= CHIP_BONAIRE) {
+		sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
+		sclk |= clock_info->ci.ucEngineClockHigh << 16;
+		mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
+		mclk |= clock_info->ci.ucMemoryClockHigh << 16;
+		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
+		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+			VOLTAGE_NONE;
 	} else if (rdev->family >= CHIP_TAHITI) {
 		sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
 		sclk |= clock_info->si.ucEngineClockHigh << 16;
Signature · 1 line
1.7.7.5
#30 lore raw

PATCH 29/165 drm/radeon/dce8: add support for display watermark setup

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/cik.c  |  537 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   11 +
 2 files changed, 548 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +537 -0
index cbc64a2..228d399 100644
@@ -5021,3 +5021,540 @@ void cik_fini(struct radeon_device *rdev)
 	kfree(rdev->bios);
 	rdev->bios = NULL;
 }
+
+/* display watermark setup */
+/**
+ * dce8_line_buffer_adjust - Set up the line buffer
+ *
+ * @rdev: radeon_device pointer
+ * @radeon_crtc: the selected display controller
+ * @mode: the current display mode on the selected display
+ * controller
+ *
+ * Setup up the line buffer allocation for
+ * the selected display controller (CIK).
+ * Returns the line buffer size in pixels.
+ */
+static u32 dce8_line_buffer_adjust(struct radeon_device *rdev,
+				   struct radeon_crtc *radeon_crtc,
+				   struct drm_display_mode *mode)
+{
+	u32 tmp;
+
+	/*
+	 * Line Buffer Setup
+	 * There are 6 line buffers, one for each display controllers.
+	 * There are 3 partitions per LB. Select the number of partitions
+	 * to enable based on the display width.  For display widths larger
+	 * than 4096, you need use to use 2 display controllers and combine
+	 * them using the stereo blender.
+	 */
+	if (radeon_crtc->base.enabled && mode) {
+		if (mode->crtc_hdisplay < 1920)
+			tmp = 1;
+		else if (mode->crtc_hdisplay < 2560)
+			tmp = 2;
+		else if (mode->crtc_hdisplay < 4096)
+			tmp = 0;
+		else {
+			DRM_DEBUG_KMS("Mode too big for LB!\n");
+			tmp = 0;
+		}
+	} else
+		tmp = 1;
+
+	WREG32(LB_MEMORY_CTRL + radeon_crtc->crtc_offset,
+	       LB_MEMORY_CONFIG(tmp) | LB_MEMORY_SIZE(0x6B0));
+
+	if (radeon_crtc->base.enabled && mode) {
+		switch (tmp) {
+		case 0:
+		default:
+			return 4096 * 2;
+		case 1:
+			return 1920 * 2;
+		case 2:
+			return 2560 * 2;
+		}
+	}
+
+	/* controller not enabled, so no lb used */
+	return 0;
+}
+
+/**
+ * cik_get_number_of_dram_channels - get the number of dram channels
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Look up the number of video ram channels (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the number of dram channels
+ */
+static u32 cik_get_number_of_dram_channels(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+	switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+	case 0:
+	default:
+		return 1;
+	case 1:
+		return 2;
+	case 2:
+		return 4;
+	case 3:
+		return 8;
+	case 4:
+		return 3;
+	case 5:
+		return 6;
+	case 6:
+		return 10;
+	case 7:
+		return 12;
+	case 8:
+		return 16;
+	}
+}
+
+struct dce8_wm_params {
+	u32 dram_channels; /* number of dram channels */
+	u32 yclk;          /* bandwidth per dram data pin in kHz */
+	u32 sclk;          /* engine clock in kHz */
+	u32 disp_clk;      /* display clock in kHz */
+	u32 src_width;     /* viewport width */
+	u32 active_time;   /* active display time in ns */
+	u32 blank_time;    /* blank time in ns */
+	bool interlaced;    /* mode is interlaced */
+	fixed20_12 vsc;    /* vertical scale ratio */
+	u32 num_heads;     /* number of active crtcs */
+	u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+	u32 lb_size;       /* line buffer allocated to pipe */
+	u32 vtaps;         /* vertical scaler taps */
+};
+
+/**
+ * dce8_dram_bandwidth - get the dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the raw dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth in MBytes/s
+ */
+static u32 dce8_dram_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate raw DRAM Bandwidth */
+	fixed20_12 dram_efficiency; /* 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	dram_efficiency.full = dfixed_const(7);
+	dram_efficiency.full = dfixed_div(dram_efficiency, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_dram_bandwidth_for_display - get the dram bandwidth for display
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dram bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth for display in MBytes/s
+ */
+static u32 dce8_dram_bandwidth_for_display(struct dce8_wm_params *wm)
+{
+	/* Calculate DRAM Bandwidth and the part allocated to display. */
+	fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+	disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_data_return_bandwidth - get the data return bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the data return bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the data return bandwidth in MBytes/s
+ */
+static u32 dce8_data_return_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the display Data return Bandwidth */
+	fixed20_12 return_efficiency; /* 0.8 */
+	fixed20_12 sclk, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	sclk.full = dfixed_const(wm->sclk);
+	sclk.full = dfixed_div(sclk, a);
+	a.full = dfixed_const(10);
+	return_efficiency.full = dfixed_const(8);
+	return_efficiency.full = dfixed_div(return_efficiency, a);
+	a.full = dfixed_const(32);
+	bandwidth.full = dfixed_mul(a, sclk);
+	bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_dmif_request_bandwidth - get the dmif bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dmif bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dmif bandwidth in MBytes/s
+ */
+static u32 dce8_dmif_request_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the DMIF Request Bandwidth */
+	fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+	fixed20_12 disp_clk, bandwidth;
+	fixed20_12 a, b;
+
+	a.full = dfixed_const(1000);
+	disp_clk.full = dfixed_const(wm->disp_clk);
+	disp_clk.full = dfixed_div(disp_clk, a);
+	a.full = dfixed_const(32);
+	b.full = dfixed_mul(a, disp_clk);
+
+	a.full = dfixed_const(10);
+	disp_clk_request_efficiency.full = dfixed_const(8);
+	disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+
+	bandwidth.full = dfixed_mul(b, disp_clk_request_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_available_bandwidth - get the min available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the min available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the min available bandwidth in MBytes/s
+ */
+static u32 dce8_available_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+	u32 dram_bandwidth = dce8_dram_bandwidth(wm);
+	u32 data_return_bandwidth = dce8_data_return_bandwidth(wm);
+	u32 dmif_req_bandwidth = dce8_dmif_request_bandwidth(wm);
+
+	return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+/**
+ * dce8_average_bandwidth - get the average available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the average available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the average available bandwidth in MBytes/s
+ */
+static u32 dce8_average_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the display mode Average Bandwidth
+	 * DisplayMode should contain the source and destination dimensions,
+	 * timing, etc.
+	 */
+	fixed20_12 bpp;
+	fixed20_12 line_time;
+	fixed20_12 src_width;
+	fixed20_12 bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+	line_time.full = dfixed_div(line_time, a);
+	bpp.full = dfixed_const(wm->bytes_per_pixel);
+	src_width.full = dfixed_const(wm->src_width);
+	bandwidth.full = dfixed_mul(src_width, bpp);
+	bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+	bandwidth.full = dfixed_div(bandwidth, line_time);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_latency_watermark - get the latency watermark
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the latency watermark (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the latency watermark in ns
+ */
+static u32 dce8_latency_watermark(struct dce8_wm_params *wm)
+{
+	/* First calculate the latency in ns */
+	u32 mc_latency = 2000; /* 2000 ns. */
+	u32 available_bandwidth = dce8_available_bandwidth(wm);
+	u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+	u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+	u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+	u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+		(wm->num_heads * cursor_line_pair_return_time);
+	u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+	u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+	u32 tmp, dmif_size = 12288;
+	fixed20_12 a, b, c;
+
+	if (wm->num_heads == 0)
+		return 0;
+
+	a.full = dfixed_const(2);
+	b.full = dfixed_const(1);
+	if ((wm->vsc.full > a.full) ||
+	    ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+	    (wm->vtaps >= 5) ||
+	    ((wm->vsc.full >= a.full) && wm->interlaced))
+		max_src_lines_per_dst_line = 4;
+	else
+		max_src_lines_per_dst_line = 2;
+
+	a.full = dfixed_const(available_bandwidth);
+	b.full = dfixed_const(wm->num_heads);
+	a.full = dfixed_div(a, b);
+
+	b.full = dfixed_const(mc_latency + 512);
+	c.full = dfixed_const(wm->disp_clk);
+	b.full = dfixed_div(b, c);
+
+	c.full = dfixed_const(dmif_size);
+	b.full = dfixed_div(c, b);
+
+	tmp = min(dfixed_trunc(a), dfixed_trunc(b));
+
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(wm->disp_clk);
+	b.full = dfixed_div(c, b);
+	c.full = dfixed_const(wm->bytes_per_pixel);
+	b.full = dfixed_mul(b, c);
+
+	lb_fill_bw = min(tmp, dfixed_trunc(b));
+
+	a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(lb_fill_bw);
+	b.full = dfixed_div(c, b);
+	a.full = dfixed_div(a, b);
+	line_fill_time = dfixed_trunc(a);
+
+	if (line_fill_time < wm->active_time)
+		return latency;
+	else
+		return latency + (line_fill_time - wm->active_time);
+
+}
+
+/**
+ * dce8_average_bandwidth_vs_dram_bandwidth_for_display - check
+ * average and available dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce8_average_bandwidth_vs_dram_bandwidth_for_display(struct dce8_wm_params *wm)
+{
+	if (dce8_average_bandwidth(wm) <=
+	    (dce8_dram_bandwidth_for_display(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dce8_average_bandwidth_vs_available_bandwidth - check
+ * average and available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * available bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce8_average_bandwidth_vs_available_bandwidth(struct dce8_wm_params *wm)
+{
+	if (dce8_average_bandwidth(wm) <=
+	    (dce8_available_bandwidth(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dce8_check_latency_hiding - check latency hiding
+ *
+ * @wm: watermark calculation data
+ *
+ * Check latency hiding (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce8_check_latency_hiding(struct dce8_wm_params *wm)
+{
+	u32 lb_partitions = wm->lb_size / wm->src_width;
+	u32 line_time = wm->active_time + wm->blank_time;
+	u32 latency_tolerant_lines;
+	u32 latency_hiding;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1);
+	if (wm->vsc.full > a.full)
+		latency_tolerant_lines = 1;
+	else {
+		if (lb_partitions <= (wm->vtaps + 1))
+			latency_tolerant_lines = 1;
+		else
+			latency_tolerant_lines = 2;
+	}
+
+	latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+	if (dce8_latency_watermark(wm) <= latency_hiding)
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dce8_program_watermarks - program display watermarks
+ *
+ * @rdev: radeon_device pointer
+ * @radeon_crtc: the selected display controller
+ * @lb_size: line buffer size
+ * @num_heads: number of display controllers in use
+ *
+ * Calculate and program the display watermarks for the
+ * selected display controller (CIK).
+ */
+static void dce8_program_watermarks(struct radeon_device *rdev,
+				    struct radeon_crtc *radeon_crtc,
+				    u32 lb_size, u32 num_heads)
+{
+	struct drm_display_mode *mode = &radeon_crtc->base.mode;
+	struct dce8_wm_params wm;
+	u32 pixel_period;
+	u32 line_time = 0;
+	u32 latency_watermark_a = 0, latency_watermark_b = 0;
+	u32 tmp, wm_mask;
+
+	if (radeon_crtc->base.enabled && num_heads && mode) {
+		pixel_period = 1000000 / (u32)mode->clock;
+		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+
+		wm.yclk = rdev->pm.current_mclk * 10;
+		wm.sclk = rdev->pm.current_sclk * 10;
+		wm.disp_clk = mode->clock;
+		wm.src_width = mode->crtc_hdisplay;
+		wm.active_time = mode->crtc_hdisplay * pixel_period;
+		wm.blank_time = line_time - wm.active_time;
+		wm.interlaced = false;
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			wm.interlaced = true;
+		wm.vsc = radeon_crtc->vsc;
+		wm.vtaps = 1;
+		if (radeon_crtc->rmx_type != RMX_OFF)
+			wm.vtaps = 2;
+		wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm.lb_size = lb_size;
+		wm.dram_channels = cik_get_number_of_dram_channels(rdev);
+		wm.num_heads = num_heads;
+
+		/* set for high clocks */
+		latency_watermark_a = min(dce8_latency_watermark(&wm), (u32)65535);
+		/* set for low clocks */
+		/* wm.yclk = low clk; wm.sclk = low clk */
+		latency_watermark_b = min(dce8_latency_watermark(&wm), (u32)65535);
+
+		/* possibly force display priority to high */
+		/* should really do this at mode validation time... */
+		if (!dce8_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
+		    !dce8_average_bandwidth_vs_available_bandwidth(&wm) ||
+		    !dce8_check_latency_hiding(&wm) ||
+		    (rdev->disp_priority == 2)) {
+			DRM_DEBUG_KMS("force priority to high\n");
+		}
+	}
+
+	/* select wm A */
+	wm_mask = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset);
+	tmp = wm_mask;
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(1);
+	WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp);
+	WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* select wm B */
+	tmp = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset);
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(2);
+	WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp);
+	WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* restore original selection */
+	WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, wm_mask);
+}
+
+/**
+ * dce8_bandwidth_update - program display watermarks
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Calculate and program the display watermarks and line
+ * buffer allocation (CIK).
+ */
+void dce8_bandwidth_update(struct radeon_device *rdev)
+{
+	struct drm_display_mode *mode = NULL;
+	u32 num_heads = 0, lb_size;
+	int i;
+
+	radeon_update_display_priority(rdev);
+
+	for (i = 0; i < rdev->num_crtc; i++) {
+		if (rdev->mode_info.crtcs[i]->base.enabled)
+			num_heads++;
+	}
+	for (i = 0; i < rdev->num_crtc; i++) {
+		mode = &rdev->mode_info.crtcs[i]->base.mode;
+		lb_size = dce8_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode);
+		dce8_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
+	}
+}
drivers/gpu/drm/radeon/cikd.h +11 -0
index 39ed517..3349e37 100644
@@ -259,6 +259,17 @@
 #define		SDMA0					(1 << 10)
 #define		SDMA1					(1 << 11)
 
+/* 0x6b04, 0x7704, 0x10304, 0x10f04, 0x11b04, 0x12704 */
+#define	LB_MEMORY_CTRL					0x6b04
+#define		LB_MEMORY_SIZE(x)			((x) << 0)
+#define		LB_MEMORY_CONFIG(x)			((x) << 20)
+
+#define	DPG_WATERMARK_MASK_CONTROL			0x6cc8
+#       define LATENCY_WATERMARK_MASK(x)		((x) << 8)
+#define	DPG_PIPE_LATENCY_CONTROL			0x6ccc
+#       define LATENCY_LOW_WATERMARK(x)			((x) << 0)
+#       define LATENCY_HIGH_WATERMARK(x)		((x) << 16)
+
 /* 0x6b24, 0x7724, 0x10324, 0x10f24, 0x11b24, 0x12724 */
 #define LB_VLINE_STATUS                                 0x6b24
 #       define VLINE_OCCURRED                           (1 << 0)
Signature · 1 line
1.7.7.5
#31 lore raw

PATCH 30/165 drm/radeon/cik: add hw cursor support (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

CIK (DCE8) hw cursors are programmed the same as evergreen (DCE4) with the following caveats:
- cursors are now 128x128 pixels
- new alpha blend enable bit

v2: rebase

---
 drivers/gpu/drm/radeon/cik_reg.h        |   65 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon.h         |    7 +++
 drivers/gpu/drm/radeon/radeon_cursor.c  |   10 ++---
 drivers/gpu/drm/radeon/radeon_display.c |   16 +++++++-
 drivers/gpu/drm/radeon/radeon_mode.h    |    2 +
 drivers/gpu/drm/radeon/radeon_reg.h     |    1 +
 6 files changed, 94 insertions(+), 7 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/cik_reg.h
drivers/gpu/drm/radeon/cik_reg.h new file +65 -0
new file mode 100644
index 0000000..b96dac0
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef __CIK_REG_H__
+#define __CIK_REG_H__
+
+#define CIK_DC_GPIO_HPD_MASK                      0x65b0
+#define CIK_DC_GPIO_HPD_A                         0x65b4
+#define CIK_DC_GPIO_HPD_EN                        0x65b8
+#define CIK_DC_GPIO_HPD_Y                         0x65bc
+
+/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
+#define CIK_CUR_CONTROL                           0x6998
+#       define CIK_CURSOR_EN                      (1 << 0)
+#       define CIK_CURSOR_MODE(x)                 (((x) & 0x3) << 8)
+#       define CIK_CURSOR_MONO                    0
+#       define CIK_CURSOR_24_1                    1
+#       define CIK_CURSOR_24_8_PRE_MULT           2
+#       define CIK_CURSOR_24_8_UNPRE_MULT         3
+#       define CIK_CURSOR_2X_MAGNIFY              (1 << 16)
+#       define CIK_CURSOR_FORCE_MC_ON             (1 << 20)
+#       define CIK_CURSOR_URGENT_CONTROL(x)       (((x) & 0x7) << 24)
+#       define CIK_CURSOR_URGENT_ALWAYS           0
+#       define CIK_CURSOR_URGENT_1_8              1
+#       define CIK_CURSOR_URGENT_1_4              2
+#       define CIK_CURSOR_URGENT_3_8              3
+#       define CIK_CURSOR_URGENT_1_2              4
+#define CIK_CUR_SURFACE_ADDRESS                   0x699c
+#       define CIK_CUR_SURFACE_ADDRESS_MASK       0xfffff000
+#define CIK_CUR_SIZE                              0x69a0
+#define CIK_CUR_SURFACE_ADDRESS_HIGH              0x69a4
+#define CIK_CUR_POSITION                          0x69a8
+#define CIK_CUR_HOT_SPOT                          0x69ac
+#define CIK_CUR_COLOR1                            0x69b0
+#define CIK_CUR_COLOR2                            0x69b4
+#define CIK_CUR_UPDATE                            0x69b8
+#       define CIK_CURSOR_UPDATE_PENDING          (1 << 0)
+#       define CIK_CURSOR_UPDATE_TAKEN            (1 << 1)
+#       define CIK_CURSOR_UPDATE_LOCK             (1 << 16)
+#       define CIK_CURSOR_DISABLE_MULTIPLE_UPDATE (1 << 24)
+
+#define CIK_ALPHA_CONTROL                         0x6af0
+#       define CIK_CURSOR_ALPHA_BLND_ENA          (1 << 1)
+
+#endif
drivers/gpu/drm/radeon/radeon.h +7 -0
index 04e8dbd..b329e99 100644
@@ -150,6 +150,13 @@ extern int radeon_fastfb;
 #define RADEON_RESET_MC				(1 << 10)
 #define RADEON_RESET_DISPLAY			(1 << 11)
 
+/* max cursor sizes (in pixels) */
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+
+#define CIK_CURSOR_WIDTH 128
+#define CIK_CURSOR_HEIGHT 128
+
 /*
  * Errata workarounds.
  */
drivers/gpu/drm/radeon/radeon_cursor.c +4 -6
index b097d5b..9630e8d 100644
@@ -27,9 +27,6 @@
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 
-#define CURSOR_WIDTH 64
-#define CURSOR_HEIGHT 64
-
 static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
 {
 	struct radeon_device *rdev = crtc->dev->dev_private;
@@ -167,7 +164,8 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc,
 		goto unpin;
 	}
 
-	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+	if ((width > radeon_crtc->max_cursor_width) ||
+	    (height > radeon_crtc->max_cursor_height)) {
 		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
 		return -EINVAL;
 	}
@@ -233,11 +231,11 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
 	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
 
 	if (x < 0) {
-		xorigin = min(-x, CURSOR_WIDTH - 1);
+		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
 		x = 0;
 	}
 	if (y < 0) {
-		yorigin = min(-y, CURSOR_HEIGHT - 1);
+		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
 		y = 0;
 	}
 
drivers/gpu/drm/radeon/radeon_display.c +15 -1
index eb18bb7..1f850eb 100644
@@ -153,7 +153,13 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
 		NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
 	/* XXX match this to the depth of the crtc fmt block, move to modeset? */
 	WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
-
+	if (ASIC_IS_DCE8(rdev)) {
+		/* XXX this only needs to be programmed once per crtc at startup,
+		 * not sure where the best place for it is
+		 */
+		WREG32(CIK_ALPHA_CONTROL + radeon_crtc->crtc_offset,
+		       CIK_CURSOR_ALPHA_BLND_ENA);
+	}
 }
 
 static void legacy_crtc_load_lut(struct drm_crtc *crtc)
@@ -512,6 +518,14 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
 	radeon_crtc->crtc_id = index;
 	rdev->mode_info.crtcs[index] = radeon_crtc;
 
+	if (rdev->family >= CHIP_BONAIRE) {
+		radeon_crtc->max_cursor_width = CIK_CURSOR_WIDTH;
+		radeon_crtc->max_cursor_height = CIK_CURSOR_HEIGHT;
+	} else {
+		radeon_crtc->max_cursor_width = CURSOR_WIDTH;
+		radeon_crtc->max_cursor_height = CURSOR_HEIGHT;
+	}
+
 #if 0
 	radeon_crtc->mode_set.crtc = &radeon_crtc->base;
 	radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1);
drivers/gpu/drm/radeon/radeon_mode.h +2 -0
index 69ad4fe..4ed0a4c 100644
@@ -307,6 +307,8 @@ struct radeon_crtc {
 	uint64_t cursor_addr;
 	int cursor_width;
 	int cursor_height;
+	int max_cursor_width;
+	int max_cursor_height;
 	uint32_t legacy_display_base_addr;
 	uint32_t legacy_cursor_offset;
 	enum radeon_rmx_type rmx_type;
drivers/gpu/drm/radeon/radeon_reg.h +1 -0
index 7e2c2b7..62d5497 100644
@@ -57,6 +57,7 @@
 #include "evergreen_reg.h"
 #include "ni_reg.h"
 #include "si_reg.h"
+#include "cik_reg.h"
 
 #define RADEON_MC_AGP_LOCATION		0x014c
 #define		RADEON_MC_AGP_START_MASK	0x0000FFFF
Signature · 1 line
1.7.7.5
#32 lore raw

PATCH 31/165 drm/radeon/dce8: properly handle interlaced timing

In reply to [email protected]

From: Alex Deucher <[email protected]>

The register bits changed on DCE8 compared to previous families.

---
 drivers/gpu/drm/radeon/atombios_encoders.c |    8 +++++++-
 drivers/gpu/drm/radeon/cik_reg.h           |    3 +++
 2 files changed, 10 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/atombios_encoders.c +7 -1
index 4120d35..4439419 100644
@@ -1962,7 +1962,13 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
 	/* set scaler clears this on some chips */
 	if (ASIC_IS_AVIVO(rdev) &&
 	    (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) {
-		if (ASIC_IS_DCE4(rdev)) {
+		if (ASIC_IS_DCE8(rdev)) {
+			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+				WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset,
+				       CIK_INTERLEAVE_EN);
+			else
+				WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+		} else if (ASIC_IS_DCE4(rdev)) {
 			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 				WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
 				       EVERGREEN_INTERLEAVE_EN);
drivers/gpu/drm/radeon/cik_reg.h +3 -0
index b96dac0..58b29b5 100644
@@ -62,4 +62,7 @@
 #define CIK_ALPHA_CONTROL                         0x6af0
 #       define CIK_CURSOR_ALPHA_BLND_ENA          (1 << 1)
 
+#define CIK_LB_DATA_FORMAT                        0x6b00
+#       define CIK_INTERLEAVE_EN                  (1 << 3)
+
 #endif
Signature · 1 line
1.7.7.5
#33 lore raw

PATCH 32/165 drm/radeon/dce8: crtc_set_base updates

In reply to [email protected]

From: Alex Deucher <[email protected]>

Some new fields and DESKTOP_HEIGHT register moved.

---
 drivers/gpu/drm/radeon/atombios_crtc.c |   34 ++++++++++++--
 drivers/gpu/drm/radeon/cik_reg.h       |   79 ++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+), 5 deletions(-)
drivers/gpu/drm/radeon/atombios_crtc.c +29 -5
index d5df8fd..4ba5184 100644
@@ -1143,7 +1143,9 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 	}
 
 	if (tiling_flags & RADEON_TILING_MACRO) {
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			tmp = rdev->config.cik.tile_config;
+		else if (rdev->family >= CHIP_TAHITI)
 			tmp = rdev->config.si.tile_config;
 		else if (rdev->family >= CHIP_CAYMAN)
 			tmp = rdev->config.cayman.tile_config;
@@ -1170,11 +1172,29 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 		fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
 		fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
 		fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
+		if (rdev->family >= CHIP_BONAIRE) {
+			/* XXX need to know more about the surface tiling mode */
+			fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING);
+		}
 	} else if (tiling_flags & RADEON_TILING_MICRO)
 		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
 
-	if ((rdev->family == CHIP_TAHITI) ||
-	    (rdev->family == CHIP_PITCAIRN))
+	if (rdev->family >= CHIP_BONAIRE) {
+		u32 num_pipe_configs = rdev->config.cik.max_tile_pipes;
+		u32 num_rb = rdev->config.cik.max_backends_per_se;
+		if (num_pipe_configs > 8)
+			num_pipe_configs = 8;
+		if (num_pipe_configs == 8)
+			fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P8_32x32_16x16);
+		else if (num_pipe_configs == 4) {
+			if (num_rb == 4)
+				fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_16x16);
+			else if (num_rb < 4)
+				fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_8x16);
+		} else if (num_pipe_configs == 2)
+			fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P2);
+	} else if ((rdev->family == CHIP_TAHITI) ||
+		   (rdev->family == CHIP_PITCAIRN))
 		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16);
 	else if (rdev->family == CHIP_VERDE)
 		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16);
@@ -1224,8 +1244,12 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 	WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
 	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
-	WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
-	       target_fb->height);
+	if (rdev->family >= CHIP_BONAIRE)
+		WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+		       target_fb->height);
+	else
+		WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+		       target_fb->height);
 	x &= ~3;
 	y &= ~1;
 	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
drivers/gpu/drm/radeon/cik_reg.h +79 -0

89 lines not on this page · raw message

Signature · 1 line
1.7.7.5
#34 lore raw

PATCH 33/165 drm/radeon/atom: add DCE8 encoder support

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/atombios_encoders.c |   27 ++++++++++++++++++++++++---
 drivers/gpu/drm/radeon/radeon_display.c    |    5 +++--
 2 files changed, 27 insertions(+), 5 deletions(-)
drivers/gpu/drm/radeon/atombios_encoders.c +24 -3
index 4439419..1bf13b3 100644
@@ -303,6 +303,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		return true;
 	default:
 		return false;
@@ -922,10 +923,14 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 				args.v4.ucLaneNum = 4;
 
 			if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) {
-				if (dp_clock == 270000)
-					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
-				else if (dp_clock == 540000)
+				if (dp_clock == 540000)
 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
+				else if (dp_clock == 324000)
+					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ;
+				else if (dp_clock == 270000)
+					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
+				else
+					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
 			}
 			args.v4.acConfig.ucDigSel = dig->dig_encoder;
 			args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
@@ -1019,6 +1024,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
@@ -1278,6 +1284,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 				else
 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
 				break;
+			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+				args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG;
+				break;
 			}
 			if (is_dp)
 				args.v5.ucLaneNum = dp_lane_count;
@@ -1742,6 +1751,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		radeon_atom_encoder_dpms_dig(encoder, mode);
 		break;
@@ -1879,6 +1889,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 				dig = radeon_encoder->enc_priv;
 				switch (dig->dig_encoder) {
@@ -1900,6 +1911,9 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
 				case 5:
 					args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
 					break;
+				case 6:
+					args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
+					break;
 				}
 				break;
 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
@@ -2015,6 +2029,9 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
 			else
 				return 4;
 			break;
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+			return 6;
+			break;
 		}
 	} else if (ASIC_IS_DCE4(rdev)) {
 		/* DCE4/5 */
@@ -2099,6 +2116,7 @@ radeon_atom_encoder_init(struct radeon_device *rdev)
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
 			break;
@@ -2143,6 +2161,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		/* handled in dpms */
 		break;
@@ -2408,6 +2427,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		/* handled in dpms */
 		break;
@@ -2639,6 +2659,7 @@ radeon_add_atom_encoder(struct drm_device *dev,
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
 			radeon_encoder->rmx_type = RMX_FULL;
 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
drivers/gpu/drm/radeon/radeon_display.c +3 -2
index 1f850eb..c2b67b4 100644
@@ -544,7 +544,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
 		radeon_legacy_init_crtc(dev, radeon_crtc);
 }
 
-static const char *encoder_names[37] = {
+static const char *encoder_names[38] = {
 	"NONE",
 	"INTERNAL_LVDS",
 	"INTERNAL_TMDS1",
@@ -581,7 +581,8 @@ static const char *encoder_names[37] = {
 	"INTERNAL_UNIPHY2",
 	"NUTMEG",
 	"TRAVIS",
-	"INTERNAL_VCE"
+	"INTERNAL_VCE",
+	"INTERNAL_UNIPHY3",
 };
 
 static const char *hpd_names[6] = {
Signature · 1 line
1.7.7.5
#35 lore raw

PATCH 34/165 drm/radeon/atom: add support for new DVO tables

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/atombios_encoders.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/atombios_encoders.c +8 -1
index 1bf13b3..092275d 100644
@@ -487,11 +487,11 @@ static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
 	}
 }
 
-
 union dvo_encoder_control {
 	ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
 	DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
 	DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
+	DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4;
 };
 
 void
@@ -541,6 +541,13 @@ atombios_dvo_setup(struct drm_encoder *encoder, int action)
 			args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
 			args.dvo_v3.ucDVOConfig = 0; /* XXX */
 			break;
+		case 4:
+			/* DCE8 */
+			args.dvo_v4.ucAction = action;
+			args.dvo_v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+			args.dvo_v4.ucDVOConfig = 0; /* XXX */
+			args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
+			break;
 		default:
 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
 			break;
Signature · 1 line
1.7.7.5
#36 lore raw

PATCH 35/165 drm/radeon: update DISPCLK programming for DCE8

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/atombios_crtc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/atombios_crtc.c +1 -1
index 4ba5184..586c452 100644
@@ -743,7 +743,7 @@ static void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev,
 			 * SetPixelClock provides the dividers
 			 */
 			args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
-			if (ASIC_IS_DCE61(rdev))
+			if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
 				args.v6.ucPpll = ATOM_EXT_PLL1;
 			else if (ASIC_IS_DCE6(rdev))
 				args.v6.ucPpll = ATOM_PPLL0;
Signature · 1 line
1.7.7.5
#37 lore raw

PATCH 36/165 drm/radeon: add support pll selection for DCE8 (v4)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: make PPLL0 is available for non-DP on CI
v3: rebase changes, update documentation
v4: fix kabini

---
 drivers/gpu/drm/radeon/atombios_crtc.c |   48 +++++++++++++++++++++++++++++++-
 1 files changed, 47 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/atombios_crtc.c +47 -1
index 586c452..590e4eb 100644
@@ -1621,6 +1621,12 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
  *
  * Asic specific PLL information
  *
+ * DCE 8.x
+ * KB/KV
+ * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP)
+ * CI
+ * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
+ *
  * DCE 6.1
  * - PPLL2 is only available to UNIPHYA (both DP and non-DP)
  * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP)
@@ -1647,7 +1653,47 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 	u32 pll_in_use;
 	int pll;
 
-	if (ASIC_IS_DCE61(rdev)) {
+	if (ASIC_IS_DCE8(rdev)) {
+		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+			if (rdev->clock.dp_extclk)
+				/* skip PPLL programming if using ext clock */
+				return ATOM_PPLL_INVALID;
+			else {
+				/* use the same PPLL for all DP monitors */
+				pll = radeon_get_shared_dp_ppll(crtc);
+				if (pll != ATOM_PPLL_INVALID)
+					return pll;
+			}
+		} else {
+			/* use the same PPLL for all monitors with the same clock */
+			pll = radeon_get_shared_nondp_ppll(crtc);
+			if (pll != ATOM_PPLL_INVALID)
+				return pll;
+		}
+		/* otherwise, pick one of the plls */
+		if ((rdev->family == CHIP_KAVERI) ||
+		    (rdev->family == CHIP_KABINI)) {
+			/* KB/KV has PPLL1 and PPLL2 */
+			pll_in_use = radeon_get_pll_use_mask(crtc);
+			if (!(pll_in_use & (1 << ATOM_PPLL2)))
+				return ATOM_PPLL2;
+			if (!(pll_in_use & (1 << ATOM_PPLL1)))
+				return ATOM_PPLL1;
+			DRM_ERROR("unable to allocate a PPLL\n");
+			return ATOM_PPLL_INVALID;
+		} else {
+			/* CI has PPLL0, PPLL1, and PPLL2 */
+			pll_in_use = radeon_get_pll_use_mask(crtc);
+			if (!(pll_in_use & (1 << ATOM_PPLL2)))
+				return ATOM_PPLL2;
+			if (!(pll_in_use & (1 << ATOM_PPLL1)))
+				return ATOM_PPLL1;
+			if (!(pll_in_use & (1 << ATOM_PPLL0)))
+				return ATOM_PPLL0;
+			DRM_ERROR("unable to allocate a PPLL\n");
+			return ATOM_PPLL_INVALID;
+		}
+	} else if (ASIC_IS_DCE61(rdev)) {
 		struct radeon_encoder_atom_dig *dig =
 			radeon_encoder->enc_priv;
 
Signature · 1 line
1.7.7.5
#38 lore raw

PATCH 37/165 drm/radeon: Handle PPLL0 powerdown on DCE8

In reply to [email protected]

From: Alex Deucher <[email protected]>

Only Bonaire has PPLL0.

---
 drivers/gpu/drm/radeon/atombios_crtc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/atombios_crtc.c +1 -1
index 590e4eb..24eee7c 100644
@@ -1931,7 +1931,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
 		break;
 	case ATOM_PPLL0:
 		/* disable the ppll */
-		if (ASIC_IS_DCE61(rdev))
+		if ((rdev->family == CHIP_ARUBA) || (rdev->family == CHIP_BONAIRE))
 			atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
 						  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
 		break;
Signature · 1 line
1.7.7.5
#39 lore raw

PATCH 38/165 drm/radeon: use frac fb div on DCE8

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/atombios_crtc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/atombios_crtc.c +1 -1
index 24eee7c..c7ad4b9 100644
@@ -555,7 +555,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
 		if (rdev->family < CHIP_RV770)
 			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
 		/* use frac fb div on APUs */
-		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
+		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
 			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
 		/* use frac fb div on RS780/RS880 */
 		if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
Signature · 1 line
1.7.7.5
#40 lore raw

PATCH 39/165 drm/radeon: add SS override support for KB/KV

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/radeon_atombios.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/radeon_atombios.c +17 -0
index 88a55af..3236755 100644
@@ -1269,6 +1269,7 @@ union igp_info {
 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
 };
 
 bool radeon_atombios_sideport_present(struct radeon_device *rdev)
@@ -1438,6 +1439,22 @@ static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
 				break;
 			}
 			break;
+		case 8:
+			switch (id) {
+			case ASIC_INTERNAL_SS_ON_TMDS:
+				percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);
+				rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);
+				break;
+			case ASIC_INTERNAL_SS_ON_HDMI:
+				percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);
+				rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);
+				break;
+			case ASIC_INTERNAL_SS_ON_LVDS:
+				percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);
+				rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);
+				break;
+			}
+			break;
 		default:
 			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
 			break;
Signature · 1 line
1.7.7.5
#41 lore raw

PATCH 40/165 drm/radeon: Update radeon_info_ioctl for CIK (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: rebase changes, fix a couple missed cases

---
 drivers/gpu/drm/radeon/radeon_kms.c |   33 ++++++++++++++++++++++++++-------
 1 files changed, 26 insertions(+), 7 deletions(-)
drivers/gpu/drm/radeon/radeon_kms.c +26 -7
index 4f2d4f4..c650228 100644
@@ -229,7 +229,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		*value = rdev->accel_working;
 		break;
 	case RADEON_INFO_TILING_CONFIG:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.tile_config;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.tile_config;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.tile_config;
@@ -281,7 +283,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 			*value = rdev->clock.spll.reference_freq * 10;
 		break;
 	case RADEON_INFO_NUM_BACKENDS:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_backends_per_se *
+				rdev->config.cik.max_shader_engines;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_backends_per_se *
 				rdev->config.si.max_shader_engines;
 		else if (rdev->family >= CHIP_CAYMAN)
@@ -298,7 +303,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		}
 		break;
 	case RADEON_INFO_NUM_TILE_PIPES:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_tile_pipes;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_tile_pipes;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.max_tile_pipes;
@@ -316,7 +323,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		*value = 1;
 		break;
 	case RADEON_INFO_BACKEND_MAP:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			return -EINVAL;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.backend_map;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.backend_map;
@@ -343,7 +352,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		*value = RADEON_IB_VM_MAX_SIZE;
 		break;
 	case RADEON_INFO_MAX_PIPES:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_cu_per_sh;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_cu_per_sh;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.max_pipes_per_simd;
@@ -367,7 +378,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		value64 = radeon_get_gpu_clock_counter(rdev);
 		break;
 	case RADEON_INFO_MAX_SE:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_shader_engines;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_shader_engines;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.max_shader_engines;
@@ -377,7 +390,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 			*value = 1;
 		break;
 	case RADEON_INFO_MAX_SH_PER_SE:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_sh_per_se;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_sh_per_se;
 		else
 			return -EINVAL;
@@ -407,6 +422,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		}
 		break;
 	case RADEON_INFO_SI_TILE_MODE_ARRAY:
+		if (rdev->family >= CHIP_BONAIRE) {
+			DRM_DEBUG_KMS("tile mode array is not implemented yet\n");
+			return -EINVAL;
+		}
 		if (rdev->family < CHIP_TAHITI) {
 			DRM_DEBUG_KMS("tile mode array is si only!\n");
 			return -EINVAL;
Signature · 1 line
1.7.7.5
#42 lore raw

PATCH 41/165 drm/radeon: add get_gpu_clock_counter() callback for cik

In reply to [email protected]

From: Alex Deucher <[email protected]>

Used for GPU clock counter snapshots.

---
 drivers/gpu/drm/radeon/cik.c         |   21 +++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |    4 +++-
 drivers/gpu/drm/radeon/radeon_asic.h |    5 +++++
 3 files changed, 29 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/cik.c +21 -0
index 228d399..d241cfd 100644
@@ -5558,3 +5558,24 @@ void dce8_bandwidth_update(struct radeon_device *rdev)
 		dce8_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
 	}
 }
+
+/**
+ * cik_get_gpu_clock_counter - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (SI).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev)
+{
+	uint64_t clock;
+
+	mutex_lock(&rdev->gpu_clock_mutex);
+	WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+	clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+	        ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+	mutex_unlock(&rdev->gpu_clock_mutex);
+	return clock;
+}
+
drivers/gpu/drm/radeon/cikd.h +3 -1
index 3349e37..daa51ac 100644
@@ -730,7 +730,9 @@
 
 #define RLC_GPM_UCODE_ADDR                                0xC388
 #define RLC_GPM_UCODE_DATA                                0xC38C
-
+#define RLC_GPU_CLOCK_COUNT_LSB                           0xC390
+#define RLC_GPU_CLOCK_COUNT_MSB                           0xC394
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                       0xC398
 #define RLC_UCODE_CNTL                                    0xC39C
 
 #define RLC_CGCG_CGLS_CTRL                                0xC424
drivers/gpu/drm/radeon/radeon_asic.h +5 -0
index a72759e..248da72 100644
@@ -553,4 +553,9 @@ u32 si_get_xclk(struct radeon_device *rdev);
 uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
 int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 
+/*
+ * cik
+ */
+uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
+
 #endif
Signature · 1 line
1.7.7.5
#43 lore raw

PATCH 42/165 drm/radeon: update CIK soft reset

In reply to [email protected]

From: Alex Deucher <[email protected]>

Update to the newer programming model.

---
 drivers/gpu/drm/radeon/cik.c  |  387 +++++++++++++++++++++++++----------------
 drivers/gpu/drm/radeon/cikd.h |   12 ++
 2 files changed, 253 insertions(+), 146 deletions(-)
drivers/gpu/drm/radeon/cik.c +241 -146
index d241cfd..aaf7bba 100644
@@ -72,9 +72,11 @@ extern int r600_ih_ring_alloc(struct radeon_device *rdev);
 extern void r600_ih_ring_fini(struct radeon_device *rdev);
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern bool evergreen_is_display_hung(struct radeon_device *rdev);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
+static void cik_rlc_stop(struct radeon_device *rdev);
 
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
@@ -2733,56 +2735,9 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
 	return r;
 }
 
-/**
- * cik_gpu_is_lockup - check if the 3D engine is locked up
- *
- * @rdev: radeon_device pointer
- * @ring: radeon_ring structure holding ring information
- *
- * Check if the 3D engine is locked up (CIK).
- * Returns true if the engine is locked, false if not.
- */
-bool cik_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
-{
-	u32 srbm_status, srbm_status2;
-	u32 grbm_status, grbm_status2;
-	u32 grbm_status_se0, grbm_status_se1, grbm_status_se2, grbm_status_se3;
-
-	srbm_status = RREG32(SRBM_STATUS);
-	srbm_status2 = RREG32(SRBM_STATUS2);
-	grbm_status = RREG32(GRBM_STATUS);
-	grbm_status2 = RREG32(GRBM_STATUS2);
-	grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
-	grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
-	grbm_status_se2 = RREG32(GRBM_STATUS_SE2);
-	grbm_status_se3 = RREG32(GRBM_STATUS_SE3);
-	if (!(grbm_status & GUI_ACTIVE)) {
-		radeon_ring_lockup_update(ring);
-		return false;
-	}
-	/* force CP activities */
-	radeon_ring_force_activity(rdev, ring);
-	return radeon_ring_test_lockup(rdev, ring);
-}
 
-/**
- * cik_gfx_gpu_soft_reset - soft reset the 3D engine and CPG
- *
- * @rdev: radeon_device pointer
- *
- * Soft reset the GFX engine and CPG blocks (CIK).
- * XXX: deal with reseting RLC and CPF
- * Returns 0 for success.
- */
-static int cik_gfx_gpu_soft_reset(struct radeon_device *rdev)
+static void cik_print_gpu_status_regs(struct radeon_device *rdev)
 {
-	struct evergreen_mc_save save;
-	u32 grbm_reset = 0;
-
-	if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
-		return 0;
-
-	dev_info(rdev->dev, "GPU GFX softreset \n");
 	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
 		RREG32(GRBM_STATUS));
 	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
@@ -2799,132 +2754,270 @@ static int cik_gfx_gpu_soft_reset(struct radeon_device *rdev)
 		RREG32(SRBM_STATUS));
 	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
 		RREG32(SRBM_STATUS2));
-	evergreen_mc_stop(rdev, &save);
-	if (radeon_mc_wait_for_idle(rdev)) {
-		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
-	}
-	/* Disable CP parsing/prefetching */
-	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+	dev_info(rdev->dev, "  SDMA0_STATUS_REG   = 0x%08X\n",
+		RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
+	dev_info(rdev->dev, "  SDMA1_STATUS_REG   = 0x%08X\n",
+		 RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
+}
 
-	/* reset all the gfx block and all CPG blocks */
-	grbm_reset = SOFT_RESET_CPG | SOFT_RESET_GFX;
+/**
+ * cik_gpu_check_soft_reset - check which blocks are busy
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Check which blocks are busy and return the relevant reset
+ * mask to be used by cik_gpu_soft_reset().
+ * Returns a mask of the blocks to be reset.
+ */
+static u32 cik_gpu_check_soft_reset(struct radeon_device *rdev)
+{
+	u32 reset_mask = 0;
+	u32 tmp;
 
-	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
-	WREG32(GRBM_SOFT_RESET, grbm_reset);
-	(void)RREG32(GRBM_SOFT_RESET);
-	udelay(50);
-	WREG32(GRBM_SOFT_RESET, 0);
-	(void)RREG32(GRBM_SOFT_RESET);
-	/* Wait a little for things to settle down */
-	udelay(50);
-	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
-		RREG32(GRBM_STATUS));
-	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
-		RREG32(GRBM_STATUS2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
-		RREG32(GRBM_STATUS_SE0));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
-		RREG32(GRBM_STATUS_SE1));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
-		RREG32(GRBM_STATUS_SE2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
-		RREG32(GRBM_STATUS_SE3));
-	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
-		RREG32(SRBM_STATUS));
-	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
-		RREG32(SRBM_STATUS2));
-	evergreen_mc_resume(rdev, &save);
-	return 0;
+	/* GRBM_STATUS */
+	tmp = RREG32(GRBM_STATUS);
+	if (tmp & (PA_BUSY | SC_BUSY |
+		   BCI_BUSY | SX_BUSY |
+		   TA_BUSY | VGT_BUSY |
+		   DB_BUSY | CB_BUSY |
+		   GDS_BUSY | SPI_BUSY |
+		   IA_BUSY | IA_BUSY_NO_DMA))
+		reset_mask |= RADEON_RESET_GFX;
+
+	if (tmp & (CP_BUSY | CP_COHERENCY_BUSY))
+		reset_mask |= RADEON_RESET_CP;
+
+	/* GRBM_STATUS2 */
+	tmp = RREG32(GRBM_STATUS2);
+	if (tmp & RLC_BUSY)
+		reset_mask |= RADEON_RESET_RLC;
+
+	/* SDMA0_STATUS_REG */
+	tmp = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+	if (!(tmp & SDMA_IDLE))
+		reset_mask |= RADEON_RESET_DMA;
+
+	/* SDMA1_STATUS_REG */
+	tmp = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
+	if (!(tmp & SDMA_IDLE))
+		reset_mask |= RADEON_RESET_DMA1;
+
+	/* SRBM_STATUS2 */
+	tmp = RREG32(SRBM_STATUS2);
+	if (tmp & SDMA_BUSY)
+		reset_mask |= RADEON_RESET_DMA;
+
+	if (tmp & SDMA1_BUSY)
+		reset_mask |= RADEON_RESET_DMA1;
+
+	/* SRBM_STATUS */
+	tmp = RREG32(SRBM_STATUS);
+
+	if (tmp & IH_BUSY)
+		reset_mask |= RADEON_RESET_IH;
+
+	if (tmp & SEM_BUSY)
+		reset_mask |= RADEON_RESET_SEM;
+
+	if (tmp & GRBM_RQ_PENDING)
+		reset_mask |= RADEON_RESET_GRBM;
+
+	if (tmp & VMC_BUSY)
+		reset_mask |= RADEON_RESET_VMC;
+
+	if (tmp & (MCB_BUSY | MCB_NON_DISPLAY_BUSY |
+		   MCC_BUSY | MCD_BUSY))
+		reset_mask |= RADEON_RESET_MC;
+
+	if (evergreen_is_display_hung(rdev))
+		reset_mask |= RADEON_RESET_DISPLAY;
+
+	/* Skip MC reset as it's mostly likely not hung, just busy */
+	if (reset_mask & RADEON_RESET_MC) {
+		DRM_DEBUG("MC busy: 0x%08X, clearing.\n", reset_mask);
+		reset_mask &= ~RADEON_RESET_MC;
+	}
+
+	return reset_mask;
 }
 
 /**
- * cik_compute_gpu_soft_reset - soft reset CPC
+ * cik_gpu_soft_reset - soft reset GPU
  *
  * @rdev: radeon_device pointer
+ * @reset_mask: mask of which blocks to reset
  *
- * Soft reset the CPC blocks (CIK).
- * XXX: deal with reseting RLC and CPF
- * Returns 0 for success.
+ * Soft reset the blocks specified in @reset_mask.
  */
-static int cik_compute_gpu_soft_reset(struct radeon_device *rdev)
+static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
 {
 	struct evergreen_mc_save save;
-	u32 grbm_reset = 0;
+	u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+	u32 tmp;
+
+	if (reset_mask == 0)
+		return;
+
+	dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+	cik_print_gpu_status_regs(rdev);
+	dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
+		 RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+	dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+		 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+
+	/* stop the rlc */
+	cik_rlc_stop(rdev);
+
+	/* Disable GFX parsing/prefetching */
+	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+	/* Disable MEC parsing/prefetching */
+	WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
+
+	if (reset_mask & RADEON_RESET_DMA) {
+		/* sdma0 */
+		tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET);
+		tmp |= SDMA_HALT;
+		WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+	}
+	if (reset_mask & RADEON_RESET_DMA1) {
+		/* sdma1 */
+		tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET);
+		tmp |= SDMA_HALT;
+		WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+	}
 
-	dev_info(rdev->dev, "GPU compute softreset \n");
-	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
-		RREG32(GRBM_STATUS));
-	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
-		RREG32(GRBM_STATUS2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
-		RREG32(GRBM_STATUS_SE0));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
-		RREG32(GRBM_STATUS_SE1));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
-		RREG32(GRBM_STATUS_SE2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
-		RREG32(GRBM_STATUS_SE3));
-	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
-		RREG32(SRBM_STATUS));
-	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
-		RREG32(SRBM_STATUS2));
 	evergreen_mc_stop(rdev, &save);
-	if (radeon_mc_wait_for_idle(rdev)) {
+	if (evergreen_mc_wait_for_idle(rdev)) {
 		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
 	}
-	/* Disable CP parsing/prefetching */
-	WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
 
-	/* reset all the CPC blocks */
-	grbm_reset = SOFT_RESET_CPG;
+	if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE | RADEON_RESET_CP))
+		grbm_soft_reset = SOFT_RESET_CP | SOFT_RESET_GFX;
+
+	if (reset_mask & RADEON_RESET_CP) {
+		grbm_soft_reset |= SOFT_RESET_CP;
+
+		srbm_soft_reset |= SOFT_RESET_GRBM;
+	}
+
+	if (reset_mask & RADEON_RESET_DMA)
+		srbm_soft_reset |= SOFT_RESET_SDMA;
+
+	if (reset_mask & RADEON_RESET_DMA1)
+		srbm_soft_reset |= SOFT_RESET_SDMA1;
+
+	if (reset_mask & RADEON_RESET_DISPLAY)
+		srbm_soft_reset |= SOFT_RESET_DC;
+
+	if (reset_mask & RADEON_RESET_RLC)
+		grbm_soft_reset |= SOFT_RESET_RLC;
+
+	if (reset_mask & RADEON_RESET_SEM)
+		srbm_soft_reset |= SOFT_RESET_SEM;
+
+	if (reset_mask & RADEON_RESET_IH)
+		srbm_soft_reset |= SOFT_RESET_IH;
+
+	if (reset_mask & RADEON_RESET_GRBM)
+		srbm_soft_reset |= SOFT_RESET_GRBM;
+
+	if (reset_mask & RADEON_RESET_VMC)
+		srbm_soft_reset |= SOFT_RESET_VMC;
+
+	if (!(rdev->flags & RADEON_IS_IGP)) {
+		if (reset_mask & RADEON_RESET_MC)
+			srbm_soft_reset |= SOFT_RESET_MC;
+	}
+
+	if (grbm_soft_reset) {
+		tmp = RREG32(GRBM_SOFT_RESET);
+		tmp |= grbm_soft_reset;
+		dev_info(rdev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
+		WREG32(GRBM_SOFT_RESET, tmp);
+		tmp = RREG32(GRBM_SOFT_RESET);
+
+		udelay(50);
+
+		tmp &= ~grbm_soft_reset;
+		WREG32(GRBM_SOFT_RESET, tmp);
+		tmp = RREG32(GRBM_SOFT_RESET);
+	}
+
+	if (srbm_soft_reset) {
+		tmp = RREG32(SRBM_SOFT_RESET);
+		tmp |= srbm_soft_reset;
+		dev_info(rdev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+		WREG32(SRBM_SOFT_RESET, tmp);
+		tmp = RREG32(SRBM_SOFT_RESET);
+
+		udelay(50);
+
+		tmp &= ~srbm_soft_reset;
+		WREG32(SRBM_SOFT_RESET, tmp);
+		tmp = RREG32(SRBM_SOFT_RESET);
+	}
 
-	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
-	WREG32(GRBM_SOFT_RESET, grbm_reset);
-	(void)RREG32(GRBM_SOFT_RESET);
-	udelay(50);
-	WREG32(GRBM_SOFT_RESET, 0);
-	(void)RREG32(GRBM_SOFT_RESET);
 	/* Wait a little for things to settle down */
 	udelay(50);
-	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
-		RREG32(GRBM_STATUS));
-	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
-		RREG32(GRBM_STATUS2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
-		RREG32(GRBM_STATUS_SE0));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
-		RREG32(GRBM_STATUS_SE1));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
-		RREG32(GRBM_STATUS_SE2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
-		RREG32(GRBM_STATUS_SE3));
-	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
-		RREG32(SRBM_STATUS));
-	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
-		RREG32(SRBM_STATUS2));
+
 	evergreen_mc_resume(rdev, &save);
-	return 0;
+	udelay(50);
+
+	cik_print_gpu_status_regs(rdev);
 }
 
 /**
- * cik_asic_reset - soft reset compute and gfx
+ * cik_asic_reset - soft reset GPU
  *
  * @rdev: radeon_device pointer
  *
- * Soft reset the CPC blocks (CIK).
- * XXX: make this more fine grained and only reset
- * what is necessary.
+ * Look up which blocks are hung and attempt
+ * to reset them.
  * Returns 0 for success.
  */
 int cik_asic_reset(struct radeon_device *rdev)
 {
-	int r;
+	u32 reset_mask;
 
-	r = cik_compute_gpu_soft_reset(rdev);
-	if (r)
-		dev_info(rdev->dev, "Compute reset failed!\n");
+	reset_mask = cik_gpu_check_soft_reset(rdev);
+
+	if (reset_mask)
+		r600_set_bios_scratch_engine_hung(rdev, true);
+
+	cik_gpu_soft_reset(rdev, reset_mask);
 
-	return cik_gfx_gpu_soft_reset(rdev);
+	reset_mask = cik_gpu_check_soft_reset(rdev);
+
+	if (!reset_mask)
+		r600_set_bios_scratch_engine_hung(rdev, false);
+
+	return 0;
+}
+
+/**
+ * cik_gfx_is_lockup - check if the 3D engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the 3D engine is locked up (CIK).
+ * Returns true if the engine is locked, false if not.
+ */
+bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	u32 reset_mask = cik_gpu_check_soft_reset(rdev);
+
+	if (!(reset_mask & (RADEON_RESET_GFX |
+			    RADEON_RESET_COMPUTE |
+			    RADEON_RESET_CP))) {
+		radeon_ring_lockup_update(ring);
+		return false;
+	}
+	/* force CP activities */
+	radeon_ring_force_activity(rdev, ring);
+	return radeon_ring_test_lockup(rdev, ring);
 }
 
 /**
@@ -2938,13 +3031,15 @@ int cik_asic_reset(struct radeon_device *rdev)
  */
 bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-	u32 dma_status_reg;
+	u32 reset_mask = cik_gpu_check_soft_reset(rdev);
+	u32 mask;
 
 	if (ring->idx == R600_RING_TYPE_DMA_INDEX)
-		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+		mask = RADEON_RESET_DMA;
 	else
-		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
-	if (dma_status_reg & SDMA_IDLE) {
+		mask = RADEON_RESET_DMA1;
+
+	if (!(reset_mask & mask)) {
 		radeon_ring_lockup_update(ring);
 		return false;
 	}
drivers/gpu/drm/radeon/cikd.h +12 -0
index daa51ac..8afb334 100644
@@ -40,7 +40,19 @@
 #define		QUEUEID(x)					((x) << 8)
 
 #define	SRBM_STATUS2				        0xE4C
+#define		SDMA_BUSY 				(1 << 5)
+#define		SDMA1_BUSY 				(1 << 6)
 #define	SRBM_STATUS				        0xE50
+#define		UVD_RQ_PENDING 				(1 << 1)
+#define		GRBM_RQ_PENDING 			(1 << 5)
+#define		VMC_BUSY 				(1 << 8)
+#define		MCB_BUSY 				(1 << 9)
+#define		MCB_NON_DISPLAY_BUSY 			(1 << 10)
+#define		MCC_BUSY 				(1 << 11)
+#define		MCD_BUSY 				(1 << 12)
+#define		SEM_BUSY 				(1 << 14)
+#define		IH_BUSY 				(1 << 17)
+#define		UVD_BUSY 				(1 << 19)
 
 #define	SRBM_SOFT_RESET				        0xE60
 #define		SOFT_RESET_BIF				(1 << 1)
Signature · 1 line
1.7.7.5
#44 lore raw

PATCH 43/165 drm/radeon: add indirect register accessors for SMC registers

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/evergreen_reg.h |    4 ++++
 drivers/gpu/drm/radeon/radeon.h        |   17 +++++++++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/evergreen_reg.h +4 -0
index 881aba2..50948ac 100644
@@ -24,6 +24,10 @@
 #ifndef __EVERGREEN_REG_H__
 #define __EVERGREEN_REG_H__
 
+/* trinity */
+#define TN_SMC_IND_INDEX_0                              0x200
+#define TN_SMC_IND_DATA_0                               0x204
+
 /* evergreen */
 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS               0x310
 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH          0x324
drivers/gpu/drm/radeon/radeon.h +17 -0
index b329e99..9af0fa6 100644
@@ -1806,6 +1806,8 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 #define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v))
 #define RREG32_PCIE_PORT(reg) rdev->pciep_rreg(rdev, (reg))
 #define WREG32_PCIE_PORT(reg, v) rdev->pciep_wreg(rdev, (reg), (v))
+#define RREG32_SMC(reg) tn_smc_rreg(rdev, (reg))
+#define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v))
 #define WREG32_P(reg, val, mask)				\
 	do {							\
 		uint32_t tmp_ = RREG32(reg);			\
@@ -1844,6 +1846,21 @@ static inline void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uin
 	WREG32(RADEON_PCIE_DATA, (v));
 }
 
+static inline u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(TN_SMC_IND_INDEX_0, (reg));
+	r = RREG32(TN_SMC_IND_DATA_0);
+	return r;
+}
+
+static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(TN_SMC_IND_INDEX_0, (reg));
+	WREG32(TN_SMC_IND_DATA_0, (v));
+}
+
 void r100_pll_errata_after_index(struct radeon_device *rdev);
 
 
Signature · 1 line
1.7.7.5
#45 lore raw

PATCH 44/165 drm/radeon: add get_xclk() callback for CIK

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/cik.c         |   22 ++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |    7 +++++++
 drivers/gpu/drm/radeon/radeon_asic.h |    1 +
 3 files changed, 30 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +22 -0
index aaf7bba..0db0ebc 100644
@@ -78,6 +78,28 @@ extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
 static void cik_rlc_stop(struct radeon_device *rdev);
 
+/**
+ * cik_get_xclk - get the xclk
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Returns the reference clock used by the gfx engine
+ * (CIK).
+ */
+u32 cik_get_xclk(struct radeon_device *rdev)
+{
+        u32 reference_clock = rdev->clock.spll.reference_freq;
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		if (RREG32_SMC(GENERAL_PWRMGT) & GPU_COUNTER_CLK)
+			return reference_clock / 2;
+	} else {
+		if (RREG32_SMC(CG_CLKPIN_CNTL) & XTALIN_DIVIDE)
+			return reference_clock / 4;
+	}
+	return reference_clock;
+}
+
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
 static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
drivers/gpu/drm/radeon/cikd.h +7 -0
index 8afb334..f00e273 100644
@@ -28,6 +28,13 @@
 
 #define CIK_RB_BITMAP_WIDTH_PER_SH  2
 
+/* SMC IND registers */
+#define GENERAL_PWRMGT                                    0xC0200000
+#       define GPU_COUNTER_CLK                            (1 << 15)
+
+#define CG_CLKPIN_CNTL                                    0xC05001A0
+#       define XTALIN_DIVIDE                              (1 << 1)
+
 #define VGA_HDP_CONTROL  				0x328
 #define		VGA_MEMORY_DISABLE				(1 << 4)
 
drivers/gpu/drm/radeon/radeon_asic.h +1 -0
index 248da72..05f75f7 100644
@@ -557,5 +557,6 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
  * cik
  */
 uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
+u32 cik_get_xclk(struct radeon_device *rdev);
 
 #endif
Signature · 1 line
1.7.7.5
#46 lore raw

PATCH 45/165 drm/radeon/cik: add pcie_port indirect register accessors

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/cik.c         |   21 +++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |    3 +++
 drivers/gpu/drm/radeon/radeon_asic.c |    6 +++++-
 drivers/gpu/drm/radeon/radeon_asic.h |    2 ++
 4 files changed, 31 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/cik.c +21 -0
index 0db0ebc..e8ea845 100644
@@ -78,6 +78,27 @@ extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
 static void cik_rlc_stop(struct radeon_device *rdev);
 
+/*
+ * Indirect registers accessor
+ */
+u32 cik_pciep_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(PCIE_INDEX, reg);
+	(void)RREG32(PCIE_INDEX);
+	r = RREG32(PCIE_DATA);
+	return r;
+}
+
+void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(PCIE_INDEX, reg);
+	(void)RREG32(PCIE_INDEX);
+	WREG32(PCIE_DATA, v);
+	(void)RREG32(PCIE_DATA);
+}
+
 /**
  * cik_get_xclk - get the xclk
  *
drivers/gpu/drm/radeon/cikd.h +3 -0
index f00e273..d23809a 100644
@@ -35,6 +35,9 @@
 #define CG_CLKPIN_CNTL                                    0xC05001A0
 #       define XTALIN_DIVIDE                              (1 << 1)
 
+#define PCIE_INDEX  					0x38
+#define PCIE_DATA  					0x3C
+
 #define VGA_HDP_CONTROL  				0x328
 #define		VGA_MEMORY_DISABLE				(1 << 4)
 
drivers/gpu/drm/radeon/radeon_asic.c +5 -1
index a2802b47..717b537 100644
@@ -126,7 +126,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
 		rdev->mc_rreg = &rs780_mc_rreg;
 		rdev->mc_wreg = &rs780_mc_wreg;
 	}
-	if (rdev->family >= CHIP_R600) {
+
+	if (rdev->family >= CHIP_BONAIRE) {
+		rdev->pciep_rreg = &cik_pciep_rreg;
+		rdev->pciep_wreg = &cik_pciep_wreg;
+	} else if (rdev->family >= CHIP_R600) {
 		rdev->pciep_rreg = &r600_pciep_rreg;
 		rdev->pciep_wreg = &r600_pciep_wreg;
 	}
drivers/gpu/drm/radeon/radeon_asic.h +2 -0
index 05f75f7..8c19e36 100644
@@ -558,5 +558,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
  */
 uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
 u32 cik_get_xclk(struct radeon_device *rdev);
+uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
+void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 
 #endif
Signature · 1 line
1.7.7.5
#47 lore raw

PATCH 46/165 drm/radeon: update radeon_atom_get_clock_dividers() for SI

In reply to [email protected]

From: Alex Deucher <[email protected]>

SI uses v5 of the command table and uses a different table for memory PLLs.

---
 drivers/gpu/drm/radeon/radeon_atombios.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/radeon_atombios.c +5 -1
index 3236755..774e354 100644
@@ -2732,7 +2732,8 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 		break;
 	case 2:
 	case 3:
-		/* r6xx, r7xx, evergreen, ni */
+	case 5:
+		/* r6xx, r7xx, evergreen, ni, si */
 		if (rdev->family <= CHIP_RV770) {
 			args.v2.ucAction = clock_type;
 			args.v2.ulClock = cpu_to_le32(clock);	/* 10 khz */
@@ -2765,6 +2766,9 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 				dividers->vco_mode = (args.v3.ucCntlFlag &
 						      ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
 			} else {
+				/* for SI we use ComputeMemoryClockParam for memory plls */
+				if (rdev->family >= CHIP_TAHITI)
+					return -EINVAL;
 				args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
 				if (strobe_mode)
 					args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
Signature · 1 line
1.7.7.5
#48 lore raw

PATCH 47/165 drm/radeon: update radeon_atom_get_clock_dividers for CIK

In reply to [email protected]

From: Alex Deucher <[email protected]>

CIK uses a slightly different variant of the table structs and params.

---
 drivers/gpu/drm/radeon/radeon_atombios.c |   20 +++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_mode.h     |    3 +++
 2 files changed, 22 insertions(+), 1 deletions(-)
drivers/gpu/drm/radeon/radeon_atombios.c +19 -1
index 774e354..bf3b924 100644
@@ -2700,6 +2700,8 @@ union get_clock_dividers {
 	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;
 	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;
 	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;
+	struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;
+	struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;
 };
 
 int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
@@ -2794,9 +2796,25 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 
 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 
-		dividers->post_div = args.v4.ucPostDiv;
+		dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
 		dividers->real_clock = le32_to_cpu(args.v4.ulClock);
 		break;
+	case 6:
+		/* CI */
+		/* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */
+		args.v6_in.ulClock.ulComputeClockFlag = clock_type;
+		args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock);	/* 10 khz */
+
+		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+		dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
+		dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
+		dividers->ref_div = args.v6_out.ucPllRefDiv;
+		dividers->post_div = args.v6_out.ucPllPostDiv;
+		dividers->flags = args.v6_out.ucPllCntlFlag;
+		dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);
+		dividers->post_divider = args.v6_out.ulClock.ucPostDiv;
+		break;
 	default:
 		return -EINVAL;
 	}
drivers/gpu/drm/radeon/radeon_mode.h +3 -0
index 4ed0a4c..576511f 100644
@@ -514,6 +514,9 @@ struct atom_clock_dividers {
 	bool enable_dithen;
 	u32 vco_mode;
 	u32 real_clock;
+	/* added for CI */
+	u32 post_divider;
+	u32 flags;
 };
 
 extern enum radeon_tv_std
Signature · 1 line
1.7.7.5
#49 lore raw

PATCH 48/165 drm/radeon: add UVD support for CIK (v3)

In reply to [email protected]

From: Christian König <[email protected]>

v2: agd5f: fix clock dividers setup for bonaire
v3: agd5f: rebase

---
 drivers/gpu/drm/radeon/cik.c         |  111 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |   28 +++++++++
 drivers/gpu/drm/radeon/radeon_asic.h |    2 +
 drivers/gpu/drm/radeon/radeon_uvd.c  |    8 +++
 4 files changed, 149 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +111 -0
index e8ea845..29e0cdd 100644
@@ -1495,6 +1495,9 @@ static void cik_gpu_init(struct radeon_device *rdev)
 	WREG32(DMIF_ADDR_CALC, gb_addr_config);
 	WREG32(SDMA0_TILING_CONFIG + SDMA0_REGISTER_OFFSET, gb_addr_config & 0x70);
 	WREG32(SDMA0_TILING_CONFIG + SDMA1_REGISTER_OFFSET, gb_addr_config & 0x70);
+	WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config);
+	WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config);
+	WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config);
 
 	cik_tiling_mode_table_init(rdev);
 
@@ -4906,6 +4909,16 @@ static int cik_startup(struct radeon_device *rdev)
 		return r;
 	}
 
+	r = cik_uvd_resume(rdev);
+	if (!r) {
+		r = radeon_fence_driver_start_ring(rdev,
+						   R600_RING_TYPE_UVD_INDEX);
+		if (r)
+			dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
+	}
+	if (r)
+		rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+
 	/* Enable IRQ */
 	if (!rdev->irq.installed) {
 		r = radeon_irq_kms_init(rdev);
@@ -4952,6 +4965,18 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+	if (ring->ring_size) {
+		r = radeon_ring_init(rdev, ring, ring->ring_size,
+				     R600_WB_UVD_RPTR_OFFSET,
+				     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
+				     0, 0xfffff, RADEON_CP_PACKET2);
+		if (!r)
+			r = r600_uvd_init(rdev);
+		if (r)
+			DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
+	}
+
 	r = radeon_ib_pool_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@@ -5013,6 +5038,8 @@ int cik_suspend(struct radeon_device *rdev)
 	radeon_vm_manager_fini(rdev);
 	cik_cp_enable(rdev, false);
 	cik_sdma_enable(rdev, false);
+	r600_uvd_rbc_stop(rdev);
+	radeon_uvd_suspend(rdev);
 	cik_irq_suspend(rdev);
 	radeon_wb_disable(rdev);
 	cik_pcie_gart_disable(rdev);
@@ -5096,6 +5123,13 @@ int cik_init(struct radeon_device *rdev)
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 256 * 1024);
 
+	r = radeon_uvd_init(rdev);
+	if (!r) {
+		ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+		ring->ring_obj = NULL;
+		r600_ring_init(rdev, ring, 4096);
+	}
+
 	rdev->ih.ring_obj = NULL;
 	r600_ih_ring_init(rdev, 64 * 1024);
 
@@ -5150,6 +5184,7 @@ void cik_fini(struct radeon_device *rdev)
 	radeon_vm_manager_fini(rdev);
 	radeon_ib_pool_fini(rdev);
 	radeon_irq_kms_fini(rdev);
+	radeon_uvd_fini(rdev);
 	cik_pcie_gart_fini(rdev);
 	r600_vram_scratch_fini(rdev);
 	radeon_gem_fini(rdev);
@@ -5717,3 +5752,79 @@ uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev)
 	return clock;
 }
 
+static int cik_set_uvd_clock(struct radeon_device *rdev, u32 clock,
+                              u32 cntl_reg, u32 status_reg)
+{
+	int r, i;
+	struct atom_clock_dividers dividers;
+	uint32_t tmp;
+
+	r = radeon_atom_get_clock_dividers(rdev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+					   clock, false, &dividers);
+	if (r)
+		return r;
+
+	tmp = RREG32_SMC(cntl_reg);
+	tmp &= ~(DCLK_DIR_CNTL_EN|DCLK_DIVIDER_MASK);
+	tmp |= dividers.post_divider;
+	WREG32_SMC(cntl_reg, tmp);
+
+	for (i = 0; i < 100; i++) {
+		if (RREG32_SMC(status_reg) & DCLK_STATUS)
+			break;
+		mdelay(10);
+	}
+	if (i == 100)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
+{
+	int r = 0;
+
+	r = cik_set_uvd_clock(rdev, vclk, CG_VCLK_CNTL, CG_VCLK_STATUS);
+	if (r)
+		return r;
+
+	r = cik_set_uvd_clock(rdev, dclk, CG_DCLK_CNTL, CG_DCLK_STATUS);
+	return r;
+}
+
+int cik_uvd_resume(struct radeon_device *rdev)
+{
+	uint64_t addr;
+	uint32_t size;
+	int r;
+
+	r = radeon_uvd_resume(rdev);
+	if (r)
+		return r;
+
+	/* programm the VCPU memory controller bits 0-27 */
+	addr = rdev->uvd.gpu_addr >> 3;
+	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
+	WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
+	WREG32(UVD_VCPU_CACHE_SIZE0, size);
+
+	addr += size;
+	size = RADEON_UVD_STACK_SIZE >> 3;
+	WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
+	WREG32(UVD_VCPU_CACHE_SIZE1, size);
+
+	addr += size;
+	size = RADEON_UVD_HEAP_SIZE >> 3;
+	WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
+	WREG32(UVD_VCPU_CACHE_SIZE2, size);
+
+	/* bits 28-31 */
+	addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
+	WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
+
+	/* bits 32-39 */
+	addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
+	WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
+
+	return 0;
+}
drivers/gpu/drm/radeon/cikd.h +28 -0
index d23809a..79be39e 100644
@@ -1204,4 +1204,32 @@
 #       define SDMA_SRBM_WRITE_EXTRA_BYTE_ENABLE(x)       ((x) << 12)
                 /* byte mask */
 
+/* UVD */
+
+#define UVD_UDEC_ADDR_CONFIG		0xef4c
+#define UVD_UDEC_DB_ADDR_CONFIG		0xef50
+#define UVD_UDEC_DBW_ADDR_CONFIG	0xef54
+
+#define UVD_LMI_EXT40_ADDR		0xf498
+#define UVD_LMI_ADDR_EXT		0xf594
+#define UVD_VCPU_CACHE_OFFSET0		0xf608
+#define UVD_VCPU_CACHE_SIZE0		0xf60c
+#define UVD_VCPU_CACHE_OFFSET1		0xf610
+#define UVD_VCPU_CACHE_SIZE1		0xf614
+#define UVD_VCPU_CACHE_OFFSET2		0xf618
+#define UVD_VCPU_CACHE_SIZE2		0xf61c
+
+#define UVD_RBC_RB_RPTR			0xf690
+#define UVD_RBC_RB_WPTR			0xf694
+
+/* UVD clocks */
+
+#define CG_DCLK_CNTL			0xC050009C
+#	define DCLK_DIVIDER_MASK	0x7f
+#	define DCLK_DIR_CNTL_EN		(1 << 8)
+#define CG_DCLK_STATUS			0xC05000A0
+#	define DCLK_STATUS		(1 << 0)
+#define CG_VCLK_CNTL			0xC05000A4
+#define CG_VCLK_STATUS			0xC05000A8
+
 #endif
drivers/gpu/drm/radeon/radeon_asic.h +2 -0
index 8c19e36..3405742 100644
@@ -560,5 +560,7 @@ uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
 u32 cik_get_xclk(struct radeon_device *rdev);
 uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
 void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int cik_uvd_resume(struct radeon_device *rdev);
 
 #endif
drivers/gpu/drm/radeon/radeon_uvd.c +8 -0
index cad735d..fdc77d1 100644
@@ -44,11 +44,13 @@
 #define FIRMWARE_CYPRESS	"radeon/CYPRESS_uvd.bin"
 #define FIRMWARE_SUMO		"radeon/SUMO_uvd.bin"
 #define FIRMWARE_TAHITI		"radeon/TAHITI_uvd.bin"
+#define FIRMWARE_BONAIRE	"radeon/BONAIRE_uvd.bin"
 
 MODULE_FIRMWARE(FIRMWARE_RV710);
 MODULE_FIRMWARE(FIRMWARE_CYPRESS);
 MODULE_FIRMWARE(FIRMWARE_SUMO);
 MODULE_FIRMWARE(FIRMWARE_TAHITI);
+MODULE_FIRMWARE(FIRMWARE_BONAIRE);
 
 static void radeon_uvd_idle_work_handler(struct work_struct *work);
 
@@ -100,6 +102,12 @@ int radeon_uvd_init(struct radeon_device *rdev)
 		fw_name = FIRMWARE_TAHITI;
 		break;
 
+	case CHIP_BONAIRE:
+	case CHIP_KABINI:
+	case CHIP_KAVERI:
+		fw_name = FIRMWARE_BONAIRE;
+		break;
+
 	default:
 		return -EINVAL;
 	}
Signature · 6 lines
1.7.7.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#50 lore raw

PATCH 49/165 drm/radeon/cik: add srbm_select function

In reply to [email protected]

From: Alex Deucher <[email protected]>

Allows us to select instanced registers based on:
- ME (micro engine
- Pipe
- Queue
- VMID

Switch MC setup to use this new function.

---
 drivers/gpu/drm/radeon/cik.c |   27 +++++++++++++++++++++++++--
 1 files changed, 25 insertions(+), 2 deletions(-)
drivers/gpu/drm/radeon/cik.c +25 -2
index 29e0cdd..bb7dbc4 100644
@@ -163,6 +163,29 @@ static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
 	{0x0000009f, 0x00b48000}
 };
 
+/**
+ * cik_srbm_select - select specific register instances
+ *
+ * @rdev: radeon_device pointer
+ * @me: selected ME (micro engine)
+ * @pipe: pipe
+ * @queue: queue
+ * @vmid: VMID
+ *
+ * Switches the currently active registers instances.  Some
+ * registers are instanced per VMID, others are instanced per
+ * me/pipe/queue combination.
+ */
+static void cik_srbm_select(struct radeon_device *rdev,
+			    u32 me, u32 pipe, u32 queue, u32 vmid)
+{
+	u32 srbm_gfx_cntl = (PIPEID(pipe & 0x3) |
+			     MEID(me & 0x3) |
+			     VMID(vmid & 0xf) |
+			     QUEUEID(queue & 0x7));
+	WREG32(SRBM_GFX_CNTL, srbm_gfx_cntl);
+}
+
 /* ucode loading */
 /**
  * ci_mc_load_microcode - load MC ucode into the hw
@@ -3351,7 +3374,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 	/* XXX SH_MEM regs */
 	/* where to put LDS, scratch, GPUVM in FSA64 space */
 	for (i = 0; i < 16; i++) {
-		WREG32(SRBM_GFX_CNTL, VMID(i));
+		cik_srbm_select(rdev, 0, 0, 0, i);
 		/* CP and shaders */
 		WREG32(SH_MEM_CONFIG, 0);
 		WREG32(SH_MEM_APE1_BASE, 1);
@@ -3364,7 +3387,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 		WREG32(SDMA0_GFX_APE1_CNTL + SDMA1_REGISTER_OFFSET, 0);
 		/* XXX SDMA RLC - todo */
 	}
-	WREG32(SRBM_GFX_CNTL, 0);
+	cik_srbm_select(rdev, 0, 0, 0, 0);
 
 	cik_pcie_gart_tlb_flush(rdev);
 	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
Signature · 1 line
1.7.7.5
#51 lore raw

PATCH 50/165 drm/radeon: use callbacks for ring pointer handling

In reply to [email protected]

From: Alex Deucher <[email protected]>

Add callbacks to the radeon_ring struct to handle rptr/wptr fetchs and wptr updates.
We currently use one version for all rings, but this allows us to override with a ring specific versions.

Needed for compute rings on CIK.

---
 drivers/gpu/drm/radeon/radeon.h      |    5 +++
 drivers/gpu/drm/radeon/radeon_ring.c |   55 +++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 14 deletions(-)
drivers/gpu/drm/radeon/radeon.h +5 -0
index 9af0fa6..ad4e68a 100644
@@ -695,6 +695,11 @@ struct radeon_ring {
 	u32			idx;
 	u64			last_semaphore_signal_addr;
 	u64			last_semaphore_wait_addr;
+	struct {
+		u32			(*get_rptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+	} funcs;
 };
 
 /*
drivers/gpu/drm/radeon/radeon_ring.c +41 -14

98 lines not on this page · raw message

Signature · 1 line
1.7.7.5
#52 lore raw

Re: [PATCH 050/165] drm/radeon: use callbacks for ring pointer handling

Am 26.06.2013 15:22, schrieb [email protected]:

Quoted 10 lines

From: Alex Deucher <[email protected]>

Add callbacks to the radeon_ring struct to handle rptr/wptr fetchs and wptr updates.
We currently use one version for all rings, but this allows us to override with a ring specific versions.

Needed for compute rings on CIK.

I'm ok with the general idea but let's put those callback into the radeon_asic.ring structure where they belong.

With this we should be able to remove most of the UVD and ptr_reg_shift/ptr_reg_mask special case handling.

Christian.

Quoted 130 lines
---
  drivers/gpu/drm/radeon/radeon.h      |    5 +++
  drivers/gpu/drm/radeon/radeon_ring.c |   55 +++++++++++++++++++++++++--------
  2 files changed, 46 insertions(+), 14 deletions(-)
drivers/gpu/drm/radeon/radeon.h +5 -0
index 9af0fa6..ad4e68a 100644
@@ -695,6 +695,11 @@ struct radeon_ring {
  	u32			idx;
  	u64			last_semaphore_signal_addr;
  	u64			last_semaphore_wait_addr;
+	struct {
+		u32			(*get_rptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+	} funcs;
  };
 
  /*
drivers/gpu/drm/radeon/radeon_ring.c +41 -14
index e17faa7..53018e9 100644
@@ -357,6 +357,38 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
  	}
  }
 
+static u32 radeon_ring_get_rptr(struct radeon_device *rdev,
+				struct radeon_ring *ring)
+{
+	u32 rptr;
+
+	if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
+		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+	else
+		rptr = RREG32(ring->rptr_reg);
+	rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return rptr;
+}
+
+static u32 radeon_ring_get_wptr(struct radeon_device *rdev,
+				struct radeon_ring *ring)
+{
+	u32 wptr;
+
+	wptr = RREG32(ring->wptr_reg);
+	wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return wptr;
+}
+
+static void radeon_ring_set_wptr(struct radeon_device *rdev,
+				 struct radeon_ring *ring)
+{
+	WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
+	(void)RREG32(ring->wptr_reg);
+}
+
  /**
   * radeon_ring_free_size - update the free size
   *
@@ -367,13 +399,7 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
   */
  void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring)
  {
-	u32 rptr;
-
-	if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
-		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
-	else
-		rptr = RREG32(ring->rptr_reg);
-	ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+	ring->rptr = ring->funcs.get_rptr(rdev, ring);
  	/* This works because ring_size is a power of 2 */
  	ring->ring_free_dw = (ring->rptr + (ring->ring_size / 4));
  	ring->ring_free_dw -= ring->wptr;
@@ -458,8 +484,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
  		radeon_ring_write(ring, ring->nop);
  	}
  	DRM_MEMORYBARRIER();
-	WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
-	(void)RREG32(ring->wptr_reg);
+	ring->funcs.set_wptr(rdev, ring);
  }
 
  /**
@@ -561,7 +586,6 @@ void radeon_ring_lockup_update(struct radeon_ring *ring)
  bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
  {
  	unsigned long cjiffies, elapsed;
-	uint32_t rptr;
 
  	cjiffies = jiffies;
  	if (!time_after(cjiffies, ring->last_activity)) {
@@ -569,8 +593,7 @@ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *rin
  		radeon_ring_lockup_update(ring);
  		return false;
  	}
-	rptr = RREG32(ring->rptr_reg);
-	ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+	ring->rptr = ring->funcs.get_rptr(rdev, ring);
  	if (ring->rptr != ring->last_rptr) {
  		/* CP is still working no lockup */
  		radeon_ring_lockup_update(ring);
@@ -708,6 +731,10 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
  	ring->ptr_reg_shift = ptr_reg_shift;
  	ring->ptr_reg_mask = ptr_reg_mask;
  	ring->nop = nop;
+	/* set the ptr callbacks */
+	ring->funcs.get_rptr = &radeon_ring_get_rptr;
+	ring->funcs.get_wptr = &radeon_ring_get_wptr;
+	ring->funcs.set_wptr = &radeon_ring_set_wptr;
  	/* Allocate ring buffer */
  	if (ring->ring_obj == NULL) {
  		r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true,
@@ -797,9 +824,9 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
 
  	radeon_ring_free_size(rdev, ring);
  	count = (ring->ring_size / 4) - ring->ring_free_dw;
-	tmp = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift;
+	tmp = ring->funcs.get_wptr(rdev, ring);
  	seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp);
-	tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift;
+	tmp = ring->funcs.get_rptr(rdev, ring);
  	seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp);
  	if (ring->rptr_save_reg) {
  		seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg,
#53 lore raw

PATCH 51/165 drm/radeon: implement simple doorbell page allocator

In reply to [email protected]

From: Alex Deucher <[email protected]>

The doorbell aperture is a PCI BAR whose pages can be mapped to compute resources for things like wptrs for userspace queues.

This patch maps the BAR and sets up a simple allocator to allocate pages from the BAR.

---
 drivers/gpu/drm/radeon/cik.c           |   38 +++++++++++++
 drivers/gpu/drm/radeon/radeon.h        |   21 +++++++
 drivers/gpu/drm/radeon/radeon_device.c |   94 ++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +38 -0
index bb7dbc4..5c28fa5 100644
@@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
 	return reference_clock;
 }
 
+/**
+ * cik_mm_rdoorbell - read a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ *
+ * Returns the value in the doorbell aperture at the
+ * requested offset (CIK).
+ */
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
+{
+	if (offset < rdev->doorbell.size) {
+		return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
+	} else {
+		DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
+		return 0;
+	}
+}
+
+/**
+ * cik_mm_wdoorbell - write a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ * @v: value to write
+ *
+ * Writes @v to the doorbell aperture at the
+ * requested offset (CIK).
+ */
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
+{
+	if (offset < rdev->doorbell.size) {
+		writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
+	} else {
+		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
+	}
+}
+
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
 static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
drivers/gpu/drm/radeon/radeon.h +21 -0
index ad4e68a..a2a3430 100644
@@ -556,6 +556,20 @@ struct radeon_scratch {
 int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
 void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
 
+/*
+ * GPU doorbell structures, functions & helpers
+ */
+struct radeon_doorbell {
+	u32			num_pages;
+	bool			free[1024];
+	/* doorbell mmio */
+	resource_size_t			base;
+	resource_size_t			size;
+	void __iomem			*ptr;
+};
+
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
 
 /*
  * IRQS.
@@ -1711,6 +1725,7 @@ struct radeon_device {
 	struct radeon_gart		gart;
 	struct radeon_mode_info		mode_info;
 	struct radeon_scratch		scratch;
+	struct radeon_doorbell		doorbell;
 	struct radeon_mman		mman;
 	struct radeon_fence_driver	fence_drv[RADEON_NUM_RINGS];
 	wait_queue_head_t		fence_queue;
@@ -1784,6 +1799,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
 u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
 void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
+
 /*
  * Cast helper
  */
@@ -1833,6 +1851,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
 #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
 
+#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
+#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
+
 /*
  * Indirect registers accessor
  */
drivers/gpu/drm/radeon/radeon_device.c +94 -0

112 lines not on this page · raw message

Signature · 1 line
1.7.7.5
#54 lore raw

Re: [PATCH 051/165] drm/radeon: implement simple doorbell page allocator

Quoted 8 lines · On Wed, Jun 26, 2013 at 09:22:11AM -0400, [email protected] wrote:

From: Alex Deucher <[email protected]>

The doorbell aperture is a PCI BAR whose pages can be mapped to compute resources for things like wptrs for userspace queues.

This patch maps the BAR and sets up a simple allocator to allocate pages from the BAR.

This doorbell stuff is cryptic, is that some memory on the GPU ? Or is it more like a register file ? ie what is backing the pci bar.

Also probably want to use bitmap as i dont think gcc will turn bool array into a bitmap.

Cheers,
Jerome

Quoted 236 lines
---
 drivers/gpu/drm/radeon/cik.c           |   38 +++++++++++++
 drivers/gpu/drm/radeon/radeon.h        |   21 +++++++
 drivers/gpu/drm/radeon/radeon_device.c |   94 ++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +38 -0
index bb7dbc4..5c28fa5 100644
@@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
 	return reference_clock;
 }
 
+/**
+ * cik_mm_rdoorbell - read a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ *
+ * Returns the value in the doorbell aperture at the
+ * requested offset (CIK).
+ */
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
+{
+	if (offset < rdev->doorbell.size) {
+		return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
+	} else {
+		DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
+		return 0;
+	}
+}
+
+/**
+ * cik_mm_wdoorbell - write a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ * @v: value to write
+ *
+ * Writes @v to the doorbell aperture at the
+ * requested offset (CIK).
+ */
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
+{
+	if (offset < rdev->doorbell.size) {
+		writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
+	} else {
+		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
+	}
+}
+
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
 static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
drivers/gpu/drm/radeon/radeon.h +21 -0
index ad4e68a..a2a3430 100644
@@ -556,6 +556,20 @@ struct radeon_scratch {
 int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
 void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
 
+/*
+ * GPU doorbell structures, functions & helpers
+ */
+struct radeon_doorbell {
+	u32			num_pages;
+	bool			free[1024];
+	/* doorbell mmio */
+	resource_size_t			base;
+	resource_size_t			size;
+	void __iomem			*ptr;
+};
+
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
 
 /*
  * IRQS.
@@ -1711,6 +1725,7 @@ struct radeon_device {
 	struct radeon_gart		gart;
 	struct radeon_mode_info		mode_info;
 	struct radeon_scratch		scratch;
+	struct radeon_doorbell		doorbell;
 	struct radeon_mman		mman;
 	struct radeon_fence_driver	fence_drv[RADEON_NUM_RINGS];
 	wait_queue_head_t		fence_queue;
@@ -1784,6 +1799,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
 u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
 void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
+
 /*
  * Cast helper
  */
@@ -1833,6 +1851,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
 #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
 
+#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
+#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
+
 /*
  * Indirect registers accessor
  */
drivers/gpu/drm/radeon/radeon_device.c +94 -0
index 4e97ff7..82335e3 100644
@@ -232,6 +232,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
 }
 
 /*
+ * GPU doorbell aperture helpers function.
+ */
+/**
+ * radeon_doorbell_init - Init doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Init doorbell driver information (CIK)
+ * Returns 0 on success, error on failure.
+ */
+int radeon_doorbell_init(struct radeon_device *rdev)
+{
+	int i;
+
+	/* doorbell bar mapping */
+	rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
+	rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
+
+	/* limit to 4 MB for now */
+	if (rdev->doorbell.size > (4 * 1024 * 1024))
+		rdev->doorbell.size = 4 * 1024 * 1024;
+
+	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
+	if (rdev->doorbell.ptr == NULL) {
+		return -ENOMEM;
+	}
+	DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
+	DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
+
+	rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE;
+
+	for (i = 0; i < rdev->doorbell.num_pages; i++) {
+		rdev->doorbell.free[i] = true;
+	}
+	return 0;
+}
+
+/**
+ * radeon_doorbell_fini - Tear down doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down doorbell driver information (CIK)
+ */
+void radeon_doorbell_fini(struct radeon_device *rdev)
+{
+	iounmap(rdev->doorbell.ptr);
+	rdev->doorbell.ptr = NULL;
+}
+
+/**
+ * radeon_doorbell_get - Allocate a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Allocate a doorbell page for use by the driver (all asics).
+ * Returns 0 on success or -EINVAL on failure.
+ */
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
+{
+	int i;
+
+	for (i = 0; i < rdev->doorbell.num_pages; i++) {
+		if (rdev->doorbell.free[i]) {
+			rdev->doorbell.free[i] = false;
+			*doorbell = i;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/**
+ * radeon_doorbell_free - Free a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Free a doorbell page allocated for use by the driver (all asics)
+ */
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
+{
+	if (doorbell < rdev->doorbell.num_pages)
+		rdev->doorbell.free[doorbell] = true;
+}
+
+/*
  * radeon_wb_*()
  * Writeback is the the method by which the the GPU updates special pages
  * in memory with the status of certain GPU events (fences, ring pointers,
@@ -1162,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev,
 	DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
 	DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
 
+	/* doorbell bar mapping */
+	if (rdev->family >= CHIP_BONAIRE)
+		radeon_doorbell_init(rdev);
+
 	/* io port mapping */
 	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 		if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
@@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
 	rdev->rio_mem = NULL;
 	iounmap(rdev->rmmio);
 	rdev->rmmio = NULL;
+	if (rdev->family >= CHIP_BONAIRE)
+		radeon_doorbell_fini(rdev);
 	radeon_debugfs_remove_files(rdev);
 }
 
Signature · 6 lines
1.7.7.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#55 lore raw

Re: [PATCH 051/165] drm/radeon: implement simple doorbell page allocator

Quoted 7 lines · Jerome Glisse
Quoted 6 lines · On Wed, Jun 26, 2013 at 09:22:11AM -0400, [email protected] wrote:

From: Alex Deucher <[email protected]>

The doorbell aperture is a PCI BAR whose pages can be mapped to compute resources for things like wptrs for userspace queues.

Quoted 6 lines
Quoted 2 lines

This patch maps the BAR and sets up a simple allocator to allocate pages from the BAR.

This doorbell stuff is cryptic, is that some memory on the GPU ? Or is it more like a register file ? ie what is backing the pci bar.

There's no memory backing it. It's just an aperture that the GPU can selectively listens to. You assign dw offsets from the doorbell aperture for things like the wrptr for compute rings. When the driver or process write a new wtpr value to the offset assigned to it's specific ring, the GPU starts processing it. Like ringing a doorbell.

Alex

Quoted 242 lines

Also probably want to use bitmap as i dont think gcc will turn bool array into a bitmap.

Cheers,
Jerome

Quoted 236 lines
---
 drivers/gpu/drm/radeon/cik.c           |   38 +++++++++++++
 drivers/gpu/drm/radeon/radeon.h        |   21 +++++++
 drivers/gpu/drm/radeon/radeon_device.c |   94 ++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +38 -0
index bb7dbc4..5c28fa5 100644
@@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
      return reference_clock;
 }
 
+/**
+ * cik_mm_rdoorbell - read a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ *
+ * Returns the value in the doorbell aperture at the
+ * requested offset (CIK).
+ */
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
+{
+     if (offset < rdev->doorbell.size) {
+             return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
+     } else {
+             DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
+             return 0;
+     }
+}
+
+/**
+ * cik_mm_wdoorbell - write a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ * @v: value to write
+ *
+ * Writes @v to the doorbell aperture at the
+ * requested offset (CIK).
+ */
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
+{
+     if (offset < rdev->doorbell.size) {
+             writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
+     } else {
+             DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
+     }
+}
+
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
 static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
drivers/gpu/drm/radeon/radeon.h +21 -0
index ad4e68a..a2a3430 100644
@@ -556,6 +556,20 @@ struct radeon_scratch {
 int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
 void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
 
+/*
+ * GPU doorbell structures, functions & helpers
+ */
+struct radeon_doorbell {
+     u32                     num_pages;
+     bool                    free[1024];
+     /* doorbell mmio */
+     resource_size_t                 base;
+     resource_size_t                 size;
+     void __iomem                    *ptr;
+};
+
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
 
 /*
  * IRQS.
@@ -1711,6 +1725,7 @@ struct radeon_device {
      struct radeon_gart              gart;
      struct radeon_mode_info         mode_info;
      struct radeon_scratch           scratch;
+     struct radeon_doorbell          doorbell;
      struct radeon_mman              mman;
      struct radeon_fence_driver      fence_drv[RADEON_NUM_RINGS];
      wait_queue_head_t               fence_queue;
@@ -1784,6 +1799,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
 u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
 void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
+
 /*
  * Cast helper
  */
@@ -1833,6 +1851,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
 #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
 
+#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
+#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
+
 /*
  * Indirect registers accessor
  */
drivers/gpu/drm/radeon/radeon_device.c +94 -1
index 4e97ff7..82335e3 100644
@@ -232,6 +232,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
 }
 
 /*
+ * GPU doorbell aperture helpers function.
+ */
+/**
+ * radeon_doorbell_init - Init doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Init doorbell driver information (CIK)
+ * Returns 0 on success, error on failure.
+ */
+int radeon_doorbell_init(struct radeon_device *rdev)
+{
+     int i;
+
+     /* doorbell bar mapping */
+     rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
+     rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
+
+     /* limit to 4 MB for now */
+     if (rdev->doorbell.size > (4 * 1024 * 1024))
+             rdev->doorbell.size = 4 * 1024 * 1024;
+
+     rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
+     if (rdev->doorbell.ptr == NULL) {
+             return -ENOMEM;
+     }
+     DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
+     DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
+
+     rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE;
+
+     for (i = 0; i < rdev->doorbell.num_pages; i++) {
+             rdev->doorbell.free[i] = true;
+     }
+     return 0;
+}
+
+/**
+ * radeon_doorbell_fini - Tear down doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down doorbell driver information (CIK)
+ */
+void radeon_doorbell_fini(struct radeon_device *rdev)
+{
+     iounmap(rdev->doorbell.ptr);
+     rdev->doorbell.ptr = NULL;
+}
+
+/**
+ * radeon_doorbell_get - Allocate a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Allocate a doorbell page for use by the driver (all asics).
+ * Returns 0 on success or -EINVAL on failure.
+ */
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
+{
+     int i;
+
+     for (i = 0; i < rdev->doorbell.num_pages; i++) {
+             if (rdev->doorbell.free[i]) {
+                     rdev->doorbell.free[i] = false;
+                     *doorbell = i;
+                     return 0;
+             }
+     }
+     return -EINVAL;
+}
+
+/**
+ * radeon_doorbell_free - Free a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Free a doorbell page allocated for use by the driver (all asics)
+ */
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
+{
+     if (doorbell < rdev->doorbell.num_pages)
+             rdev->doorbell.free[doorbell] = true;
+}
+
+/*
  * radeon_wb_*()
  * Writeback is the the method by which the the GPU updates special pages
  * in memory with the status of certain GPU events (fences, ring pointers,
@@ -1162,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev,
      DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
      DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
 
+     /* doorbell bar mapping */
+     if (rdev->family >= CHIP_BONAIRE)
+             radeon_doorbell_init(rdev);
+
      /* io port mapping */
      for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
              if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
@@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
      rdev->rio_mem = NULL;
      iounmap(rdev->rmmio);
      rdev->rmmio = NULL;
+     if (rdev->family >= CHIP_BONAIRE)
+             radeon_doorbell_fini(rdev);
      radeon_debugfs_remove_files(rdev);
 }
 
--

1.7.7.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel

#56 lore raw

PATCH 52/165 drm/radeon/cik: Add support for compute queues (v2)

In reply to [email protected]

From: Alex Deucher <[email protected]>

On CIK, the compute rings work slightly differently than on previous asics, however the basic concepts are the same.

The main differences:
- New MEC engines for compute queues
- Multiple queues per MEC:
- CI/KB: 1 MEC, 4 pipes per MEC, 8 queues per pipe = 32 queues
- KV: 2 MEC, 4 pipes per MEC, 8 queues per pipe = 64 queues
- Queues can be allocated and scheduled by another queue
- New doorbell aperture allows you to assign space in the aperture for the wptr which allows for userspace access to queues

v2: add wptr shadow, fix eop setup

---
 drivers/gpu/drm/radeon/cik.c       |  528 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/cikd.h      |   62 +++++
 drivers/gpu/drm/radeon/radeon.h    |   19 ++
 drivers/gpu/drm/radeon/radeon_cs.c |    4 +-
 4 files changed, 601 insertions(+), 12 deletions(-)
drivers/gpu/drm/radeon/cik.c +519 -9
index 5c28fa5..9d2d6bb 100644
@@ -1687,6 +1687,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
 	radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
 	radeon_ring_write(ring, 0xDEADBEEF);
 	radeon_ring_unlock_commit(rdev, ring);
+
 	for (i = 0; i < rdev->usec_timeout; i++) {
 		tmp = RREG32(scratch);
 		if (tmp == 0xDEADBEEF)
@@ -2112,6 +2113,51 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
 	return 0;
 }
 
+static u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
+				     struct radeon_ring *ring)
+{
+	u32 rptr;
+
+
+
+	if (rdev->wb.enabled) {
+		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+	} else {
+		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+		rptr = RREG32(CP_HQD_PQ_RPTR);
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+	}
+	rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return rptr;
+}
+
+static u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
+				     struct radeon_ring *ring)
+{
+	u32 wptr;
+
+	if (rdev->wb.enabled) {
+		wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
+	} else {
+		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+		wptr = RREG32(CP_HQD_PQ_WPTR);
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+	}
+	wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return wptr;
+}
+
+static void cik_compute_ring_set_wptr(struct radeon_device *rdev,
+				      struct radeon_ring *ring)
+{
+	u32 wptr = (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask;
+
+	rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(wptr);
+	WDOORBELL32(ring->doorbell_offset, wptr);
+}
+
 /**
  * cik_cp_compute_enable - enable/disable the compute CP MEs
  *
@@ -2176,7 +2222,8 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
  */
 static int cik_cp_compute_start(struct radeon_device *rdev)
 {
-	//todo
+	cik_cp_compute_enable(rdev, true);
+
 	return 0;
 }
 
@@ -2190,10 +2237,171 @@ static int cik_cp_compute_start(struct radeon_device *rdev)
  */
 static void cik_cp_compute_fini(struct radeon_device *rdev)
 {
+	int i, idx, r;
+
 	cik_cp_compute_enable(rdev, false);
-	//todo
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			idx = CAYMAN_RING_TYPE_CP1_INDEX;
+		else
+			idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+		if (rdev->ring[idx].mqd_obj) {
+			r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+			if (unlikely(r != 0))
+				dev_warn(rdev->dev, "(%d) reserve MQD bo failed\n", r);
+
+			radeon_bo_unpin(rdev->ring[idx].mqd_obj);
+			radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+			radeon_bo_unref(&rdev->ring[idx].mqd_obj);
+			rdev->ring[idx].mqd_obj = NULL;
+		}
+	}
+}
+
+static void cik_mec_fini(struct radeon_device *rdev)
+{
+	int r;
+
+	if (rdev->mec.hpd_eop_obj) {
+		r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+		if (unlikely(r != 0))
+			dev_warn(rdev->dev, "(%d) reserve HPD EOP bo failed\n", r);
+		radeon_bo_unpin(rdev->mec.hpd_eop_obj);
+		radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+		radeon_bo_unref(&rdev->mec.hpd_eop_obj);
+		rdev->mec.hpd_eop_obj = NULL;
+	}
+}
+
+#define MEC_HPD_SIZE 2048
+
+static int cik_mec_init(struct radeon_device *rdev)
+{
+	int r;
+	u32 *hpd;
+
+	/*
+	 * KV:    2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total
+	 * CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total
+	 */
+	if (rdev->family == CHIP_KAVERI)
+		rdev->mec.num_mec = 2;
+	else
+		rdev->mec.num_mec = 1;
+	rdev->mec.num_pipe = 4;
+	rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8;
+
+	if (rdev->mec.hpd_eop_obj == NULL) {
+		r = radeon_bo_create(rdev,
+				     rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2,
+				     PAGE_SIZE, true,
+				     RADEON_GEM_DOMAIN_GTT, NULL,
+				     &rdev->mec.hpd_eop_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r);
+			return r;
+		}
+	}
+
+	r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+	if (unlikely(r != 0)) {
+		cik_mec_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->mec.hpd_eop_obj, RADEON_GEM_DOMAIN_GTT,
+			  &rdev->mec.hpd_eop_gpu_addr);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) pin HDP EOP bo failed\n", r);
+		cik_mec_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_kmap(rdev->mec.hpd_eop_obj, (void **)&hpd);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) map HDP EOP bo failed\n", r);
+		cik_mec_fini(rdev);
+		return r;
+	}
+
+	/* clear memory.  Not sure if this is required or not */
+	memset(hpd, 0, rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2);
+
+	radeon_bo_kunmap(rdev->mec.hpd_eop_obj);
+	radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+	return 0;
 }
 
+struct hqd_registers
+{
+	u32 cp_mqd_base_addr;
+	u32 cp_mqd_base_addr_hi;
+	u32 cp_hqd_active;
+	u32 cp_hqd_vmid;
+	u32 cp_hqd_persistent_state;
+	u32 cp_hqd_pipe_priority;
+	u32 cp_hqd_queue_priority;
+	u32 cp_hqd_quantum;
+	u32 cp_hqd_pq_base;
+	u32 cp_hqd_pq_base_hi;
+	u32 cp_hqd_pq_rptr;
+	u32 cp_hqd_pq_rptr_report_addr;
+	u32 cp_hqd_pq_rptr_report_addr_hi;
+	u32 cp_hqd_pq_wptr_poll_addr;
+	u32 cp_hqd_pq_wptr_poll_addr_hi;
+	u32 cp_hqd_pq_doorbell_control;
+	u32 cp_hqd_pq_wptr;
+	u32 cp_hqd_pq_control;
+	u32 cp_hqd_ib_base_addr;
+	u32 cp_hqd_ib_base_addr_hi;
+	u32 cp_hqd_ib_rptr;
+	u32 cp_hqd_ib_control;
+	u32 cp_hqd_iq_timer;
+	u32 cp_hqd_iq_rptr;
+	u32 cp_hqd_dequeue_request;
+	u32 cp_hqd_dma_offload;
+	u32 cp_hqd_sema_cmd;
+	u32 cp_hqd_msg_type;
+	u32 cp_hqd_atomic0_preop_lo;
+	u32 cp_hqd_atomic0_preop_hi;
+	u32 cp_hqd_atomic1_preop_lo;
+	u32 cp_hqd_atomic1_preop_hi;
+	u32 cp_hqd_hq_scheduler0;
+	u32 cp_hqd_hq_scheduler1;
+	u32 cp_mqd_control;
+};
+
+struct bonaire_mqd
+{
+	u32 header;
+	u32 dispatch_initiator;
+	u32 dimensions[3];
+	u32 start_idx[3];
+	u32 num_threads[3];
+	u32 pipeline_stat_enable;
+	u32 perf_counter_enable;
+	u32 pgm[2];
+	u32 tba[2];
+	u32 tma[2];
+	u32 pgm_rsrc[2];
+	u32 vmid;
+	u32 resource_limits;
+	u32 static_thread_mgmt01[2];
+	u32 tmp_ring_size;
+	u32 static_thread_mgmt23[2];
+	u32 restart[3];
+	u32 thread_trace_enable;
+	u32 reserved1;
+	u32 user_data[16];
+	u32 vgtcs_invoke_count[2];
+	struct hqd_registers queue_state;
+	u32 dequeue_cntr;
+	u32 interrupt_queue[64];
+};
+
 /**
  * cik_cp_compute_resume - setup the compute queue registers
  *
@@ -2205,24 +2413,247 @@ static void cik_cp_compute_fini(struct radeon_device *rdev)
  */
 static int cik_cp_compute_resume(struct radeon_device *rdev)
 {
-	int r;
+	int r, i, idx;
+	u32 tmp;
+	bool use_doorbell = true;
+	u64 hqd_gpu_addr;
+	u64 mqd_gpu_addr;
+	u64 eop_gpu_addr;
+	u64 wb_gpu_addr;
+	u32 *buf;
+	struct bonaire_mqd *mqd;
 
-	//todo
 	r = cik_cp_compute_start(rdev);
 	if (r)
 		return r;
+
+	/* fix up chicken bits */
+	tmp = RREG32(CP_CPF_DEBUG);
+	tmp |= (1 << 23);
+	WREG32(CP_CPF_DEBUG, tmp);
+
+	/* init the pipes */
+	for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
+		int me = (i < 4) ? 1 : 2;
+		int pipe = (i < 4) ? i : (i - 4);
+
+		eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2);
+
+		cik_srbm_select(rdev, me, pipe, 0, 0);
+
+		/* write the EOP addr */
+		WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
+		WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8);
+
+		/* set the VMID assigned */
+		WREG32(CP_HPD_EOP_VMID, 0);
+
+		/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+		tmp = RREG32(CP_HPD_EOP_CONTROL);
+		tmp &= ~EOP_SIZE_MASK;
+		tmp |= drm_order(MEC_HPD_SIZE / 8);
+		WREG32(CP_HPD_EOP_CONTROL, tmp);
+	}
+	cik_srbm_select(rdev, 0, 0, 0, 0);
+
+	/* init the queues.  Just two for now. */
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			idx = CAYMAN_RING_TYPE_CP1_INDEX;
+		else
+			idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+		if (rdev->ring[idx].mqd_obj == NULL) {
+			r = radeon_bo_create(rdev,
+					     sizeof(struct bonaire_mqd),
+					     PAGE_SIZE, true,
+					     RADEON_GEM_DOMAIN_GTT, NULL,
+					     &rdev->ring[idx].mqd_obj);
+			if (r) {
+				dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r);
+				return r;
+			}
+		}
+
+		r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+		if (unlikely(r != 0)) {
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+		r = radeon_bo_pin(rdev->ring[idx].mqd_obj, RADEON_GEM_DOMAIN_GTT,
+				  &mqd_gpu_addr);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) pin MQD bo failed\n", r);
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+		r = radeon_bo_kmap(rdev->ring[idx].mqd_obj, (void **)&buf);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) map MQD bo failed\n", r);
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+
+		/* doorbell offset */
+		rdev->ring[idx].doorbell_offset =
+			(rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0;
+
+		/* init the mqd struct */
+		memset(buf, 0, sizeof(struct bonaire_mqd));
+
+		mqd = (struct bonaire_mqd *)buf;
+		mqd->header = 0xC0310800;
+		mqd->static_thread_mgmt01[0] = 0xffffffff;
+		mqd->static_thread_mgmt01[1] = 0xffffffff;
+		mqd->static_thread_mgmt23[0] = 0xffffffff;
+		mqd->static_thread_mgmt23[1] = 0xffffffff;
+
+		cik_srbm_select(rdev, rdev->ring[idx].me,
+				rdev->ring[idx].pipe,
+				rdev->ring[idx].queue, 0);
+
+		/* disable wptr polling */
+		tmp = RREG32(CP_PQ_WPTR_POLL_CNTL);
+		tmp &= ~WPTR_POLL_EN;
+		WREG32(CP_PQ_WPTR_POLL_CNTL, tmp);
+
+		/* enable doorbell? */
+		mqd->queue_state.cp_hqd_pq_doorbell_control =
+			RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+		if (use_doorbell)
+			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+		else
+			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_EN;
+		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+		       mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+		/* disable the queue if it's active */
+		mqd->queue_state.cp_hqd_dequeue_request = 0;
+		mqd->queue_state.cp_hqd_pq_rptr = 0;
+		mqd->queue_state.cp_hqd_pq_wptr= 0;
+		if (RREG32(CP_HQD_ACTIVE) & 1) {
+			WREG32(CP_HQD_DEQUEUE_REQUEST, 1);
+			for (i = 0; i < rdev->usec_timeout; i++) {
+				if (!(RREG32(CP_HQD_ACTIVE) & 1))
+					break;
+				udelay(1);
+			}
+			WREG32(CP_HQD_DEQUEUE_REQUEST, mqd->queue_state.cp_hqd_dequeue_request);
+			WREG32(CP_HQD_PQ_RPTR, mqd->queue_state.cp_hqd_pq_rptr);
+			WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+		}
+
+		/* set the pointer to the MQD */
+		mqd->queue_state.cp_mqd_base_addr = mqd_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_mqd_base_addr_hi = upper_32_bits(mqd_gpu_addr);
+		WREG32(CP_MQD_BASE_ADDR, mqd->queue_state.cp_mqd_base_addr);
+		WREG32(CP_MQD_BASE_ADDR_HI, mqd->queue_state.cp_mqd_base_addr_hi);
+		/* set MQD vmid to 0 */
+		mqd->queue_state.cp_mqd_control = RREG32(CP_MQD_CONTROL);
+		mqd->queue_state.cp_mqd_control &= ~MQD_VMID_MASK;
+		WREG32(CP_MQD_CONTROL, mqd->queue_state.cp_mqd_control);
+
+		/* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
+		hqd_gpu_addr = rdev->ring[idx].gpu_addr >> 8;
+		mqd->queue_state.cp_hqd_pq_base = hqd_gpu_addr;
+		mqd->queue_state.cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
+		WREG32(CP_HQD_PQ_BASE, mqd->queue_state.cp_hqd_pq_base);
+		WREG32(CP_HQD_PQ_BASE_HI, mqd->queue_state.cp_hqd_pq_base_hi);
+
+		/* set up the HQD, this is similar to CP_RB0_CNTL */
+		mqd->queue_state.cp_hqd_pq_control = RREG32(CP_HQD_PQ_CONTROL);
+		mqd->queue_state.cp_hqd_pq_control &=
+			~(QUEUE_SIZE_MASK | RPTR_BLOCK_SIZE_MASK);
+
+		mqd->queue_state.cp_hqd_pq_control |=
+			drm_order(rdev->ring[idx].ring_size / 8);
+		mqd->queue_state.cp_hqd_pq_control |=
+			(drm_order(RADEON_GPU_PAGE_SIZE/8) << 8);
+#ifdef __BIG_ENDIAN
+		mqd->queue_state.cp_hqd_pq_control |= BUF_SWAP_32BIT;
+#endif
+		mqd->queue_state.cp_hqd_pq_control &=
+			~(UNORD_DISPATCH | ROQ_PQ_IB_FLIP | PQ_VOLATILE);
+		mqd->queue_state.cp_hqd_pq_control |=
+			PRIV_STATE | KMD_QUEUE; /* assuming kernel queue control */
+		WREG32(CP_HQD_PQ_CONTROL, mqd->queue_state.cp_hqd_pq_control);
+
+		/* only used if CP_PQ_WPTR_POLL_CNTL.WPTR_POLL_EN=1 */
+		if (i == 0)
+			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP1_WPTR_OFFSET;
+		else
+			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP2_WPTR_OFFSET;
+		mqd->queue_state.cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
+		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR, mqd->queue_state.cp_hqd_pq_wptr_poll_addr);
+		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR_HI,
+		       mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi);
+
+		/* set the wb address wether it's enabled or not */
+		if (i == 0)
+			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET;
+		else
+			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET;
+		mqd->queue_state.cp_hqd_pq_rptr_report_addr = wb_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi =
+			upper_32_bits(wb_gpu_addr) & 0xffff;
+		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR,
+		       mqd->queue_state.cp_hqd_pq_rptr_report_addr);
+		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR_HI,
+		       mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi);
+
+		/* enable the doorbell if requested */
+		if (use_doorbell) {
+			mqd->queue_state.cp_hqd_pq_doorbell_control =
+				RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_OFFSET_MASK;
+			mqd->queue_state.cp_hqd_pq_doorbell_control |=
+				DOORBELL_OFFSET(rdev->ring[idx].doorbell_offset / 4);
+			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+			mqd->queue_state.cp_hqd_pq_doorbell_control &=
+				~(DOORBELL_SOURCE | DOORBELL_HIT);
+
+		} else {
+			mqd->queue_state.cp_hqd_pq_doorbell_control = 0;
+		}
+		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+		       mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+		/* read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+		rdev->ring[idx].wptr = 0;
+		mqd->queue_state.cp_hqd_pq_wptr = rdev->ring[idx].wptr;
+		WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+		rdev->ring[idx].rptr = RREG32(CP_HQD_PQ_RPTR);
+		mqd->queue_state.cp_hqd_pq_rptr = rdev->ring[idx].rptr;
+
+		/* set the vmid for the queue */
+		mqd->queue_state.cp_hqd_vmid = 0;
+		WREG32(CP_HQD_VMID, mqd->queue_state.cp_hqd_vmid);
+
+		/* activate the queue */
+		mqd->queue_state.cp_hqd_active = 1;
+		WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active);
+
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+
+		radeon_bo_kunmap(rdev->ring[idx].mqd_obj);
+		radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+		rdev->ring[idx].ready = true;
+		r = radeon_ring_test(rdev, idx, &rdev->ring[idx]);
+		if (r)
+			rdev->ring[idx].ready = false;
+	}
+
 	return 0;
 }
 
-/* XXX temporary wrappers to handle both compute and gfx */
-/* XXX */
 static void cik_cp_enable(struct radeon_device *rdev, bool enable)
 {
 	cik_cp_gfx_enable(rdev, enable);
 	cik_cp_compute_enable(rdev, enable);
 }
 
-/* XXX */
 static int cik_cp_load_microcode(struct radeon_device *rdev)
 {
 	int r;
@@ -2237,14 +2668,12 @@ static int cik_cp_load_microcode(struct radeon_device *rdev)
 	return 0;
 }
 
-/* XXX */
 static void cik_cp_fini(struct radeon_device *rdev)
 {
 	cik_cp_gfx_fini(rdev);
 	cik_cp_compute_fini(rdev);
 }
 
-/* XXX */
 static int cik_cp_resume(struct radeon_device *rdev)
 {
 	int r;
@@ -2865,6 +3294,22 @@ static void cik_print_gpu_status_regs(struct radeon_device *rdev)
 		RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
 	dev_info(rdev->dev, "  SDMA1_STATUS_REG   = 0x%08X\n",
 		 RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
+	dev_info(rdev->dev, "  CP_STAT = 0x%08x\n", RREG32(CP_STAT));
+	dev_info(rdev->dev, "  CP_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_STALLED_STAT2 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT2));
+	dev_info(rdev->dev, "  CP_STALLED_STAT3 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT3));
+	dev_info(rdev->dev, "  CP_CPF_BUSY_STAT = 0x%08x\n",
+		 RREG32(CP_CPF_BUSY_STAT));
+	dev_info(rdev->dev, "  CP_CPF_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_CPF_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_CPF_STATUS = 0x%08x\n", RREG32(CP_CPF_STATUS));
+	dev_info(rdev->dev, "  CP_CPC_BUSY_STAT = 0x%08x\n", RREG32(CP_CPC_BUSY_STAT));
+	dev_info(rdev->dev, "  CP_CPC_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_CPC_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_CPC_STATUS = 0x%08x\n", RREG32(CP_CPC_STATUS));
 }
 
 /**
@@ -4952,12 +5397,31 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	/* allocate rlc buffers */
+	r = cik_mec_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init MEC BOs!\n");
+		return r;
+	}
+
 	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
 		return r;
 	}
 
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
 	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
@@ -5002,6 +5466,36 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	/* set up the compute queues */
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
+			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+	ring->me = 1; /* first MEC */
+	ring->pipe = 0; /* first pipe */
+	ring->queue = 0; /* first queue */
+	ring->wptr_offs = CIK_WB_CP1_WPTR_OFFSET;
+	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
+	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
+	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
+			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+			     0, 0xffffffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+	/* dGPU only have 1 MEC */
+	ring->me = 1; /* first MEC */
+	ring->pipe = 0; /* first pipe */
+	ring->queue = 1; /* second queue */
+	ring->wptr_offs = CIK_WB_CP2_WPTR_OFFSET;
+	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
+	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
+	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
+
 	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
 			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
@@ -5176,6 +5670,20 @@ int cik_init(struct radeon_device *rdev)
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 1024 * 1024);
 
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+	if (r)
+		return r;
+
 	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 256 * 1024);
@@ -5206,6 +5714,7 @@ int cik_init(struct radeon_device *rdev)
 		cik_sdma_fini(rdev);
 		cik_irq_fini(rdev);
 		si_rlc_fini(rdev);
+		cik_mec_fini(rdev);
 		radeon_wb_fini(rdev);
 		radeon_ib_pool_fini(rdev);
 		radeon_vm_manager_fini(rdev);
@@ -5241,6 +5750,7 @@ void cik_fini(struct radeon_device *rdev)
 	cik_sdma_fini(rdev);
 	cik_irq_fini(rdev);
 	si_rlc_fini(rdev);
+	cik_mec_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	radeon_ib_pool_fini(rdev);
drivers/gpu/drm/radeon/cikd.h +62 -0

86 lines not on this page · raw message

drivers/gpu/drm/radeon/radeon.h +19 -0
index a2a3430..d40d506 100644
@@ -714,6 +714,22 @@ struct radeon_ring {
 		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
 		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
 	} funcs;
+	/* for CIK queues */
+	u32 me;
+	u32 pipe;
+	u32 queue;
+	struct radeon_bo	*mqd_obj;
+	u32 doorbell_page_num;
+	u32 doorbell_offset;
+	unsigned		wptr_offs;
+};
+
+struct radeon_mec {
+	struct radeon_bo	*hpd_eop_obj;
+	u64			hpd_eop_gpu_addr;
+	u32 num_pipe;
+	u32 num_mec;
+	u32 num_queue;
 };
 
 /*
@@ -971,6 +987,8 @@ struct radeon_wb {
 #define CAYMAN_WB_DMA1_RPTR_OFFSET   2304
 #define R600_WB_UVD_RPTR_OFFSET  2560
 #define R600_WB_EVENT_OFFSET     3072
+#define CIK_WB_CP1_WPTR_OFFSET     3328
+#define CIK_WB_CP2_WPTR_OFFSET     3584
 
 /**
  * struct radeon_pm - power management datas
@@ -1760,6 +1778,7 @@ struct radeon_device {
 	int msi_enabled; /* msi enabled */
 	struct r600_ih ih; /* r6/700 interrupt ring */
 	struct si_rlc rlc;
+	struct radeon_mec mec;
 	struct work_struct hotplug_work;
 	struct work_struct audio_work;
 	struct work_struct reset_work;
drivers/gpu/drm/radeon/radeon_cs.c +1 -3
index cf71734..7e265a5 100644
@@ -121,9 +121,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
 		p->ring = RADEON_RING_TYPE_GFX_INDEX;
 		break;
 	case RADEON_CS_RING_COMPUTE:
-		if (p->rdev->family >= CHIP_BONAIRE)
-			p->ring = RADEON_RING_TYPE_GFX_INDEX;
-		else if (p->rdev->family >= CHIP_TAHITI) {
+		if (p->rdev->family >= CHIP_TAHITI) {
 			if (p->priority > 0)
 				p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
 			else
Signature · 1 line
1.7.7.5
Reviewed-by on v1 52/165
#57 lore raw

Re: [PATCH 052/165] drm/radeon/cik: Add support for compute queues (v2)

Quoted 14 lines · On Wed, Jun 26, 2013 at 09:22:12AM -0400, [email protected] wrote:

From: Alex Deucher <[email protected]>

On CIK, the compute rings work slightly differently than on previous asics, however the basic concepts are the same.

The main differences:
- New MEC engines for compute queues
- Multiple queues per MEC:
- CI/KB: 1 MEC, 4 pipes per MEC, 8 queues per pipe = 32 queues
- KV: 2 MEC, 4 pipes per MEC, 8 queues per pipe = 64 queues
- Queues can be allocated and scheduled by another queue
- New doorbell aperture allows you to assign space in the aperture for the wptr which allows for userspace access to queues

Quoted 3 lines

v2: add wptr shadow, fix eop setup

Minor nitpick below otherwise

Quoted 267 lines
---
 drivers/gpu/drm/radeon/cik.c       |  528 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/cikd.h      |   62 +++++
 drivers/gpu/drm/radeon/radeon.h    |   19 ++
 drivers/gpu/drm/radeon/radeon_cs.c |    4 +-
 4 files changed, 601 insertions(+), 12 deletions(-)
drivers/gpu/drm/radeon/cik.c +218 -3
index 5c28fa5..9d2d6bb 100644
@@ -1687,6 +1687,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
 	radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
 	radeon_ring_write(ring, 0xDEADBEEF);
 	radeon_ring_unlock_commit(rdev, ring);
+
 	for (i = 0; i < rdev->usec_timeout; i++) {
 		tmp = RREG32(scratch);
 		if (tmp == 0xDEADBEEF)
@@ -2112,6 +2113,51 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
 	return 0;
 }
 
+static u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
+				     struct radeon_ring *ring)
+{
+	u32 rptr;
+
+
+
+	if (rdev->wb.enabled) {
+		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+	} else {
+		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+		rptr = RREG32(CP_HQD_PQ_RPTR);
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+	}
+	rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return rptr;
+}
+
+static u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
+				     struct radeon_ring *ring)
+{
+	u32 wptr;
+
+	if (rdev->wb.enabled) {
+		wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
+	} else {
+		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+		wptr = RREG32(CP_HQD_PQ_WPTR);
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+	}
+	wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return wptr;
+}
+
+static void cik_compute_ring_set_wptr(struct radeon_device *rdev,
+				      struct radeon_ring *ring)
+{
+	u32 wptr = (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask;
+
+	rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(wptr);
+	WDOORBELL32(ring->doorbell_offset, wptr);
+}
+
 /**
  * cik_cp_compute_enable - enable/disable the compute CP MEs
  *
@@ -2176,7 +2222,8 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
  */
 static int cik_cp_compute_start(struct radeon_device *rdev)
 {
-	//todo
+	cik_cp_compute_enable(rdev, true);
+
 	return 0;
 }
 
@@ -2190,10 +2237,171 @@ static int cik_cp_compute_start(struct radeon_device *rdev)
  */
 static void cik_cp_compute_fini(struct radeon_device *rdev)
 {
+	int i, idx, r;
+
 	cik_cp_compute_enable(rdev, false);
-	//todo
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			idx = CAYMAN_RING_TYPE_CP1_INDEX;
+		else
+			idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+		if (rdev->ring[idx].mqd_obj) {
+			r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+			if (unlikely(r != 0))
+				dev_warn(rdev->dev, "(%d) reserve MQD bo failed\n", r);
+
+			radeon_bo_unpin(rdev->ring[idx].mqd_obj);
+			radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+			radeon_bo_unref(&rdev->ring[idx].mqd_obj);
+			rdev->ring[idx].mqd_obj = NULL;
+		}
+	}
+}
+
+static void cik_mec_fini(struct radeon_device *rdev)
+{
+	int r;
+
+	if (rdev->mec.hpd_eop_obj) {
+		r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+		if (unlikely(r != 0))
+			dev_warn(rdev->dev, "(%d) reserve HPD EOP bo failed\n", r);
+		radeon_bo_unpin(rdev->mec.hpd_eop_obj);
+		radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+		radeon_bo_unref(&rdev->mec.hpd_eop_obj);
+		rdev->mec.hpd_eop_obj = NULL;
+	}
+}
+
+#define MEC_HPD_SIZE 2048
+
+static int cik_mec_init(struct radeon_device *rdev)
+{
+	int r;
+	u32 *hpd;
+
+	/*
+	 * KV:    2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total
+	 * CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total
+	 */
+	if (rdev->family == CHIP_KAVERI)
+		rdev->mec.num_mec = 2;
+	else
+		rdev->mec.num_mec = 1;
+	rdev->mec.num_pipe = 4;
+	rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8;
+
+	if (rdev->mec.hpd_eop_obj == NULL) {
+		r = radeon_bo_create(rdev,
+				     rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2,
+				     PAGE_SIZE, true,
+				     RADEON_GEM_DOMAIN_GTT, NULL,
+				     &rdev->mec.hpd_eop_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r);
+			return r;
+		}
+	}
+
+	r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+	if (unlikely(r != 0)) {
+		cik_mec_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->mec.hpd_eop_obj, RADEON_GEM_DOMAIN_GTT,
+			  &rdev->mec.hpd_eop_gpu_addr);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) pin HDP EOP bo failed\n", r);
+		cik_mec_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_kmap(rdev->mec.hpd_eop_obj, (void **)&hpd);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) map HDP EOP bo failed\n", r);
+		cik_mec_fini(rdev);
+		return r;
+	}
+
+	/* clear memory.  Not sure if this is required or not */
+	memset(hpd, 0, rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2);
+
+	radeon_bo_kunmap(rdev->mec.hpd_eop_obj);
+	radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+	return 0;
 }
 
+struct hqd_registers
+{
+	u32 cp_mqd_base_addr;
+	u32 cp_mqd_base_addr_hi;
+	u32 cp_hqd_active;
+	u32 cp_hqd_vmid;
+	u32 cp_hqd_persistent_state;
+	u32 cp_hqd_pipe_priority;
+	u32 cp_hqd_queue_priority;
+	u32 cp_hqd_quantum;
+	u32 cp_hqd_pq_base;
+	u32 cp_hqd_pq_base_hi;
+	u32 cp_hqd_pq_rptr;
+	u32 cp_hqd_pq_rptr_report_addr;
+	u32 cp_hqd_pq_rptr_report_addr_hi;
+	u32 cp_hqd_pq_wptr_poll_addr;
+	u32 cp_hqd_pq_wptr_poll_addr_hi;
+	u32 cp_hqd_pq_doorbell_control;
+	u32 cp_hqd_pq_wptr;
+	u32 cp_hqd_pq_control;
+	u32 cp_hqd_ib_base_addr;
+	u32 cp_hqd_ib_base_addr_hi;
+	u32 cp_hqd_ib_rptr;
+	u32 cp_hqd_ib_control;
+	u32 cp_hqd_iq_timer;
+	u32 cp_hqd_iq_rptr;
+	u32 cp_hqd_dequeue_request;
+	u32 cp_hqd_dma_offload;
+	u32 cp_hqd_sema_cmd;
+	u32 cp_hqd_msg_type;
+	u32 cp_hqd_atomic0_preop_lo;
+	u32 cp_hqd_atomic0_preop_hi;
+	u32 cp_hqd_atomic1_preop_lo;
+	u32 cp_hqd_atomic1_preop_hi;
+	u32 cp_hqd_hq_scheduler0;
+	u32 cp_hqd_hq_scheduler1;
+	u32 cp_mqd_control;
+};
+
+struct bonaire_mqd
+{
+	u32 header;
+	u32 dispatch_initiator;
+	u32 dimensions[3];
+	u32 start_idx[3];
+	u32 num_threads[3];
+	u32 pipeline_stat_enable;
+	u32 perf_counter_enable;
+	u32 pgm[2];
+	u32 tba[2];
+	u32 tma[2];
+	u32 pgm_rsrc[2];
+	u32 vmid;
+	u32 resource_limits;
+	u32 static_thread_mgmt01[2];
+	u32 tmp_ring_size;
+	u32 static_thread_mgmt23[2];
+	u32 restart[3];
+	u32 thread_trace_enable;
+	u32 reserved1;
+	u32 user_data[16];
+	u32 vgtcs_invoke_count[2];
+	struct hqd_registers queue_state;
+	u32 dequeue_cntr;
+	u32 interrupt_queue[64];
+};
+
 /**
  * cik_cp_compute_resume - setup the compute queue registers
  *
@@ -2205,24 +2413,247 @@ static void cik_cp_compute_fini(struct radeon_device *rdev)
  */
 static int cik_cp_compute_resume(struct radeon_device *rdev)
 {
-	int r;
+	int r, i, idx;
+	u32 tmp;
+	bool use_doorbell = true;
+	u64 hqd_gpu_addr;
+	u64 mqd_gpu_addr;
+	u64 eop_gpu_addr;
+	u64 wb_gpu_addr;
+	u32 *buf;

drivers/gpu/drm/radeon/cik.c static void cik_cp_compute_fini(struct radeon_device *rdev) · line 2432

Quoted 10 lines
drivers/gpu/drm/radeon/cik.c +5 -1
+	struct bonaire_mqd *mqd;
 
-	//todo
 	r = cik_cp_compute_start(rdev);
 	if (r)
 		return r;
+
+	/* fix up chicken bits */
+	tmp = RREG32(CP_CPF_DEBUG);
+	tmp |= (1 << 23);

What is this chicken bit ? Is it tasty ?

Quoted 269 lines
drivers/gpu/drm/radeon/cik.c +231 -5
+	WREG32(CP_CPF_DEBUG, tmp);
+
+	/* init the pipes */
+	for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
+		int me = (i < 4) ? 1 : 2;
+		int pipe = (i < 4) ? i : (i - 4);
+
+		eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2);
+
+		cik_srbm_select(rdev, me, pipe, 0, 0);
+
+		/* write the EOP addr */
+		WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
+		WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8);
+
+		/* set the VMID assigned */
+		WREG32(CP_HPD_EOP_VMID, 0);
+
+		/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+		tmp = RREG32(CP_HPD_EOP_CONTROL);
+		tmp &= ~EOP_SIZE_MASK;
+		tmp |= drm_order(MEC_HPD_SIZE / 8);
+		WREG32(CP_HPD_EOP_CONTROL, tmp);
+	}
+	cik_srbm_select(rdev, 0, 0, 0, 0);
+
+	/* init the queues.  Just two for now. */
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			idx = CAYMAN_RING_TYPE_CP1_INDEX;
+		else
+			idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+		if (rdev->ring[idx].mqd_obj == NULL) {
+			r = radeon_bo_create(rdev,
+					     sizeof(struct bonaire_mqd),
+					     PAGE_SIZE, true,
+					     RADEON_GEM_DOMAIN_GTT, NULL,
+					     &rdev->ring[idx].mqd_obj);
+			if (r) {
+				dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r);
+				return r;
+			}
+		}
+
+		r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+		if (unlikely(r != 0)) {
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+		r = radeon_bo_pin(rdev->ring[idx].mqd_obj, RADEON_GEM_DOMAIN_GTT,
+				  &mqd_gpu_addr);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) pin MQD bo failed\n", r);
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+		r = radeon_bo_kmap(rdev->ring[idx].mqd_obj, (void **)&buf);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) map MQD bo failed\n", r);
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+
+		/* doorbell offset */
+		rdev->ring[idx].doorbell_offset =
+			(rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0;
+
+		/* init the mqd struct */
+		memset(buf, 0, sizeof(struct bonaire_mqd));
+
+		mqd = (struct bonaire_mqd *)buf;
+		mqd->header = 0xC0310800;
+		mqd->static_thread_mgmt01[0] = 0xffffffff;
+		mqd->static_thread_mgmt01[1] = 0xffffffff;
+		mqd->static_thread_mgmt23[0] = 0xffffffff;
+		mqd->static_thread_mgmt23[1] = 0xffffffff;
+
+		cik_srbm_select(rdev, rdev->ring[idx].me,
+				rdev->ring[idx].pipe,
+				rdev->ring[idx].queue, 0);
+
+		/* disable wptr polling */
+		tmp = RREG32(CP_PQ_WPTR_POLL_CNTL);
+		tmp &= ~WPTR_POLL_EN;
+		WREG32(CP_PQ_WPTR_POLL_CNTL, tmp);
+
+		/* enable doorbell? */
+		mqd->queue_state.cp_hqd_pq_doorbell_control =
+			RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+		if (use_doorbell)
+			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+		else
+			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_EN;
+		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+		       mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+		/* disable the queue if it's active */
+		mqd->queue_state.cp_hqd_dequeue_request = 0;
+		mqd->queue_state.cp_hqd_pq_rptr = 0;
+		mqd->queue_state.cp_hqd_pq_wptr= 0;
+		if (RREG32(CP_HQD_ACTIVE) & 1) {
+			WREG32(CP_HQD_DEQUEUE_REQUEST, 1);
+			for (i = 0; i < rdev->usec_timeout; i++) {
+				if (!(RREG32(CP_HQD_ACTIVE) & 1))
+					break;
+				udelay(1);
+			}
+			WREG32(CP_HQD_DEQUEUE_REQUEST, mqd->queue_state.cp_hqd_dequeue_request);
+			WREG32(CP_HQD_PQ_RPTR, mqd->queue_state.cp_hqd_pq_rptr);
+			WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+		}
+
+		/* set the pointer to the MQD */
+		mqd->queue_state.cp_mqd_base_addr = mqd_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_mqd_base_addr_hi = upper_32_bits(mqd_gpu_addr);
+		WREG32(CP_MQD_BASE_ADDR, mqd->queue_state.cp_mqd_base_addr);
+		WREG32(CP_MQD_BASE_ADDR_HI, mqd->queue_state.cp_mqd_base_addr_hi);
+		/* set MQD vmid to 0 */
+		mqd->queue_state.cp_mqd_control = RREG32(CP_MQD_CONTROL);
+		mqd->queue_state.cp_mqd_control &= ~MQD_VMID_MASK;
+		WREG32(CP_MQD_CONTROL, mqd->queue_state.cp_mqd_control);
+
+		/* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
+		hqd_gpu_addr = rdev->ring[idx].gpu_addr >> 8;
+		mqd->queue_state.cp_hqd_pq_base = hqd_gpu_addr;
+		mqd->queue_state.cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
+		WREG32(CP_HQD_PQ_BASE, mqd->queue_state.cp_hqd_pq_base);
+		WREG32(CP_HQD_PQ_BASE_HI, mqd->queue_state.cp_hqd_pq_base_hi);
+
+		/* set up the HQD, this is similar to CP_RB0_CNTL */
+		mqd->queue_state.cp_hqd_pq_control = RREG32(CP_HQD_PQ_CONTROL);
+		mqd->queue_state.cp_hqd_pq_control &=
+			~(QUEUE_SIZE_MASK | RPTR_BLOCK_SIZE_MASK);
+
+		mqd->queue_state.cp_hqd_pq_control |=
+			drm_order(rdev->ring[idx].ring_size / 8);
+		mqd->queue_state.cp_hqd_pq_control |=
+			(drm_order(RADEON_GPU_PAGE_SIZE/8) << 8);
+#ifdef __BIG_ENDIAN
+		mqd->queue_state.cp_hqd_pq_control |= BUF_SWAP_32BIT;
+#endif
+		mqd->queue_state.cp_hqd_pq_control &=
+			~(UNORD_DISPATCH | ROQ_PQ_IB_FLIP | PQ_VOLATILE);
+		mqd->queue_state.cp_hqd_pq_control |=
+			PRIV_STATE | KMD_QUEUE; /* assuming kernel queue control */
+		WREG32(CP_HQD_PQ_CONTROL, mqd->queue_state.cp_hqd_pq_control);
+
+		/* only used if CP_PQ_WPTR_POLL_CNTL.WPTR_POLL_EN=1 */
+		if (i == 0)
+			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP1_WPTR_OFFSET;
+		else
+			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP2_WPTR_OFFSET;
+		mqd->queue_state.cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
+		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR, mqd->queue_state.cp_hqd_pq_wptr_poll_addr);
+		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR_HI,
+		       mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi);
+
+		/* set the wb address wether it's enabled or not */
+		if (i == 0)
+			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET;
+		else
+			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET;
+		mqd->queue_state.cp_hqd_pq_rptr_report_addr = wb_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi =
+			upper_32_bits(wb_gpu_addr) & 0xffff;
+		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR,
+		       mqd->queue_state.cp_hqd_pq_rptr_report_addr);
+		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR_HI,
+		       mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi);
+
+		/* enable the doorbell if requested */
+		if (use_doorbell) {
+			mqd->queue_state.cp_hqd_pq_doorbell_control =
+				RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_OFFSET_MASK;
+			mqd->queue_state.cp_hqd_pq_doorbell_control |=
+				DOORBELL_OFFSET(rdev->ring[idx].doorbell_offset / 4);
+			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+			mqd->queue_state.cp_hqd_pq_doorbell_control &=
+				~(DOORBELL_SOURCE | DOORBELL_HIT);
+
+		} else {
+			mqd->queue_state.cp_hqd_pq_doorbell_control = 0;
+		}
+		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+		       mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+		/* read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+		rdev->ring[idx].wptr = 0;
+		mqd->queue_state.cp_hqd_pq_wptr = rdev->ring[idx].wptr;
+		WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+		rdev->ring[idx].rptr = RREG32(CP_HQD_PQ_RPTR);
+		mqd->queue_state.cp_hqd_pq_rptr = rdev->ring[idx].rptr;
+
+		/* set the vmid for the queue */
+		mqd->queue_state.cp_hqd_vmid = 0;
+		WREG32(CP_HQD_VMID, mqd->queue_state.cp_hqd_vmid);
+
+		/* activate the queue */
+		mqd->queue_state.cp_hqd_active = 1;
+		WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active);
+
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+
+		radeon_bo_kunmap(rdev->ring[idx].mqd_obj);
+		radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+		rdev->ring[idx].ready = true;
+		r = radeon_ring_test(rdev, idx, &rdev->ring[idx]);
+		if (r)
+			rdev->ring[idx].ready = false;
+	}
+
 	return 0;
 }
 
-/* XXX temporary wrappers to handle both compute and gfx */
-/* XXX */
 static void cik_cp_enable(struct radeon_device *rdev, bool enable)
 {
 	cik_cp_gfx_enable(rdev, enable);
 	cik_cp_compute_enable(rdev, enable);
 }
 
-/* XXX */
 static int cik_cp_load_microcode(struct radeon_device *rdev)
 {
 	int r;
@@ -2237,14 +2668,12 @@ static int cik_cp_load_microcode(struct radeon_device *rdev)
 	return 0;
 }
 
-/* XXX */
 static void cik_cp_fini(struct radeon_device *rdev)
 {
 	cik_cp_gfx_fini(rdev);
 	cik_cp_compute_fini(rdev);
 }
 
-/* XXX */
 static int cik_cp_resume(struct radeon_device *rdev)
 {
 	int r;
@@ -2865,6 +3294,22 @@ static void cik_print_gpu_status_regs(struct radeon_device *rdev)
 		RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
 	dev_info(rdev->dev, "  SDMA1_STATUS_REG   = 0x%08X\n",
 		 RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
+	dev_info(rdev->dev, "  CP_STAT = 0x%08x\n", RREG32(CP_STAT));
+	dev_info(rdev->dev, "  CP_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_STALLED_STAT2 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT2));
+	dev_info(rdev->dev, "  CP_STALLED_STAT3 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT3));
+	dev_info(rdev->dev, "  CP_CPF_BUSY_STAT = 0x%08x\n",
+		 RREG32(CP_CPF_BUSY_STAT));
+	dev_info(rdev->dev, "  CP_CPF_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_CPF_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_CPF_STATUS = 0x%08x\n", RREG32(CP_CPF_STATUS));
+	dev_info(rdev->dev, "  CP_CPC_BUSY_STAT = 0x%08x\n", RREG32(CP_CPC_BUSY_STAT));
+	dev_info(rdev->dev, "  CP_CPC_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_CPC_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_CPC_STATUS = 0x%08x\n", RREG32(CP_CPC_STATUS));
 }
 
 /**

drivers/gpu/drm/radeon/cik.c static int cik_startup(struct radeon_device *rdev) · line 5400

Quoted 4 lines
drivers/gpu/drm/radeon/cik.c +1 -0
@@ -4952,12 +5397,31 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	/* allocate rlc buffers */

Init mec not allocate rlc ...

Quoted 261 lines
drivers/gpu/drm/radeon/cik.c +64 -0
+	r = cik_mec_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init MEC BOs!\n");
+		return r;
+	}
+
 	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
 		return r;
 	}
 
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
 	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
@@ -5002,6 +5466,36 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	/* set up the compute queues */
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
+			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+	ring->me = 1; /* first MEC */
+	ring->pipe = 0; /* first pipe */
+	ring->queue = 0; /* first queue */
+	ring->wptr_offs = CIK_WB_CP1_WPTR_OFFSET;
+	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
+	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
+	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
+			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+			     0, 0xffffffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+	/* dGPU only have 1 MEC */
+	ring->me = 1; /* first MEC */
+	ring->pipe = 0; /* first pipe */
+	ring->queue = 1; /* second queue */
+	ring->wptr_offs = CIK_WB_CP2_WPTR_OFFSET;
+	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
+	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
+	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
+
 	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
 			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
@@ -5176,6 +5670,20 @@ int cik_init(struct radeon_device *rdev)
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 1024 * 1024);
 
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+	if (r)
+		return r;
+
 	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 256 * 1024);
@@ -5206,6 +5714,7 @@ int cik_init(struct radeon_device *rdev)
 		cik_sdma_fini(rdev);
 		cik_irq_fini(rdev);
 		si_rlc_fini(rdev);
+		cik_mec_fini(rdev);
 		radeon_wb_fini(rdev);
 		radeon_ib_pool_fini(rdev);
 		radeon_vm_manager_fini(rdev);
@@ -5241,6 +5750,7 @@ void cik_fini(struct radeon_device *rdev)
 	cik_sdma_fini(rdev);
 	cik_irq_fini(rdev);
 	si_rlc_fini(rdev);
+	cik_mec_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	radeon_ib_pool_fini(rdev);
drivers/gpu/drm/radeon/cikd.h +62 -0
index 79be39e..63514b9 100644
@@ -460,6 +460,13 @@
 #       define RDERR_INT_ENABLE                         (1 << 0)
 #       define GUI_IDLE_INT_ENABLE                      (1 << 19)
 
+#define CP_CPC_STATUS					0x8210
+#define CP_CPC_BUSY_STAT				0x8214
+#define CP_CPC_STALLED_STAT1				0x8218
+#define CP_CPF_STATUS					0x821c
+#define CP_CPF_BUSY_STAT				0x8220
+#define CP_CPF_STALLED_STAT1				0x8224
+
 #define CP_MEC_CNTL					0x8234
 #define		MEC_ME2_HALT					(1 << 28)
 #define		MEC_ME1_HALT					(1 << 30)
@@ -468,6 +475,12 @@
 #define		MEC_ME2_HALT					(1 << 28)
 #define		MEC_ME1_HALT					(1 << 30)
 
+#define CP_STALLED_STAT3				0x8670
+#define CP_STALLED_STAT1				0x8674
+#define CP_STALLED_STAT2				0x8678
+
+#define CP_STAT						0x8680
+
 #define CP_ME_CNTL					0x86D8
 #define		CP_CE_HALT					(1 << 24)
 #define		CP_PFP_HALT					(1 << 26)
@@ -701,6 +714,11 @@
 #       define CP_RINGID1_INT_STAT                      (1 << 30)
 #       define CP_RINGID0_INT_STAT                      (1 << 31)
 
+#define CP_CPF_DEBUG                                    0xC200
+
+#define CP_PQ_WPTR_POLL_CNTL                            0xC20C
+#define		WPTR_POLL_EN      			(1 << 31)
+
 #define CP_ME1_PIPE0_INT_CNTL                           0xC214
 #define CP_ME1_PIPE1_INT_CNTL                           0xC218
 #define CP_ME1_PIPE2_INT_CNTL                           0xC21C
@@ -773,6 +791,50 @@
 #define RLC_GPM_SCRATCH_ADDR                              0xC4B0
 #define RLC_GPM_SCRATCH_DATA                              0xC4B4
 
+#define CP_HPD_EOP_BASE_ADDR                              0xC904
+#define CP_HPD_EOP_BASE_ADDR_HI                           0xC908
+#define CP_HPD_EOP_VMID                                   0xC90C
+#define CP_HPD_EOP_CONTROL                                0xC910
+#define		EOP_SIZE(x)				((x) << 0)
+#define		EOP_SIZE_MASK      			(0x3f << 0)
+#define CP_MQD_BASE_ADDR                                  0xC914
+#define CP_MQD_BASE_ADDR_HI                               0xC918
+#define CP_HQD_ACTIVE                                     0xC91C
+#define CP_HQD_VMID                                       0xC920
+
+#define CP_HQD_PQ_BASE                                    0xC934
+#define CP_HQD_PQ_BASE_HI                                 0xC938
+#define CP_HQD_PQ_RPTR                                    0xC93C
+#define CP_HQD_PQ_RPTR_REPORT_ADDR                        0xC940
+#define CP_HQD_PQ_RPTR_REPORT_ADDR_HI                     0xC944
+#define CP_HQD_PQ_WPTR_POLL_ADDR                          0xC948
+#define CP_HQD_PQ_WPTR_POLL_ADDR_HI                       0xC94C
+#define CP_HQD_PQ_DOORBELL_CONTROL                        0xC950
+#define		DOORBELL_OFFSET(x)			((x) << 2)
+#define		DOORBELL_OFFSET_MASK			(0x1fffff << 2)
+#define		DOORBELL_SOURCE      			(1 << 28)
+#define		DOORBELL_SCHD_HIT      			(1 << 29)
+#define		DOORBELL_EN      			(1 << 30)
+#define		DOORBELL_HIT      			(1 << 31)
+#define CP_HQD_PQ_WPTR                                    0xC954
+#define CP_HQD_PQ_CONTROL                                 0xC958
+#define		QUEUE_SIZE(x)				((x) << 0)
+#define		QUEUE_SIZE_MASK      			(0x3f << 0)
+#define		RPTR_BLOCK_SIZE(x)			((x) << 8)
+#define		RPTR_BLOCK_SIZE_MASK			(0x3f << 8)
+#define		PQ_VOLATILE      			(1 << 26)
+#define		NO_UPDATE_RPTR      			(1 << 27)
+#define		UNORD_DISPATCH      			(1 << 28)
+#define		ROQ_PQ_IB_FLIP      			(1 << 29)
+#define		PRIV_STATE      			(1 << 30)
+#define		KMD_QUEUE      				(1 << 31)
+
+#define CP_HQD_DEQUEUE_REQUEST                          0xC974
+
+#define CP_MQD_CONTROL                                  0xC99C
+#define		MQD_VMID(x)				((x) << 0)
+#define		MQD_VMID_MASK      			(0xf << 0)
+
 #define PA_SC_RASTER_CONFIG                             0x28350
 #       define RASTER_CONFIG_RB_MAP_0                   0
 #       define RASTER_CONFIG_RB_MAP_1                   1
drivers/gpu/drm/radeon/radeon.h +19 -0
index a2a3430..d40d506 100644
@@ -714,6 +714,22 @@ struct radeon_ring {
 		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
 		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
 	} funcs;
+	/* for CIK queues */
+	u32 me;
+	u32 pipe;
+	u32 queue;
+	struct radeon_bo	*mqd_obj;
+	u32 doorbell_page_num;
+	u32 doorbell_offset;
+	unsigned		wptr_offs;
+};
+
+struct radeon_mec {
+	struct radeon_bo	*hpd_eop_obj;
+	u64			hpd_eop_gpu_addr;
+	u32 num_pipe;
+	u32 num_mec;
+	u32 num_queue;
 };
 
 /*
@@ -971,6 +987,8 @@ struct radeon_wb {
 #define CAYMAN_WB_DMA1_RPTR_OFFSET   2304
 #define R600_WB_UVD_RPTR_OFFSET  2560
 #define R600_WB_EVENT_OFFSET     3072
+#define CIK_WB_CP1_WPTR_OFFSET     3328
+#define CIK_WB_CP2_WPTR_OFFSET     3584
 
 /**
  * struct radeon_pm - power management datas
@@ -1760,6 +1778,7 @@ struct radeon_device {
 	int msi_enabled; /* msi enabled */
 	struct r600_ih ih; /* r6/700 interrupt ring */
 	struct si_rlc rlc;
+	struct radeon_mec mec;
 	struct work_struct hotplug_work;
 	struct work_struct audio_work;
 	struct work_struct reset_work;
drivers/gpu/drm/radeon/radeon_cs.c +1 -3
index cf71734..7e265a5 100644
@@ -121,9 +121,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
 		p->ring = RADEON_RING_TYPE_GFX_INDEX;
 		break;
 	case RADEON_CS_RING_COMPUTE:
-		if (p->rdev->family >= CHIP_BONAIRE)
-			p->ring = RADEON_RING_TYPE_GFX_INDEX;
-		else if (p->rdev->family >= CHIP_TAHITI) {
+		if (p->rdev->family >= CHIP_TAHITI) {
 			if (p->priority > 0)
 				p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
 			else
Signature · 6 lines
1.7.7.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#58 lore raw

PATCH 53/165 drm/radeon/cik: switch to type3 nop packet for compute rings

In reply to [email protected]

From: Alex Deucher <[email protected]>

Type 2 packets are deprecated on CIK MEC and we should use type 3 nop packets. Setting the count field to the max value (0x3fff) indicates that only one dword should be skipped like a type 2 packet.

---
 drivers/gpu/drm/radeon/cik.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/radeon/cik.c +2 -2
index 9d2d6bb..08dc4c2 100644
@@ -5470,7 +5470,7 @@ static int cik_startup(struct radeon_device *rdev)
 	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
 			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
-			     0, 0xfffff, RADEON_CP_PACKET2);
+			     0, 0xfffff, PACKET3(PACKET3_NOP, 0x3FFF));
 	if (r)
 		return r;
 	ring->me = 1; /* first MEC */
@@ -5484,7 +5484,7 @@ static int cik_startup(struct radeon_device *rdev)
 	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
 			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
-			     0, 0xffffffff, RADEON_CP_PACKET2);
+			     0, 0xffffffff, PACKET3(PACKET3_NOP, 0x3FFF));
 	if (r)
 		return r;
 	/* dGPU only have 1 MEC */
Signature · 1 line
1.7.7.5
Reviewed-by on v1 53/165
#59 lore raw

Re: [PATCH 053/165] drm/radeon/cik: switch to type3 nop packet for compute rings

Quoted 8 lines · On Wed, Jun 26, 2013 at 09:22:13AM -0400, [email protected] wrote:

From: Alex Deucher <[email protected]>

Type 2 packets are deprecated on CIK MEC and we should use type 3 nop packets. Setting the count field to the max value (0x3fff) indicates that only one dword should be skipped like a type 2 packet.

What about adding same comment in the code and not only in git commit message.

Quoted 33 lines
---
 drivers/gpu/drm/radeon/cik.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/radeon/cik.c +2 -2
index 9d2d6bb..08dc4c2 100644
@@ -5470,7 +5470,7 @@ static int cik_startup(struct radeon_device *rdev)
 	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
 			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
-			     0, 0xfffff, RADEON_CP_PACKET2);
+			     0, 0xfffff, PACKET3(PACKET3_NOP, 0x3FFF));
 	if (r)
 		return r;
 	ring->me = 1; /* first MEC */
@@ -5484,7 +5484,7 @@ static int cik_startup(struct radeon_device *rdev)
 	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
 			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
-			     0, 0xffffffff, RADEON_CP_PACKET2);
+			     0, 0xffffffff, PACKET3(PACKET3_NOP, 0x3FFF));
 	if (r)
 		return r;
 	/* dGPU only have 1 MEC */
Signature · 6 lines
1.7.7.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#60 lore raw

PATCH 54/165 drm/radeon: fix up ring functions for compute rings

In reply to [email protected]

From: Alex Deucher <[email protected]>

The compute rings use RELEASE_MEM rather then EOP packets for writing fences and there is no SYNC_PFP_ME packet on the compute rings.

---
 drivers/gpu/drm/radeon/cik.c |   53 +++++++++++++++++++++++++++++++++++++----
 1 files changed, 47 insertions(+), 6 deletions(-)
drivers/gpu/drm/radeon/cik.c +47 -6
index 08dc4c2..596bfed 100644
@@ -1706,7 +1706,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
 }
 
 /**
- * cik_fence_ring_emit - emit a fence on the gfx ring
+ * cik_fence_gfx_ring_emit - emit a fence on the gfx ring
  *
  * @rdev: radeon_device pointer
  * @fence: radeon fence object
@@ -1714,8 +1714,8 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
  * Emits a fence sequnce number on the gfx ring and flushes
  * GPU caches.
  */
-void cik_fence_ring_emit(struct radeon_device *rdev,
-			 struct radeon_fence *fence)
+void cik_fence_gfx_ring_emit(struct radeon_device *rdev,
+			     struct radeon_fence *fence)
 {
 	struct radeon_ring *ring = &rdev->ring[fence->ring];
 	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
@@ -1742,6 +1742,44 @@ void cik_fence_ring_emit(struct radeon_device *rdev,
 	radeon_ring_write(ring, 0);
 }
 
+/**
+ * cik_fence_compute_ring_emit - emit a fence on the compute ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Emits a fence sequnce number on the compute ring and flushes
+ * GPU caches.
+ */
+void cik_fence_compute_ring_emit(struct radeon_device *rdev,
+				 struct radeon_fence *fence)
+{
+	struct radeon_ring *ring = &rdev->ring[fence->ring];
+	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+	/* RELEASE_MEM - flush caches, send int */
+	radeon_ring_write(ring, PACKET3(PACKET3_RELEASE_MEM, 5));
+	radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+				 EOP_TC_ACTION_EN |
+				 EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+				 EVENT_INDEX(5)));
+	radeon_ring_write(ring, DATA_SEL(1) | INT_SEL(2));
+	radeon_ring_write(ring, addr & 0xfffffffc);
+	radeon_ring_write(ring, upper_32_bits(addr));
+	radeon_ring_write(ring, fence->seq);
+	radeon_ring_write(ring, 0);
+	/* HDP flush */
+	/* We should be using the new WAIT_REG_MEM special op packet here
+	 * but it causes the CP to hang
+	 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 0);
+}
+
 void cik_semaphore_ring_emit(struct radeon_device *rdev,
 			     struct radeon_ring *ring,
 			     struct radeon_semaphore *semaphore,
@@ -4051,9 +4089,12 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 	radeon_ring_write(ring, 0);
 	radeon_ring_write(ring, 1 << vm->id);
 
-	/* sync PFP to ME, otherwise we might get invalid PFP reads */
-	radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
-	radeon_ring_write(ring, 0x0);
+	/* compute doesn't have PFP */
+	if (ridx == RADEON_RING_TYPE_GFX_INDEX) {
+		/* sync PFP to ME, otherwise we might get invalid PFP reads */
+		radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+		radeon_ring_write(ring, 0x0);
+	}
 }
 
 /**
Signature · 1 line
1.7.7.5
#61 lore raw

PATCH 55/165 drm/radeon/cik: add support for compute interrupts

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/cik.c |  121 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 116 insertions(+), 5 deletions(-)
drivers/gpu/drm/radeon/cik.c +116 -5
index 596bfed..5923ef7 100644
@@ -4631,6 +4631,8 @@ int cik_irq_set(struct radeon_device *rdev)
 {
 	u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE |
 		PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
+	u32 cp_m1p0, cp_m1p1, cp_m1p2, cp_m1p3;
+	u32 cp_m2p0, cp_m2p1, cp_m2p2, cp_m2p3;
 	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
 	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
 	u32 grbm_int_cntl = 0;
@@ -4658,13 +4660,106 @@ int cik_irq_set(struct radeon_device *rdev)
 	dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
 	dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
 
+	cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m1p1 = RREG32(CP_ME1_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m1p2 = RREG32(CP_ME1_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m1p3 = RREG32(CP_ME1_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p0 = RREG32(CP_ME2_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p1 = RREG32(CP_ME2_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+
 	/* enable CP interrupts on all rings */
 	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
 		DRM_DEBUG("cik_irq_set: sw int gfx\n");
 		cp_int_cntl |= TIME_STAMP_INT_ENABLE;
 	}
-	/* TODO: compute queues! */
-	/* CP_ME[1-2]_PIPE[0-3]_INT_CNTL */
+	if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP1_INDEX])) {
+		struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+		DRM_DEBUG("si_irq_set: sw int cp1\n");
+		if (ring->me == 1) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m1p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m1p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else if (ring->me == 2) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m2p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m2p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else {
+			DRM_DEBUG("si_irq_set: sw int cp1 invalid me %d\n", ring->me);
+		}
+	}
+	if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP2_INDEX])) {
+		struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+		DRM_DEBUG("si_irq_set: sw int cp2\n");
+		if (ring->me == 1) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m1p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m1p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else if (ring->me == 2) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m2p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m2p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else {
+			DRM_DEBUG("si_irq_set: sw int cp2 invalid me %d\n", ring->me);
+		}
+	}
 
 	if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
 		DRM_DEBUG("cik_irq_set: sw int dma\n");
@@ -4736,6 +4831,15 @@ int cik_irq_set(struct radeon_device *rdev)
 	WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl);
 	WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1);
 
+	WREG32(CP_ME1_PIPE0_INT_CNTL, cp_m1p0);
+	WREG32(CP_ME1_PIPE1_INT_CNTL, cp_m1p1);
+	WREG32(CP_ME1_PIPE2_INT_CNTL, cp_m1p2);
+	WREG32(CP_ME1_PIPE3_INT_CNTL, cp_m1p3);
+	WREG32(CP_ME2_PIPE0_INT_CNTL, cp_m2p0);
+	WREG32(CP_ME2_PIPE1_INT_CNTL, cp_m2p1);
+	WREG32(CP_ME2_PIPE2_INT_CNTL, cp_m2p2);
+	WREG32(CP_ME2_PIPE3_INT_CNTL, cp_m2p3);
+
 	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
 
 	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
@@ -4957,6 +5061,8 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
  */
 int cik_irq_process(struct radeon_device *rdev)
 {
+	struct radeon_ring *cp1_ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	struct radeon_ring *cp2_ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
 	u32 wptr;
 	u32 rptr;
 	u32 src_id, src_data, ring_id;
@@ -5222,10 +5328,11 @@ restart_ih:
 				radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
 				break;
 			case 1:
-				/* XXX compute */
-				break;
 			case 2:
-				/* XXX compute */
+				if ((cp1_ring->me == me_id) & (cp1_ring->pipe == pipe_id))
+					radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+				if ((cp2_ring->me == me_id) & (cp2_ring->pipe == pipe_id))
+					radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
 				break;
 			}
 			break;
@@ -5244,9 +5351,11 @@ restart_ih:
 				break;
 			case 1:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			case 2:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			}
 			break;
@@ -5265,9 +5374,11 @@ restart_ih:
 				break;
 			case 1:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			case 2:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			}
 			break;
Signature · 1 line
1.7.7.5
#62 lore raw

PATCH 56/165 drm/radeon/cik: add support for golden register init

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/cik.c |  438 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 438 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/cik.c +438 -0
index 5923ef7..e899c44 100644
@@ -99,6 +99,439 @@ void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 	(void)RREG32(PCIE_DATA);
 }
 
+static const u32 bonaire_golden_spm_registers[] =
+{
+	0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 bonaire_golden_common_registers[] =
+{
+	0xc770, 0xffffffff, 0x00000800,
+	0xc774, 0xffffffff, 0x00000800,
+	0xc798, 0xffffffff, 0x00007fbf,
+	0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 bonaire_golden_registers[] =
+{
+	0x3354, 0x00000333, 0x00000333,
+	0x3350, 0x000c0fc0, 0x00040200,
+	0x9a10, 0x00010000, 0x00058208,
+	0x3c000, 0xffff1fff, 0x00140000,
+	0x3c200, 0xfdfc0fff, 0x00000100,
+	0x3c234, 0x40000000, 0x40000200,
+	0x9830, 0xffffffff, 0x00000000,
+	0x9834, 0xf00fffff, 0x00000400,
+	0x9838, 0x0002021c, 0x00020200,
+	0xc78, 0x00000080, 0x00000000,
+	0x5bb0, 0x000000f0, 0x00000070,
+	0x5bc0, 0xf0311fff, 0x80300000,
+	0x98f8, 0x73773777, 0x12010001,
+	0x350c, 0x00810000, 0x408af000,
+	0x7030, 0x31000111, 0x00000011,
+	0x2f48, 0x73773777, 0x12010001,
+	0x220c, 0x00007fb6, 0x0021a1b1,
+	0x2210, 0x00007fb6, 0x002021b1,
+	0x2180, 0x00007fb6, 0x00002191,
+	0x2218, 0x00007fb6, 0x002121b1,
+	0x221c, 0x00007fb6, 0x002021b1,
+	0x21dc, 0x00007fb6, 0x00002191,
+	0x21e0, 0x00007fb6, 0x00002191,
+	0x3628, 0x0000003f, 0x0000000a,
+	0x362c, 0x0000003f, 0x0000000a,
+	0x2ae4, 0x00073ffe, 0x000022a2,
+	0x240c, 0x000007ff, 0x00000000,
+	0x8a14, 0xf000003f, 0x00000007,
+	0x8bf0, 0x00002001, 0x00000001,
+	0x8b24, 0xffffffff, 0x00ffffff,
+	0x30a04, 0x0000ff0f, 0x00000000,
+	0x28a4c, 0x07ffffff, 0x06000000,
+	0x4d8, 0x00000fff, 0x00000100,
+	0x3e78, 0x00000001, 0x00000002,
+	0x9100, 0x03000000, 0x0362c688,
+	0x8c00, 0x000000ff, 0x00000001,
+	0xe40, 0x00001fff, 0x00001fff,
+	0x9060, 0x0000007f, 0x00000020,
+	0x9508, 0x00010000, 0x00010000,
+	0xac14, 0x000003ff, 0x000000f3,
+	0xac0c, 0xffffffff, 0x00001032
+};
+
+static const u32 bonaire_mgcg_cgcg_init[] =
+{
+	0xc420, 0xffffffff, 0xfffffffc,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c2a0, 0xffffffff, 0x00000100,
+	0x3c208, 0xffffffff, 0x00000100,
+	0x3c2c0, 0xffffffff, 0xc0000100,
+	0x3c2c8, 0xffffffff, 0xc0000100,
+	0x3c2c4, 0xffffffff, 0xc0000100,
+	0x55e4, 0xffffffff, 0x00600100,
+	0x3c280, 0xffffffff, 0x00000100,
+	0x3c214, 0xffffffff, 0x06000100,
+	0x3c220, 0xffffffff, 0x00000100,
+	0x3c218, 0xffffffff, 0x06000100,
+	0x3c204, 0xffffffff, 0x00000100,
+	0x3c2e0, 0xffffffff, 0x00000100,
+	0x3c224, 0xffffffff, 0x00000100,
+	0x3c200, 0xffffffff, 0x00000100,
+	0x3c230, 0xffffffff, 0x00000100,
+	0x3c234, 0xffffffff, 0x00000100,
+	0x3c250, 0xffffffff, 0x00000100,
+	0x3c254, 0xffffffff, 0x00000100,
+	0x3c258, 0xffffffff, 0x00000100,
+	0x3c25c, 0xffffffff, 0x00000100,
+	0x3c260, 0xffffffff, 0x00000100,
+	0x3c27c, 0xffffffff, 0x00000100,
+	0x3c278, 0xffffffff, 0x00000100,
+	0x3c210, 0xffffffff, 0x06000100,
+	0x3c290, 0xffffffff, 0x00000100,
+	0x3c274, 0xffffffff, 0x00000100,
+	0x3c2b4, 0xffffffff, 0x00000100,
+	0x3c2b0, 0xffffffff, 0x00000100,
+	0x3c270, 0xffffffff, 0x00000100,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c020, 0xffffffff, 0x00010000,
+	0x3c024, 0xffffffff, 0x00030002,
+	0x3c028, 0xffffffff, 0x00040007,
+	0x3c02c, 0xffffffff, 0x00060005,
+	0x3c030, 0xffffffff, 0x00090008,
+	0x3c034, 0xffffffff, 0x00010000,
+	0x3c038, 0xffffffff, 0x00030002,
+	0x3c03c, 0xffffffff, 0x00040007,
+	0x3c040, 0xffffffff, 0x00060005,
+	0x3c044, 0xffffffff, 0x00090008,
+	0x3c048, 0xffffffff, 0x00010000,
+	0x3c04c, 0xffffffff, 0x00030002,
+	0x3c050, 0xffffffff, 0x00040007,
+	0x3c054, 0xffffffff, 0x00060005,
+	0x3c058, 0xffffffff, 0x00090008,
+	0x3c05c, 0xffffffff, 0x00010000,
+	0x3c060, 0xffffffff, 0x00030002,
+	0x3c064, 0xffffffff, 0x00040007,
+	0x3c068, 0xffffffff, 0x00060005,
+	0x3c06c, 0xffffffff, 0x00090008,
+	0x3c070, 0xffffffff, 0x00010000,
+	0x3c074, 0xffffffff, 0x00030002,
+	0x3c078, 0xffffffff, 0x00040007,
+	0x3c07c, 0xffffffff, 0x00060005,
+	0x3c080, 0xffffffff, 0x00090008,
+	0x3c084, 0xffffffff, 0x00010000,
+	0x3c088, 0xffffffff, 0x00030002,
+	0x3c08c, 0xffffffff, 0x00040007,
+	0x3c090, 0xffffffff, 0x00060005,
+	0x3c094, 0xffffffff, 0x00090008,
+	0x3c098, 0xffffffff, 0x00010000,
+	0x3c09c, 0xffffffff, 0x00030002,
+	0x3c0a0, 0xffffffff, 0x00040007,
+	0x3c0a4, 0xffffffff, 0x00060005,
+	0x3c0a8, 0xffffffff, 0x00090008,
+	0x3c000, 0xffffffff, 0x96e00200,
+	0x8708, 0xffffffff, 0x00900100,
+	0xc424, 0xffffffff, 0x0020003f,
+	0x38, 0xffffffff, 0x0140001c,
+	0x3c, 0x000f0000, 0x000f0000,
+	0x220, 0xffffffff, 0xC060000C,
+	0x224, 0xc0000fff, 0x00000100,
+	0xf90, 0xffffffff, 0x00000100,
+	0xf98, 0x00000101, 0x00000000,
+	0x20a8, 0xffffffff, 0x00000104,
+	0x55e4, 0xff000fff, 0x00000100,
+	0x30cc, 0xc0000fff, 0x00000104,
+	0xc1e4, 0x00000001, 0x00000001,
+	0xd00c, 0xff000ff0, 0x00000100,
+	0xd80c, 0xff000ff0, 0x00000100
+};
+
+static const u32 spectre_golden_spm_registers[] =
+{
+	0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 spectre_golden_common_registers[] =
+{
+	0xc770, 0xffffffff, 0x00000800,
+	0xc774, 0xffffffff, 0x00000800,
+	0xc798, 0xffffffff, 0x00007fbf,
+	0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 spectre_golden_registers[] =
+{
+	0x3c000, 0xffff1fff, 0x96940200,
+	0x3c00c, 0xffff0001, 0xff000000,
+	0x3c200, 0xfffc0fff, 0x00000100,
+	0x6ed8, 0x00010101, 0x00010000,
+	0x9834, 0xf00fffff, 0x00000400,
+	0x9838, 0xfffffffc, 0x00020200,
+	0x5bb0, 0x000000f0, 0x00000070,
+	0x5bc0, 0xf0311fff, 0x80300000,
+	0x98f8, 0x73773777, 0x12010001,
+	0x9b7c, 0x00ff0000, 0x00fc0000,
+	0x2f48, 0x73773777, 0x12010001,
+	0x8a14, 0xf000003f, 0x00000007,
+	0x8b24, 0xffffffff, 0x00ffffff,
+	0x28350, 0x3f3f3fff, 0x00000082,
+	0x28355, 0x0000003f, 0x00000000,
+	0x3e78, 0x00000001, 0x00000002,
+	0x913c, 0xffff03df, 0x00000004,
+	0xc768, 0x00000008, 0x00000008,
+	0x8c00, 0x000008ff, 0x00000800,
+	0x9508, 0x00010000, 0x00010000,
+	0xac0c, 0xffffffff, 0x54763210,
+	0x214f8, 0x01ff01ff, 0x00000002,
+	0x21498, 0x007ff800, 0x00200000,
+	0x2015c, 0xffffffff, 0x00000f40,
+	0x30934, 0xffffffff, 0x00000001
+};
+
+static const u32 spectre_mgcg_cgcg_init[] =
+{
+	0xc420, 0xffffffff, 0xfffffffc,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c2a0, 0xffffffff, 0x00000100,
+	0x3c208, 0xffffffff, 0x00000100,
+	0x3c2c0, 0xffffffff, 0x00000100,
+	0x3c2c8, 0xffffffff, 0x00000100,
+	0x3c2c4, 0xffffffff, 0x00000100,
+	0x55e4, 0xffffffff, 0x00600100,
+	0x3c280, 0xffffffff, 0x00000100,
+	0x3c214, 0xffffffff, 0x06000100,
+	0x3c220, 0xffffffff, 0x00000100,
+	0x3c218, 0xffffffff, 0x06000100,
+	0x3c204, 0xffffffff, 0x00000100,
+	0x3c2e0, 0xffffffff, 0x00000100,
+	0x3c224, 0xffffffff, 0x00000100,
+	0x3c200, 0xffffffff, 0x00000100,
+	0x3c230, 0xffffffff, 0x00000100,
+	0x3c234, 0xffffffff, 0x00000100,
+	0x3c250, 0xffffffff, 0x00000100,
+	0x3c254, 0xffffffff, 0x00000100,
+	0x3c258, 0xffffffff, 0x00000100,
+	0x3c25c, 0xffffffff, 0x00000100,
+	0x3c260, 0xffffffff, 0x00000100,
+	0x3c27c, 0xffffffff, 0x00000100,
+	0x3c278, 0xffffffff, 0x00000100,
+	0x3c210, 0xffffffff, 0x06000100,
+	0x3c290, 0xffffffff, 0x00000100,
+	0x3c274, 0xffffffff, 0x00000100,
+	0x3c2b4, 0xffffffff, 0x00000100,
+	0x3c2b0, 0xffffffff, 0x00000100,
+	0x3c270, 0xffffffff, 0x00000100,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c020, 0xffffffff, 0x00010000,
+	0x3c024, 0xffffffff, 0x00030002,
+	0x3c028, 0xffffffff, 0x00040007,
+	0x3c02c, 0xffffffff, 0x00060005,
+	0x3c030, 0xffffffff, 0x00090008,
+	0x3c034, 0xffffffff, 0x00010000,
+	0x3c038, 0xffffffff, 0x00030002,
+	0x3c03c, 0xffffffff, 0x00040007,
+	0x3c040, 0xffffffff, 0x00060005,
+	0x3c044, 0xffffffff, 0x00090008,
+	0x3c048, 0xffffffff, 0x00010000,
+	0x3c04c, 0xffffffff, 0x00030002,
+	0x3c050, 0xffffffff, 0x00040007,
+	0x3c054, 0xffffffff, 0x00060005,
+	0x3c058, 0xffffffff, 0x00090008,
+	0x3c05c, 0xffffffff, 0x00010000,
+	0x3c060, 0xffffffff, 0x00030002,
+	0x3c064, 0xffffffff, 0x00040007,
+	0x3c068, 0xffffffff, 0x00060005,
+	0x3c06c, 0xffffffff, 0x00090008,
+	0x3c070, 0xffffffff, 0x00010000,
+	0x3c074, 0xffffffff, 0x00030002,
+	0x3c078, 0xffffffff, 0x00040007,
+	0x3c07c, 0xffffffff, 0x00060005,
+	0x3c080, 0xffffffff, 0x00090008,
+	0x3c084, 0xffffffff, 0x00010000,
+	0x3c088, 0xffffffff, 0x00030002,
+	0x3c08c, 0xffffffff, 0x00040007,
+	0x3c090, 0xffffffff, 0x00060005,
+	0x3c094, 0xffffffff, 0x00090008,
+	0x3c098, 0xffffffff, 0x00010000,
+	0x3c09c, 0xffffffff, 0x00030002,
+	0x3c0a0, 0xffffffff, 0x00040007,
+	0x3c0a4, 0xffffffff, 0x00060005,
+	0x3c0a8, 0xffffffff, 0x00090008,
+	0x3c0ac, 0xffffffff, 0x00010000,
+	0x3c0b0, 0xffffffff, 0x00030002,
+	0x3c0b4, 0xffffffff, 0x00040007,
+	0x3c0b8, 0xffffffff, 0x00060005,
+	0x3c0bc, 0xffffffff, 0x00090008,
+	0x3c000, 0xffffffff, 0x96e00200,
+	0x8708, 0xffffffff, 0x00900100,
+	0xc424, 0xffffffff, 0x0020003f,
+	0x38, 0xffffffff, 0x0140001c,
+	0x3c, 0x000f0000, 0x000f0000,
+	0x220, 0xffffffff, 0xC060000C,
+	0x224, 0xc0000fff, 0x00000100,
+	0xf90, 0xffffffff, 0x00000100,
+	0xf98, 0x00000101, 0x00000000,
+	0x20a8, 0xffffffff, 0x00000104,
+	0x55e4, 0xff000fff, 0x00000100,
+	0x30cc, 0xc0000fff, 0x00000104,
+	0xc1e4, 0x00000001, 0x00000001,
+	0xd00c, 0xff000ff0, 0x00000100,
+	0xd80c, 0xff000ff0, 0x00000100
+};
+
+static const u32 kalindi_golden_spm_registers[] =
+{
+	0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 kalindi_golden_common_registers[] =
+{
+	0xc770, 0xffffffff, 0x00000800,
+	0xc774, 0xffffffff, 0x00000800,
+	0xc798, 0xffffffff, 0x00007fbf,
+	0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 kalindi_golden_registers[] =
+{
+	0x3c000, 0xffffdfff, 0x6e944040,
+	0x55e4, 0xff607fff, 0xfc000100,
+	0x3c220, 0xff000fff, 0x00000100,
+	0x3c224, 0xff000fff, 0x00000100,
+	0x3c200, 0xfffc0fff, 0x00000100,
+	0x6ed8, 0x00010101, 0x00010000,
+	0x9830, 0xffffffff, 0x00000000,
+	0x9834, 0xf00fffff, 0x00000400,
+	0x5bb0, 0x000000f0, 0x00000070,
+	0x5bc0, 0xf0311fff, 0x80300000,
+	0x98f8, 0x73773777, 0x12010001,
+	0x98fc, 0xffffffff, 0x00000010,
+	0x9b7c, 0x00ff0000, 0x00fc0000,
+	0x8030, 0x00001f0f, 0x0000100a,
+	0x2f48, 0x73773777, 0x12010001,
+	0x2408, 0x000fffff, 0x000c007f,
+	0x8a14, 0xf000003f, 0x00000007,
+	0x8b24, 0x3fff3fff, 0x00ffcfff,
+	0x30a04, 0x0000ff0f, 0x00000000,
+	0x28a4c, 0x07ffffff, 0x06000000,
+	0x4d8, 0x00000fff, 0x00000100,
+	0x3e78, 0x00000001, 0x00000002,
+	0xc768, 0x00000008, 0x00000008,
+	0x8c00, 0x000000ff, 0x00000003,
+	0x214f8, 0x01ff01ff, 0x00000002,
+	0x21498, 0x007ff800, 0x00200000,
+	0x2015c, 0xffffffff, 0x00000f40,
+	0x88c4, 0x001f3ae3, 0x00000082,
+	0x88d4, 0x0000001f, 0x00000010,
+	0x30934, 0xffffffff, 0x00000000
+};
+
+static const u32 kalindi_mgcg_cgcg_init[] =
+{
+	0xc420, 0xffffffff, 0xfffffffc,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c2a0, 0xffffffff, 0x00000100,
+	0x3c208, 0xffffffff, 0x00000100,
+	0x3c2c0, 0xffffffff, 0x00000100,
+	0x3c2c8, 0xffffffff, 0x00000100,
+	0x3c2c4, 0xffffffff, 0x00000100,
+	0x55e4, 0xffffffff, 0x00600100,
+	0x3c280, 0xffffffff, 0x00000100,
+	0x3c214, 0xffffffff, 0x06000100,
+	0x3c220, 0xffffffff, 0x00000100,
+	0x3c218, 0xffffffff, 0x06000100,
+	0x3c204, 0xffffffff, 0x00000100,
+	0x3c2e0, 0xffffffff, 0x00000100,
+	0x3c224, 0xffffffff, 0x00000100,
+	0x3c200, 0xffffffff, 0x00000100,
+	0x3c230, 0xffffffff, 0x00000100,
+	0x3c234, 0xffffffff, 0x00000100,
+	0x3c250, 0xffffffff, 0x00000100,
+	0x3c254, 0xffffffff, 0x00000100,
+	0x3c258, 0xffffffff, 0x00000100,
+	0x3c25c, 0xffffffff, 0x00000100,
+	0x3c260, 0xffffffff, 0x00000100,
+	0x3c27c, 0xffffffff, 0x00000100,
+	0x3c278, 0xffffffff, 0x00000100,
+	0x3c210, 0xffffffff, 0x06000100,
+	0x3c290, 0xffffffff, 0x00000100,
+	0x3c274, 0xffffffff, 0x00000100,
+	0x3c2b4, 0xffffffff, 0x00000100,
+	0x3c2b0, 0xffffffff, 0x00000100,
+	0x3c270, 0xffffffff, 0x00000100,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c020, 0xffffffff, 0x00010000,
+	0x3c024, 0xffffffff, 0x00030002,
+	0x3c028, 0xffffffff, 0x00040007,
+	0x3c02c, 0xffffffff, 0x00060005,
+	0x3c030, 0xffffffff, 0x00090008,
+	0x3c034, 0xffffffff, 0x00010000,
+	0x3c038, 0xffffffff, 0x00030002,
+	0x3c03c, 0xffffffff, 0x00040007,
+	0x3c040, 0xffffffff, 0x00060005,
+	0x3c044, 0xffffffff, 0x00090008,
+	0x3c000, 0xffffffff, 0x96e00200,
+	0x8708, 0xffffffff, 0x00900100,
+	0xc424, 0xffffffff, 0x0020003f,
+	0x38, 0xffffffff, 0x0140001c,
+	0x3c, 0x000f0000, 0x000f0000,
+	0x220, 0xffffffff, 0xC060000C,
+	0x224, 0xc0000fff, 0x00000100,
+	0x20a8, 0xffffffff, 0x00000104,
+	0x55e4, 0xff000fff, 0x00000100,
+	0x30cc, 0xc0000fff, 0x00000104,
+	0xc1e4, 0x00000001, 0x00000001,
+	0xd00c, 0xff000ff0, 0x00000100,
+	0xd80c, 0xff000ff0, 0x00000100
+};
+
+static void cik_init_golden_registers(struct radeon_device *rdev)
+{
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+		radeon_program_register_sequence(rdev,
+						 bonaire_mgcg_cgcg_init,
+						 (const u32)ARRAY_SIZE(bonaire_mgcg_cgcg_init));
+		radeon_program_register_sequence(rdev,
+						 bonaire_golden_registers,
+						 (const u32)ARRAY_SIZE(bonaire_golden_registers));
+		radeon_program_register_sequence(rdev,
+						 bonaire_golden_common_registers,
+						 (const u32)ARRAY_SIZE(bonaire_golden_common_registers));
+		radeon_program_register_sequence(rdev,
+						 bonaire_golden_spm_registers,
+						 (const u32)ARRAY_SIZE(bonaire_golden_spm_registers));
+		break;
+	case CHIP_KABINI:
+		radeon_program_register_sequence(rdev,
+						 kalindi_mgcg_cgcg_init,
+						 (const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init));
+		radeon_program_register_sequence(rdev,
+						 kalindi_golden_registers,
+						 (const u32)ARRAY_SIZE(kalindi_golden_registers));
+		radeon_program_register_sequence(rdev,
+						 kalindi_golden_common_registers,
+						 (const u32)ARRAY_SIZE(kalindi_golden_common_registers));
+		radeon_program_register_sequence(rdev,
+						 kalindi_golden_spm_registers,
+						 (const u32)ARRAY_SIZE(kalindi_golden_spm_registers));
+		break;
+	case CHIP_KAVERI:
+		radeon_program_register_sequence(rdev,
+						 spectre_mgcg_cgcg_init,
+						 (const u32)ARRAY_SIZE(spectre_mgcg_cgcg_init));
+		radeon_program_register_sequence(rdev,
+						 spectre_golden_registers,
+						 (const u32)ARRAY_SIZE(spectre_golden_registers));
+		radeon_program_register_sequence(rdev,
+						 spectre_golden_common_registers,
+						 (const u32)ARRAY_SIZE(spectre_golden_common_registers));
+		radeon_program_register_sequence(rdev,
+						 spectre_golden_spm_registers,
+						 (const u32)ARRAY_SIZE(spectre_golden_spm_registers));
+		break;
+	default:
+		break;
+	}
+}
+
 /**
  * cik_get_xclk - get the xclk
  *
@@ -5719,6 +6152,9 @@ int cik_resume(struct radeon_device *rdev)
 	/* post card */
 	atom_asic_init(rdev->mode_info.atom_context);
 
+	/* init golden registers */
+	cik_init_golden_registers(rdev);
+
 	rdev->accel_working = true;
 	r = cik_startup(rdev);
 	if (r) {
@@ -5797,6 +6233,8 @@ int cik_init(struct radeon_device *rdev)
 		DRM_INFO("GPU not posted. posting now...\n");
 		atom_asic_init(rdev->mode_info.atom_context);
 	}
+	/* init golden registers */
+	cik_init_golden_registers(rdev);
 	/* Initialize scratch registers */
 	cik_scratch_init(rdev);
 	/* Initialize surface registers */
Signature · 1 line
1.7.7.5
#63 lore raw

PATCH 57/165 drm/radeon: add radeon_asic struct for CIK (v11)

In reply to [email protected]

From: Alex Deucher <[email protected]>

v2: fix up for latest reset changes
v3: use CP for pt updates for now
v4: update for 2 level PTs
v5: update for ib_parse removal
v6: vm_flush api change
v7: rebase
v8: fix gfx ring function pointers
v9: fix vm_set_page function params
v10: update for compute changes
v11: cleanup for release

---
 drivers/gpu/drm/radeon/radeon_asic.c |  287 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_asic.h |   47 ++++++
 2 files changed, 334 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/radeon_asic.c +287 -0
index 717b537..d60adb3 100644
@@ -1923,6 +1923,280 @@ static struct radeon_asic si_asic = {
 	},
 };
 
+static struct radeon_asic ci_asic = {
+	.init = &cik_init,
+	.fini = &cik_fini,
+	.suspend = &cik_suspend,
+	.resume = &cik_resume,
+	.asic_reset = &cik_asic_reset,
+	.vga_set_state = &r600_vga_set_state,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.get_xclk = &cik_get_xclk,
+	.get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+	.gart = {
+		.tlb_flush = &cik_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
+	.vm = {
+		.init = &cik_vm_init,
+		.fini = &cik_vm_fini,
+		.pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.set_page = &cik_vm_set_page,
+	},
+	.ring = {
+		[RADEON_RING_TYPE_GFX_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_gfx_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP1_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP2_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[R600_RING_TYPE_DMA_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_DMA1_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[R600_RING_TYPE_UVD_INDEX] = {
+			.ib_execute = &r600_uvd_ib_execute,
+			.emit_fence = &r600_uvd_fence_emit,
+			.emit_semaphore = &cayman_uvd_semaphore_emit,
+			.cs_parse = &radeon_uvd_cs_parse,
+			.ring_test = &r600_uvd_ring_test,
+			.ib_test = &r600_uvd_ib_test,
+			.is_lockup = &radeon_ring_test_lockup,
+		}
+	},
+	.irq = {
+		.set = &cik_irq_set,
+		.process = &cik_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &dce8_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = NULL,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &cik_copy_dma,
+		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &cik_copy_dma,
+		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &sumo_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+		.set_uvd_clocks = &cik_set_uvd_clocks,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
+};
+
+static struct radeon_asic kv_asic = {
+	.init = &cik_init,
+	.fini = &cik_fini,
+	.suspend = &cik_suspend,
+	.resume = &cik_resume,
+	.asic_reset = &cik_asic_reset,
+	.vga_set_state = &r600_vga_set_state,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.get_xclk = &cik_get_xclk,
+	.get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+	.gart = {
+		.tlb_flush = &cik_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
+	.vm = {
+		.init = &cik_vm_init,
+		.fini = &cik_vm_fini,
+		.pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.set_page = &cik_vm_set_page,
+	},
+	.ring = {
+		[RADEON_RING_TYPE_GFX_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_gfx_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP1_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP2_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[R600_RING_TYPE_DMA_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_DMA1_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[R600_RING_TYPE_UVD_INDEX] = {
+			.ib_execute = &r600_uvd_ib_execute,
+			.emit_fence = &r600_uvd_fence_emit,
+			.emit_semaphore = &cayman_uvd_semaphore_emit,
+			.cs_parse = &radeon_uvd_cs_parse,
+			.ring_test = &r600_uvd_ring_test,
+			.ib_test = &r600_uvd_ib_test,
+			.is_lockup = &radeon_ring_test_lockup,
+		}
+	},
+	.irq = {
+		.set = &cik_irq_set,
+		.process = &cik_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &dce8_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = NULL,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &cik_copy_dma,
+		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &cik_copy_dma,
+		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &sumo_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+		.set_uvd_clocks = &cik_set_uvd_clocks,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
+};
+
 /**
  * radeon_asic_init - register asic specific callbacks
  *
@@ -2086,6 +2360,19 @@ int radeon_asic_init(struct radeon_device *rdev)
 		else
 			rdev->has_uvd = true;
 		break;
+	case CHIP_BONAIRE:
+		rdev->asic = &ci_asic;
+		rdev->num_crtc = 6;
+		break;
+	case CHIP_KAVERI:
+	case CHIP_KABINI:
+		rdev->asic = &kv_asic;
+		/* set num crtcs */
+		if (rdev->family == CHIP_KAVERI)
+			rdev->num_crtc = 4;
+		else
+			rdev->num_crtc = 2;
+		break;
 	default:
 		/* FIXME: not supported yet */
 		return -EINVAL;
drivers/gpu/drm/radeon/radeon_asic.h +47 -0

58 lines not on this page · raw message

Signature · 1 line
1.7.7.5
#64 lore raw

PATCH 58/165 drm/radeon: add cik tile mode array query

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/cik.c        |    4 ++++
 drivers/gpu/drm/radeon/radeon.h     |    1 +
 drivers/gpu/drm/radeon/radeon_drv.c |    3 ++-
 drivers/gpu/drm/radeon/radeon_kms.c |   14 +++++++-------
 4 files changed, 14 insertions(+), 8 deletions(-)
drivers/gpu/drm/radeon/cik.c +4 -0
index e899c44..2cf3521 100644
@@ -1059,6 +1059,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 				gb_tile_moden = 0;
 				break;
 			}
+			rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 		}
 		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
@@ -1277,6 +1278,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 					gb_tile_moden = 0;
 					break;
 				}
+				rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 				WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 			}
 		} else if (num_rbs < 4) {
@@ -1402,6 +1404,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 					gb_tile_moden = 0;
 					break;
 				}
+				rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 				WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 			}
 		}
@@ -1619,6 +1622,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 				gb_tile_moden = 0;
 				break;
 			}
+			rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 		}
 		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
drivers/gpu/drm/radeon/radeon.h +1 -0
index d40d506..83f62aa 100644
@@ -1588,6 +1588,7 @@ struct cik_asic {
 	unsigned multi_gpu_tile_size;
 
 	unsigned tile_config;
+	uint32_t tile_mode_array[32];
 };
 
 union radeon_asic_config {
drivers/gpu/drm/radeon/radeon_drv.c +2 -1
index 094e7e5..02709e4 100644
@@ -74,9 +74,10 @@
  *   2.31.0 - Add fastfb support for rs690
  *   2.32.0 - new info request for rings working
  *   2.33.0 - Add SI tiling mode array query
+ *   2.34.0 - Add CIK tiling mode array query
  */
 #define KMS_DRIVER_MAJOR	2
-#define KMS_DRIVER_MINOR	33
+#define KMS_DRIVER_MINOR	34
 #define KMS_DRIVER_PATCHLEVEL	0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
drivers/gpu/drm/radeon/radeon_kms.c +7 -7
index c650228..49ff3d1 100644
@@ -423,15 +423,15 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		break;
 	case RADEON_INFO_SI_TILE_MODE_ARRAY:
 		if (rdev->family >= CHIP_BONAIRE) {
-			DRM_DEBUG_KMS("tile mode array is not implemented yet\n");
+			value = rdev->config.cik.tile_mode_array;
+			value_size = sizeof(uint32_t)*32;
+		} else if (rdev->family >= CHIP_TAHITI) {
+			value = rdev->config.si.tile_mode_array;
+			value_size = sizeof(uint32_t)*32;
+		} else {
+			DRM_DEBUG_KMS("tile mode array is si+ only!\n");
 			return -EINVAL;
 		}
-		if (rdev->family < CHIP_TAHITI) {
-			DRM_DEBUG_KMS("tile mode array is si only!\n");
-			return -EINVAL;
-		}
-		value = rdev->config.si.tile_mode_array;
-		value_size = sizeof(uint32_t)*32;
 		break;
 	default:
 		DRM_DEBUG_KMS("Invalid request %d\n", info->request);
Signature · 1 line
1.7.7.5
#65 lore raw

PATCH 59/165 drm/radeon: add current Bonaire PCI ids

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 include/drm/drm_pciids.h |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)
include/drm/drm_pciids.h +8 -0
index bb1bc48..23f89df 100644
@@ -152,6 +152,14 @@
 	{0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6631, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
Signature · 1 line
1.7.7.5
#66 lore raw

PATCH 60/165 drm/radeon: add current KB pci ids

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 include/drm/drm_pciids.h |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)
include/drm/drm_pciids.h +16 -0
index 23f89df..34efaf6 100644
@@ -588,6 +588,22 @@
 	{0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9832, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9833, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
Signature · 1 line
1.7.7.5
#67 lore raw

PATCH 61/165 drm/radeon/kms: add accessors for RCU indirect space

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/evergreen.c |    6 ++----
 drivers/gpu/drm/radeon/r600_reg.h  |    3 +++
 drivers/gpu/drm/radeon/radeon.h    |   17 +++++++++++++++++
 3 files changed, 22 insertions(+), 4 deletions(-)
drivers/gpu/drm/radeon/evergreen.c +2 -4
index 0f89ce3..9009dd4 100644
@@ -3120,10 +3120,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
 		u32 efuse_straps_4;
 		u32 efuse_straps_3;
 
-		WREG32(RCU_IND_INDEX, 0x204);
-		efuse_straps_4 = RREG32(RCU_IND_DATA);
-		WREG32(RCU_IND_INDEX, 0x203);
-		efuse_straps_3 = RREG32(RCU_IND_DATA);
+		efuse_straps_4 = RREG32_RCU(0x204);
+		efuse_straps_3 = RREG32_RCU(0x203);
 		tmp = (((efuse_straps_4 & 0xf) << 4) |
 		      ((efuse_straps_3 & 0xf0000000) >> 28));
 	} else {
drivers/gpu/drm/radeon/r600_reg.h +3 -0
index 909219b..58c86cc 100644
@@ -31,6 +31,9 @@
 #define R600_PCIE_PORT_INDEX                0x0038
 #define R600_PCIE_PORT_DATA                 0x003c
 
+#define R600_RCU_INDEX                      0x0100
+#define R600_RCU_DATA                       0x0104
+
 #define R600_MC_VM_FB_LOCATION			0x2180
 #define		R600_MC_FB_BASE_MASK			0x0000FFFF
 #define		R600_MC_FB_BASE_SHIFT			0
drivers/gpu/drm/radeon/radeon.h +17 -0
index 83f62aa..0814aa7 100644
@@ -1851,6 +1851,8 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
 #define WREG32_PCIE_PORT(reg, v) rdev->pciep_wreg(rdev, (reg), (v))
 #define RREG32_SMC(reg) tn_smc_rreg(rdev, (reg))
 #define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v))
+#define RREG32_RCU(reg) r600_rcu_rreg(rdev, (reg))
+#define WREG32_RCU(reg, v) r600_rcu_wreg(rdev, (reg), (v))
 #define WREG32_P(reg, val, mask)				\
 	do {							\
 		uint32_t tmp_ = RREG32(reg);			\
@@ -1907,6 +1909,21 @@ static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 	WREG32(TN_SMC_IND_DATA_0, (v));
 }
 
+static inline u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
+	r = RREG32(R600_RCU_DATA);
+	return r;
+}
+
+static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
+	WREG32(R600_RCU_DATA, (v));
+}
+
 void r100_pll_errata_after_index(struct radeon_device *rdev);
 
 
Signature · 1 line
1.7.7.5
#68 lore raw

PATCH 62/165 drm/radeon/evergreen: add indirect register accessors for CG registers

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/evergreen_reg.h |    3 +++
 drivers/gpu/drm/radeon/radeon.h        |   17 +++++++++++++++++
 2 files changed, 20 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/evergreen_reg.h +3 -0
index 50948ac..76630c6b 100644
@@ -44,6 +44,9 @@
 #define EVERGREEN_AUDIO_PLL1_DIV			0x5b4
 #define EVERGREEN_AUDIO_PLL1_UNK			0x5bc
 
+#define EVERGREEN_CG_IND_ADDR                           0x8f8
+#define EVERGREEN_CG_IND_DATA                           0x8fc
+
 #define EVERGREEN_AUDIO_ENABLE				0x5e78
 #define EVERGREEN_AUDIO_VENDOR_ID			0x5ec0
 
drivers/gpu/drm/radeon/radeon.h +17 -0
index 0814aa7..e73c972 100644
@@ -1853,6 +1853,8 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
 #define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v))
 #define RREG32_RCU(reg) r600_rcu_rreg(rdev, (reg))
 #define WREG32_RCU(reg, v) r600_rcu_wreg(rdev, (reg), (v))
+#define RREG32_CG(reg) eg_cg_rreg(rdev, (reg))
+#define WREG32_CG(reg, v) eg_cg_wreg(rdev, (reg), (v))
 #define WREG32_P(reg, val, mask)				\
 	do {							\
 		uint32_t tmp_ = RREG32(reg);			\
@@ -1924,6 +1926,21 @@ static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 	WREG32(R600_RCU_DATA, (v));
 }
 
+static inline u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
+	r = RREG32(EVERGREEN_CG_IND_DATA);
+	return r;
+}
+
+static inline void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
+	WREG32(EVERGREEN_CG_IND_DATA, (v));
+}
+
 void r100_pll_errata_after_index(struct radeon_device *rdev);
 
 
Signature · 1 line
1.7.7.5
#69 lore raw

PATCH 63/165 drm/radeon: make get_temperature functions a callback

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/radeon.h      |    7 ++-----
 drivers/gpu/drm/radeon/radeon_asic.c |    8 ++++++++
 drivers/gpu/drm/radeon/radeon_asic.h |    5 +++++
 drivers/gpu/drm/radeon/radeon_pm.c   |   26 ++++----------------------
 4 files changed, 19 insertions(+), 27 deletions(-)
drivers/gpu/drm/radeon/radeon.h +2 -5
index e73c972..40053c8 100644
@@ -220,11 +220,6 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 				   struct atom_clock_dividers *dividers);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
 void rs690_pm_info(struct radeon_device *rdev);
-extern int rv6xx_get_temp(struct radeon_device *rdev);
-extern int rv770_get_temp(struct radeon_device *rdev);
-extern int evergreen_get_temp(struct radeon_device *rdev);
-extern int sumo_get_temp(struct radeon_device *rdev);
-extern int si_get_temp(struct radeon_device *rdev);
 extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
 				    unsigned *bankh, unsigned *mtaspect,
 				    unsigned *tile_split);
@@ -1396,6 +1391,7 @@ struct radeon_asic {
 		void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
 		void (*set_clock_gating)(struct radeon_device *rdev, int enable);
 		int (*set_uvd_clocks)(struct radeon_device *rdev, u32 vclk, u32 dclk);
+		int (*get_temperature)(struct radeon_device *rdev);
 	} pm;
 	/* pageflipping */
 	struct {
@@ -2065,6 +2061,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->pm.set_pcie_lanes((rdev), (l))
 #define radeon_set_clock_gating(rdev, e) (rdev)->asic->pm.set_clock_gating((rdev), (e))
 #define radeon_set_uvd_clocks(rdev, v, d) (rdev)->asic->pm.set_uvd_clocks((rdev), (v), (d))
+#define radeon_get_temperature(rdev) (rdev)->asic->pm.get_temperature((rdev))
 #define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->surface.set_reg((rdev), (r), (f), (p), (o), (s)))
 #define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->surface.clear_reg((rdev), (r)))
 #define radeon_bandwidth_update(rdev) (rdev)->asic->display.bandwidth_update((rdev))
drivers/gpu/drm/radeon/radeon_asic.c +8 -0
index d60adb3..f127ea2 100644
@@ -1016,6 +1016,7 @@ static struct radeon_asic r600_asic = {
 		.get_pcie_lanes = &r600_get_pcie_lanes,
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
+		.get_temperature = &rv6xx_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1104,6 +1105,7 @@ static struct radeon_asic rs780_asic = {
 		.get_pcie_lanes = NULL,
 		.set_pcie_lanes = NULL,
 		.set_clock_gating = NULL,
+		.get_temperature = &rv6xx_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1202,6 +1204,7 @@ static struct radeon_asic rv770_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = &radeon_atom_set_clock_gating,
 		.set_uvd_clocks = &rv770_set_uvd_clocks,
+		.get_temperature = &rv770_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1300,6 +1303,7 @@ static struct radeon_asic evergreen_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
+		.get_temperature = &evergreen_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1398,6 +1402,7 @@ static struct radeon_asic sumo_asic = {
 		.set_pcie_lanes = NULL,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &sumo_set_uvd_clocks,
+		.get_temperature = &sumo_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1496,6 +1501,7 @@ static struct radeon_asic btc_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
+		.get_temperature = &evergreen_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1637,6 +1643,7 @@ static struct radeon_asic cayman_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
+		.get_temperature = &evergreen_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1915,6 +1922,7 @@ static struct radeon_asic si_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &si_set_uvd_clocks,
+		.get_temperature = &si_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
drivers/gpu/drm/radeon/radeon_asic.h +5 -0
index 4c2f51f..f1dcb07 100644
@@ -395,6 +395,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
 int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
+int rv6xx_get_temp(struct radeon_device *rdev);
 
 /* uvd */
 int r600_uvd_init(struct radeon_device *rdev);
@@ -428,6 +429,7 @@ int rv770_copy_dma(struct radeon_device *rdev,
 u32 rv770_get_xclk(struct radeon_device *rdev);
 int rv770_uvd_resume(struct radeon_device *rdev);
 int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int rv770_get_temp(struct radeon_device *rdev);
 
 /*
  * evergreen
@@ -482,6 +484,8 @@ int evergreen_copy_dma(struct radeon_device *rdev,
 		       struct radeon_fence **fence);
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
+int evergreen_get_temp(struct radeon_device *rdev);
+int sumo_get_temp(struct radeon_device *rdev);
 
 /*
  * cayman
@@ -552,6 +556,7 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 u32 si_get_xclk(struct radeon_device *rdev);
 uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
 int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int si_get_temp(struct radeon_device *rdev);
 
 /* DCE8 - CIK */
 void dce8_bandwidth_update(struct radeon_device *rdev);
drivers/gpu/drm/radeon/radeon_pm.c +4 -22
index 788c64c..e8c1bea 100644
@@ -434,27 +434,10 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
 	struct radeon_device *rdev = ddev->dev_private;
 	int temp;
 
-	switch (rdev->pm.int_thermal_type) {
-	case THERMAL_TYPE_RV6XX:
-		temp = rv6xx_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_RV770:
-		temp = rv770_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_EVERGREEN:
-	case THERMAL_TYPE_NI:
-		temp = evergreen_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_SUMO:
-		temp = sumo_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_SI:
-		temp = si_get_temp(rdev);
-		break;
-	default:
+	if (rdev->asic->pm.get_temperature)
+		temp = radeon_get_temperature(rdev);
+	else
 		temp = 0;
-		break;
-	}
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", temp);
 }
@@ -492,8 +475,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev)
 	case THERMAL_TYPE_NI:
 	case THERMAL_TYPE_SUMO:
 	case THERMAL_TYPE_SI:
-		/* No support for TN yet */
-		if (rdev->family == CHIP_ARUBA)
+		if (rdev->asic->pm.get_temperature == NULL)
 			return err;
 		rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
 		if (IS_ERR(rdev->pm.int_hwmon_dev)) {
Signature · 1 line
1.7.7.5
#70 lore raw

PATCH 64/165 drm/radeon: add support for thermal sensor on tn

In reply to [email protected]

From: Alex Deucher <[email protected]>

---
 drivers/gpu/drm/radeon/ni.c          |    8 ++++++++
 drivers/gpu/drm/radeon/nid.h         |    3 +++
 drivers/gpu/drm/radeon/radeon_asic.c |    1 +
 drivers/gpu/drm/radeon/radeon_asic.h |    1 +
 4 files changed, 13 insertions(+), 0 deletions(-)
drivers/gpu/drm/radeon/ni.c +8 -0
index 8458330..f889461 100644
@@ -692,6 +692,14 @@ out:
 	return err;
 }
 
+int tn_get_temp(struct radeon_device *rdev)
+{
+	u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff;
+	int actual_temp = (temp / 8) - 49;
+
+	return actual_temp * 1000;
+}
+
 /*
  * Core functions
  */
drivers/gpu/drm/radeon/nid.h +3 -0
index e226faf..7b8da52 100644
@@ -489,6 +489,9 @@
 #       define CACHE_FLUSH_AND_INV_EVENT_TS                     (0x14 << 0)
 #       define CACHE_FLUSH_AND_INV_EVENT                        (0x16 << 0)
 
+/* TN SMU registers */
+#define	TN_CURRENT_GNB_TEMP				0x1F390
+
 /*
  * UVD
  */
drivers/gpu/drm/radeon/radeon_asic.c +1 -0
index f127ea2..5736377 100644
@@ -1783,6 +1783,7 @@ static struct radeon_asic trinity_asic = {
 		.set_pcie_lanes = NULL,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &sumo_set_uvd_clocks,
+		.get_temperature = &tn_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
drivers/gpu/drm/radeon/radeon_asic.h +1 -0
index f1dcb07..8507cae 100644
@@ -486,6 +486,7 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
 int evergreen_get_temp(struct radeon_device *rdev);
 int sumo_get_temp(struct radeon_device *rdev);
+int tn_get_temp(struct radeon_device *rdev);
 
 /*
  * cayman
Signature · 1 line
1.7.7.5
#71 lore raw

PATCH 65/165 drm/radeon/kms: move ucode defines to a separate header

In reply to [email protected]

From: Alex Deucher <[email protected]>

Avoids confusion and duplication.

---
 drivers/gpu/drm/radeon/evergreen.c    |    4 +--
 drivers/gpu/drm/radeon/ni.c           |   13 +--------
 drivers/gpu/drm/radeon/r600.c         |   25 +++++------------
 drivers/gpu/drm/radeon/radeon_ucode.h |   47 +++++++++++++++++++++++++++++++++
 4 files changed, 56 insertions(+), 33 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/radeon_ucode.h
drivers/gpu/drm/radeon/evergreen.c +1 -3
index 9009dd4..6b559cb5 100644
@@ -33,9 +33,7 @@
 #include "avivod.h"
 #include "evergreen_reg.h"
 #include "evergreen_blit_shaders.h"
-
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
+#include "radeon_ucode.h"
 
 static const u32 crtc_offsets[6] =
 {
drivers/gpu/drm/radeon/ni.c +1 -12
index f889461..9284346 100644
@@ -33,6 +33,7 @@
 #include "atom.h"
 #include "ni_reg.h"
 #include "cayman_blit_shaders.h"
+#include "radeon_ucode.h"
 
 extern bool evergreen_is_display_hung(struct radeon_device *rdev);
 extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
@@ -47,18 +48,6 @@ extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
 extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
 
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
-#define EVERGREEN_RLC_UCODE_SIZE 768
-#define BTC_MC_UCODE_SIZE 6024
-
-#define CAYMAN_PFP_UCODE_SIZE 2176
-#define CAYMAN_PM4_UCODE_SIZE 2176
-#define CAYMAN_RLC_UCODE_SIZE 1024
-#define CAYMAN_MC_UCODE_SIZE 6037
-
-#define ARUBA_RLC_UCODE_SIZE 1536
-
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
 MODULE_FIRMWARE("radeon/BARTS_me.bin");
drivers/gpu/drm/radeon/r600.c +7 -18
index 6948eb8..6089261 100644
@@ -38,18 +38,7 @@
 #include "r600d.h"
 #include "atom.h"
 #include "avivod.h"
-
-#define PFP_UCODE_SIZE 576
-#define PM4_UCODE_SIZE 1792
-#define RLC_UCODE_SIZE 768
-#define R700_PFP_UCODE_SIZE 848
-#define R700_PM4_UCODE_SIZE 1360
-#define R700_RLC_UCODE_SIZE 1024
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
-#define EVERGREEN_RLC_UCODE_SIZE 768
-#define CAYMAN_RLC_UCODE_SIZE 1024
-#define ARUBA_RLC_UCODE_SIZE 1536
+#include "radeon_ucode.h"
 
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/R600_pfp.bin");
@@ -2246,9 +2235,9 @@ int r600_init_microcode(struct radeon_device *rdev)
 		me_req_size = R700_PM4_UCODE_SIZE * 4;
 		rlc_req_size = R700_RLC_UCODE_SIZE * 4;
 	} else {
-		pfp_req_size = PFP_UCODE_SIZE * 4;
-		me_req_size = PM4_UCODE_SIZE * 12;
-		rlc_req_size = RLC_UCODE_SIZE * 4;
+		pfp_req_size = R600_PFP_UCODE_SIZE * 4;
+		me_req_size = R600_PM4_UCODE_SIZE * 12;
+		rlc_req_size = R600_RLC_UCODE_SIZE * 4;
 	}
 
 	DRM_INFO("Loading %s Microcode\n", chip_name);
@@ -2331,13 +2320,13 @@ static int r600_cp_load_microcode(struct radeon_device *rdev)
 
 	fw_data = (const __be32 *)rdev->me_fw->data;
 	WREG32(CP_ME_RAM_WADDR, 0);
-	for (i = 0; i < PM4_UCODE_SIZE * 3; i++)
+	for (i = 0; i < R600_PM4_UCODE_SIZE * 3; i++)
 		WREG32(CP_ME_RAM_DATA,
 		       be32_to_cpup(fw_data++));
 
 	fw_data = (const __be32 *)rdev->pfp_fw->data;
 	WREG32(CP_PFP_UCODE_ADDR, 0);
-	for (i = 0; i < PFP_UCODE_SIZE; i++)
+	for (i = 0; i < R600_PFP_UCODE_SIZE; i++)
 		WREG32(CP_PFP_UCODE_DATA,
 		       be32_to_cpup(fw_data++));
 
@@ -3839,7 +3828,7 @@ static int r600_rlc_init(struct radeon_device *rdev)
 			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
 		}
 	} else {
-		for (i = 0; i < RLC_UCODE_SIZE; i++) {
+		for (i = 0; i < R600_RLC_UCODE_SIZE; i++) {
 			WREG32(RLC_UCODE_ADDR, i);
 			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
 		}
drivers/gpu/drm/radeon/radeon_ucode.h new file +47 -0

47 lines not on this page · raw message

Signature · 1 line
1.7.7.5