diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_i2c.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_i2c.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c new file mode 100644 index 000000000000..71465ed2688a --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_i2c.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * Copyright 2007-8 Advanced Micro Devices, Inc. | ||
3 | * Copyright 2008 Red Hat Inc. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be included in | ||
13 | * all copies or substantial portions of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
21 | * OTHER DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: Dave Airlie | ||
24 | * Alex Deucher | ||
25 | */ | ||
26 | #include "drmP.h" | ||
27 | #include "radeon_drm.h" | ||
28 | #include "radeon.h" | ||
29 | |||
30 | /** | ||
31 | * radeon_ddc_probe | ||
32 | * | ||
33 | */ | ||
34 | bool radeon_ddc_probe(struct radeon_connector *radeon_connector) | ||
35 | { | ||
36 | u8 out_buf[] = { 0x0, 0x0}; | ||
37 | u8 buf[2]; | ||
38 | int ret; | ||
39 | struct i2c_msg msgs[] = { | ||
40 | { | ||
41 | .addr = 0x50, | ||
42 | .flags = 0, | ||
43 | .len = 1, | ||
44 | .buf = out_buf, | ||
45 | }, | ||
46 | { | ||
47 | .addr = 0x50, | ||
48 | .flags = I2C_M_RD, | ||
49 | .len = 1, | ||
50 | .buf = buf, | ||
51 | } | ||
52 | }; | ||
53 | |||
54 | ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); | ||
55 | if (ret == 2) | ||
56 | return true; | ||
57 | |||
58 | return false; | ||
59 | } | ||
60 | |||
61 | |||
62 | void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) | ||
63 | { | ||
64 | struct radeon_device *rdev = radeon_connector->base.dev->dev_private; | ||
65 | uint32_t temp; | ||
66 | struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; | ||
67 | |||
68 | /* RV410 appears to have a bug where the hw i2c in reset | ||
69 | * holds the i2c port in a bad state - switch hw i2c away before | ||
70 | * doing DDC - do this for all r200s/r300s/r400s for safety sake | ||
71 | */ | ||
72 | if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) { | ||
73 | if (rec->a_clk_reg == RADEON_GPIO_MONID) { | ||
74 | WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | | ||
75 | R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1))); | ||
76 | } else { | ||
77 | WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | | ||
78 | R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3))); | ||
79 | } | ||
80 | } | ||
81 | if (lock_state) { | ||
82 | temp = RREG32(rec->a_clk_reg); | ||
83 | temp &= ~(rec->a_clk_mask); | ||
84 | WREG32(rec->a_clk_reg, temp); | ||
85 | |||
86 | temp = RREG32(rec->a_data_reg); | ||
87 | temp &= ~(rec->a_data_mask); | ||
88 | WREG32(rec->a_data_reg, temp); | ||
89 | } | ||
90 | |||
91 | temp = RREG32(rec->mask_clk_reg); | ||
92 | if (lock_state) | ||
93 | temp |= rec->mask_clk_mask; | ||
94 | else | ||
95 | temp &= ~rec->mask_clk_mask; | ||
96 | WREG32(rec->mask_clk_reg, temp); | ||
97 | temp = RREG32(rec->mask_clk_reg); | ||
98 | |||
99 | temp = RREG32(rec->mask_data_reg); | ||
100 | if (lock_state) | ||
101 | temp |= rec->mask_data_mask; | ||
102 | else | ||
103 | temp &= ~rec->mask_data_mask; | ||
104 | WREG32(rec->mask_data_reg, temp); | ||
105 | temp = RREG32(rec->mask_data_reg); | ||
106 | } | ||
107 | |||
108 | static int get_clock(void *i2c_priv) | ||
109 | { | ||
110 | struct radeon_i2c_chan *i2c = i2c_priv; | ||
111 | struct radeon_device *rdev = i2c->dev->dev_private; | ||
112 | struct radeon_i2c_bus_rec *rec = &i2c->rec; | ||
113 | uint32_t val; | ||
114 | |||
115 | val = RREG32(rec->get_clk_reg); | ||
116 | val &= rec->get_clk_mask; | ||
117 | |||
118 | return (val != 0); | ||
119 | } | ||
120 | |||
121 | |||
122 | static int get_data(void *i2c_priv) | ||
123 | { | ||
124 | struct radeon_i2c_chan *i2c = i2c_priv; | ||
125 | struct radeon_device *rdev = i2c->dev->dev_private; | ||
126 | struct radeon_i2c_bus_rec *rec = &i2c->rec; | ||
127 | uint32_t val; | ||
128 | |||
129 | val = RREG32(rec->get_data_reg); | ||
130 | val &= rec->get_data_mask; | ||
131 | return (val != 0); | ||
132 | } | ||
133 | |||
134 | static void set_clock(void *i2c_priv, int clock) | ||
135 | { | ||
136 | struct radeon_i2c_chan *i2c = i2c_priv; | ||
137 | struct radeon_device *rdev = i2c->dev->dev_private; | ||
138 | struct radeon_i2c_bus_rec *rec = &i2c->rec; | ||
139 | uint32_t val; | ||
140 | |||
141 | val = RREG32(rec->put_clk_reg) & (uint32_t)~(rec->put_clk_mask); | ||
142 | val |= clock ? 0 : rec->put_clk_mask; | ||
143 | WREG32(rec->put_clk_reg, val); | ||
144 | } | ||
145 | |||
146 | static void set_data(void *i2c_priv, int data) | ||
147 | { | ||
148 | struct radeon_i2c_chan *i2c = i2c_priv; | ||
149 | struct radeon_device *rdev = i2c->dev->dev_private; | ||
150 | struct radeon_i2c_bus_rec *rec = &i2c->rec; | ||
151 | uint32_t val; | ||
152 | |||
153 | val = RREG32(rec->put_data_reg) & (uint32_t)~(rec->put_data_mask); | ||
154 | val |= data ? 0 : rec->put_data_mask; | ||
155 | WREG32(rec->put_data_reg, val); | ||
156 | } | ||
157 | |||
158 | struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, | ||
159 | struct radeon_i2c_bus_rec *rec, | ||
160 | const char *name) | ||
161 | { | ||
162 | struct radeon_i2c_chan *i2c; | ||
163 | int ret; | ||
164 | |||
165 | i2c = drm_calloc(1, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); | ||
166 | if (i2c == NULL) | ||
167 | return NULL; | ||
168 | |||
169 | i2c->adapter.owner = THIS_MODULE; | ||
170 | i2c->adapter.algo_data = &i2c->algo; | ||
171 | i2c->dev = dev; | ||
172 | i2c->algo.setsda = set_data; | ||
173 | i2c->algo.setscl = set_clock; | ||
174 | i2c->algo.getsda = get_data; | ||
175 | i2c->algo.getscl = get_clock; | ||
176 | i2c->algo.udelay = 20; | ||
177 | /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always | ||
178 | * make this, 2 jiffies is a lot more reliable */ | ||
179 | i2c->algo.timeout = 2; | ||
180 | i2c->algo.data = i2c; | ||
181 | i2c->rec = *rec; | ||
182 | i2c_set_adapdata(&i2c->adapter, i2c); | ||
183 | |||
184 | ret = i2c_bit_add_bus(&i2c->adapter); | ||
185 | if (ret) { | ||
186 | DRM_INFO("Failed to register i2c %s\n", name); | ||
187 | goto out_free; | ||
188 | } | ||
189 | |||
190 | return i2c; | ||
191 | out_free: | ||
192 | drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); | ||
193 | return NULL; | ||
194 | |||
195 | } | ||
196 | |||
197 | void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) | ||
198 | { | ||
199 | if (!i2c) | ||
200 | return; | ||
201 | |||
202 | i2c_del_adapter(&i2c->adapter); | ||
203 | drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); | ||
204 | } | ||
205 | |||
206 | struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) | ||
207 | { | ||
208 | return NULL; | ||
209 | } | ||