diff options
author | Slava Grigorev <slava.grigorev@amd.com> | 2014-12-01 13:49:39 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2015-01-22 10:39:00 -0500 |
commit | 1a626b68fbfa4782477caad56f3b8b652a9dbf7e (patch) | |
tree | 6b56038c9f72076fe96f96097b7d318e1f8ff58b | |
parent | bfc1f97d8ac5d3dc6f7ded64ba9adbac371e912c (diff) |
radeon/audio: defined initial audio interface that gets initialized via detect() call
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Slava Grigorev <slava.grigorev@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/radeon/dce6_afmt.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_audio.c | 96 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_audio.h | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 1 |
6 files changed, 136 insertions, 7 deletions
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index a97fb22ed06a..821f53ce3f65 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c | |||
@@ -23,9 +23,10 @@ | |||
23 | #include <linux/hdmi.h> | 23 | #include <linux/hdmi.h> |
24 | #include <drm/drmP.h> | 24 | #include <drm/drmP.h> |
25 | #include "radeon.h" | 25 | #include "radeon.h" |
26 | #include "radeon_audio.h" | ||
26 | #include "sid.h" | 27 | #include "sid.h" |
27 | 28 | ||
28 | static u32 dce6_endpoint_rreg(struct radeon_device *rdev, | 29 | u32 dce6_endpoint_rreg(struct radeon_device *rdev, |
29 | u32 block_offset, u32 reg) | 30 | u32 block_offset, u32 reg) |
30 | { | 31 | { |
31 | unsigned long flags; | 32 | unsigned long flags; |
@@ -39,7 +40,7 @@ static u32 dce6_endpoint_rreg(struct radeon_device *rdev, | |||
39 | return r; | 40 | return r; |
40 | } | 41 | } |
41 | 42 | ||
42 | static void dce6_endpoint_wreg(struct radeon_device *rdev, | 43 | void dce6_endpoint_wreg(struct radeon_device *rdev, |
43 | u32 block_offset, u32 reg, u32 v) | 44 | u32 block_offset, u32 reg, u32 v) |
44 | { | 45 | { |
45 | unsigned long flags; | 46 | unsigned long flags; |
@@ -54,10 +55,6 @@ static void dce6_endpoint_wreg(struct radeon_device *rdev, | |||
54 | spin_unlock_irqrestore(&rdev->end_idx_lock, flags); | 55 | spin_unlock_irqrestore(&rdev->end_idx_lock, flags); |
55 | } | 56 | } |
56 | 57 | ||
57 | #define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg)) | ||
58 | #define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v)) | ||
59 | |||
60 | |||
61 | static void dce6_afmt_get_connected_pins(struct radeon_device *rdev) | 58 | static void dce6_afmt_get_connected_pins(struct radeon_device *rdev) |
62 | { | 59 | { |
63 | int i; | 60 | int i; |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4195e6cc4e52..d15e3c0c09f5 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -1757,6 +1757,9 @@ struct r600_audio { | |||
1757 | bool enabled; | 1757 | bool enabled; |
1758 | struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS]; | 1758 | struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS]; |
1759 | int num_pins; | 1759 | int num_pins; |
1760 | struct radeon_audio_funcs *hdmi_funcs; | ||
1761 | struct radeon_audio_funcs *dp_funcs; | ||
1762 | struct radeon_audio_basic_funcs *funcs; | ||
1760 | }; | 1763 | }; |
1761 | 1764 | ||
1762 | /* | 1765 | /* |
diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index cc835e2e0de5..36174b6ca681 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c | |||
@@ -23,12 +23,18 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <drm/drmP.h> | 25 | #include <drm/drmP.h> |
26 | #include <drm/drm_crtc.h> | ||
26 | #include "radeon.h" | 27 | #include "radeon.h" |
28 | #include "atom.h" | ||
29 | #include "radeon_audio.h" | ||
27 | 30 | ||
28 | void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, | 31 | void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, |
29 | u8 enable_mask); | 32 | u8 enable_mask); |
30 | void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, | 33 | void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, |
31 | u8 enable_mask); | 34 | u8 enable_mask); |
35 | u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg); | ||
36 | void dce6_endpoint_wreg(struct radeon_device *rdev, | ||
37 | u32 offset, u32 reg, u32 v); | ||
32 | 38 | ||
33 | static const u32 pin_offsets[7] = | 39 | static const u32 pin_offsets[7] = |
34 | { | 40 | { |
@@ -41,6 +47,43 @@ static const u32 pin_offsets[7] = | |||
41 | (0x5e90 - 0x5e00), | 47 | (0x5e90 - 0x5e00), |
42 | }; | 48 | }; |
43 | 49 | ||
50 | static u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg) | ||
51 | { | ||
52 | return RREG32(reg); | ||
53 | } | ||
54 | |||
55 | static void radeon_audio_wreg(struct radeon_device *rdev, u32 offset, | ||
56 | u32 reg, u32 v) | ||
57 | { | ||
58 | WREG32(reg, v); | ||
59 | } | ||
60 | |||
61 | static struct radeon_audio_basic_funcs dce32_funcs = { | ||
62 | .endpoint_rreg = radeon_audio_rreg, | ||
63 | .endpoint_wreg = radeon_audio_wreg, | ||
64 | }; | ||
65 | |||
66 | static struct radeon_audio_basic_funcs dce4_funcs = { | ||
67 | .endpoint_rreg = radeon_audio_rreg, | ||
68 | .endpoint_wreg = radeon_audio_wreg, | ||
69 | }; | ||
70 | |||
71 | static struct radeon_audio_basic_funcs dce6_funcs = { | ||
72 | .endpoint_rreg = dce6_endpoint_rreg, | ||
73 | .endpoint_wreg = dce6_endpoint_wreg, | ||
74 | }; | ||
75 | |||
76 | static void radeon_audio_interface_init(struct radeon_device *rdev) | ||
77 | { | ||
78 | if (ASIC_IS_DCE6(rdev)) { | ||
79 | rdev->audio.funcs = &dce6_funcs; | ||
80 | } else if (ASIC_IS_DCE4(rdev)) { | ||
81 | rdev->audio.funcs = &dce4_funcs; | ||
82 | } else { | ||
83 | rdev->audio.funcs = &dce32_funcs; | ||
84 | } | ||
85 | } | ||
86 | |||
44 | static int radeon_audio_chipset_supported(struct radeon_device *rdev) | 87 | static int radeon_audio_chipset_supported(struct radeon_device *rdev) |
45 | { | 88 | { |
46 | return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); | 89 | return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); |
@@ -79,12 +122,63 @@ int radeon_audio_init(struct radeon_device *rdev) | |||
79 | rdev->audio.pin[i].connected = false; | 122 | rdev->audio.pin[i].connected = false; |
80 | rdev->audio.pin[i].offset = pin_offsets[i]; | 123 | rdev->audio.pin[i].offset = pin_offsets[i]; |
81 | rdev->audio.pin[i].id = i; | 124 | rdev->audio.pin[i].id = i; |
82 | /* disable audio. it will be set up later */ | 125 | } |
126 | |||
127 | radeon_audio_interface_init(rdev); | ||
128 | |||
129 | /* disable audio. it will be set up later */ | ||
130 | for (i = 0; i < rdev->audio.num_pins; i++) | ||
83 | if (ASIC_IS_DCE6(rdev)) | 131 | if (ASIC_IS_DCE6(rdev)) |
84 | dce6_audio_enable(rdev, &rdev->audio.pin[i], false); | 132 | dce6_audio_enable(rdev, &rdev->audio.pin[i], false); |
85 | else | 133 | else |
86 | r600_audio_enable(rdev, &rdev->audio.pin[i], false); | 134 | r600_audio_enable(rdev, &rdev->audio.pin[i], false); |
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | void radeon_audio_detect(struct drm_connector *connector, | ||
140 | enum drm_connector_status status) | ||
141 | { | ||
142 | if (!connector || !connector->encoder) | ||
143 | return; | ||
144 | |||
145 | if (status == connector_status_connected) { | ||
146 | int sink_type; | ||
147 | struct radeon_device *rdev = connector->encoder->dev->dev_private; | ||
148 | struct radeon_connector *radeon_connector; | ||
149 | struct radeon_encoder *radeon_encoder = | ||
150 | to_radeon_encoder(connector->encoder); | ||
151 | |||
152 | if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) { | ||
153 | radeon_encoder->audio = 0; | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | radeon_connector = to_radeon_connector(connector); | ||
158 | sink_type = radeon_dp_getsinktype(radeon_connector); | ||
159 | |||
160 | if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort && | ||
161 | sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) | ||
162 | radeon_encoder->audio = rdev->audio.dp_funcs; | ||
163 | else | ||
164 | radeon_encoder->audio = rdev->audio.hdmi_funcs; | ||
165 | /* TODO: set up the sads, etc. and set the audio enable_mask */ | ||
166 | } else { | ||
167 | /* TODO: reset the audio enable_mask */ | ||
87 | } | 168 | } |
169 | } | ||
170 | |||
171 | u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg) | ||
172 | { | ||
173 | if (rdev->audio.funcs->endpoint_rreg) | ||
174 | return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg); | ||
88 | 175 | ||
89 | return 0; | 176 | return 0; |
90 | } | 177 | } |
178 | |||
179 | void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset, | ||
180 | u32 reg, u32 v) | ||
181 | { | ||
182 | if (rdev->audio.funcs->endpoint_wreg) | ||
183 | rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v); | ||
184 | } | ||
diff --git a/drivers/gpu/drm/radeon/radeon_audio.h b/drivers/gpu/drm/radeon/radeon_audio.h index 8455fbdf97e4..e4b0b6437df7 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.h +++ b/drivers/gpu/drm/radeon/radeon_audio.h | |||
@@ -21,9 +21,35 @@ | |||
21 | * | 21 | * |
22 | * Authors: Slava Grigorev <slava.grigorev@amd.com> | 22 | * Authors: Slava Grigorev <slava.grigorev@amd.com> |
23 | */ | 23 | */ |
24 | |||
24 | #ifndef __RADEON_AUDIO_H__ | 25 | #ifndef __RADEON_AUDIO_H__ |
25 | #define __RADEON_AUDIO_H__ | 26 | #define __RADEON_AUDIO_H__ |
26 | 27 | ||
28 | #include <linux/types.h> | ||
29 | |||
30 | #define RREG32_ENDPOINT(block, reg) \ | ||
31 | radeon_audio_endpoint_rreg(rdev, (block), (reg)) | ||
32 | #define WREG32_ENDPOINT(block, reg, v) \ | ||
33 | radeon_audio_endpoint_wreg(rdev, (block), (reg), (v)) | ||
34 | |||
35 | struct radeon_audio_basic_funcs | ||
36 | { | ||
37 | u32 (*endpoint_rreg)(struct radeon_device *rdev, u32 offset, u32 reg); | ||
38 | void (*endpoint_wreg)(struct radeon_device *rdev, | ||
39 | u32 offset, u32 reg, u32 v); | ||
40 | }; | ||
41 | |||
42 | struct radeon_audio_funcs | ||
43 | { | ||
44 | /* TODO: add mode depended audio interface */ | ||
45 | }; | ||
46 | |||
27 | int radeon_audio_init(struct radeon_device *rdev); | 47 | int radeon_audio_init(struct radeon_device *rdev); |
48 | void radeon_audio_detect(struct drm_connector *connector, | ||
49 | enum drm_connector_status status); | ||
50 | u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, | ||
51 | u32 offset, u32 reg); | ||
52 | void radeon_audio_endpoint_wreg(struct radeon_device *rdev, | ||
53 | u32 offset, u32 reg, u32 v); | ||
28 | 54 | ||
29 | #endif | 55 | #endif |
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 26baa9c05f6c..27def67cb6be 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <drm/drm_fb_helper.h> | 29 | #include <drm/drm_fb_helper.h> |
30 | #include <drm/radeon_drm.h> | 30 | #include <drm/radeon_drm.h> |
31 | #include "radeon.h" | 31 | #include "radeon.h" |
32 | #include "radeon_audio.h" | ||
32 | #include "atom.h" | 33 | #include "atom.h" |
33 | 34 | ||
34 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
@@ -1332,6 +1333,9 @@ out: | |||
1332 | /* updated in get modes as well since we need to know if it's analog or digital */ | 1333 | /* updated in get modes as well since we need to know if it's analog or digital */ |
1333 | radeon_connector_update_scratch_regs(connector, ret); | 1334 | radeon_connector_update_scratch_regs(connector, ret); |
1334 | 1335 | ||
1336 | if (radeon_audio != 0) | ||
1337 | radeon_audio_detect(connector, ret); | ||
1338 | |||
1335 | exit: | 1339 | exit: |
1336 | pm_runtime_mark_last_busy(connector->dev->dev); | 1340 | pm_runtime_mark_last_busy(connector->dev->dev); |
1337 | pm_runtime_put_autosuspend(connector->dev->dev); | 1341 | pm_runtime_put_autosuspend(connector->dev->dev); |
@@ -1654,6 +1658,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) | |||
1654 | } | 1658 | } |
1655 | 1659 | ||
1656 | radeon_connector_update_scratch_regs(connector, ret); | 1660 | radeon_connector_update_scratch_regs(connector, ret); |
1661 | |||
1662 | if (radeon_audio != 0) | ||
1663 | radeon_audio_detect(connector, ret); | ||
1664 | |||
1657 | out: | 1665 | out: |
1658 | pm_runtime_mark_last_busy(connector->dev->dev); | 1666 | pm_runtime_mark_last_busy(connector->dev->dev); |
1659 | pm_runtime_put_autosuspend(connector->dev->dev); | 1667 | pm_runtime_put_autosuspend(connector->dev->dev); |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5135d02b7c1e..920a8be8abad 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -449,6 +449,7 @@ struct radeon_encoder { | |||
449 | int audio_polling_active; | 449 | int audio_polling_active; |
450 | bool is_ext_encoder; | 450 | bool is_ext_encoder; |
451 | u16 caps; | 451 | u16 caps; |
452 | struct radeon_audio_funcs *audio; | ||
452 | }; | 453 | }; |
453 | 454 | ||
454 | struct radeon_connector_atom_dig { | 455 | struct radeon_connector_atom_dig { |