aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_i2c.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-06-05 08:42:42 -0400
committerDave Airlie <airlied@redhat.com>2009-06-14 22:01:53 -0400
commit771fe6b912fca54f03e8a72eb63058b582775362 (patch)
tree58aa5469ba8058c2b564d50807395ad6cd7bd7e4 /drivers/gpu/drm/radeon/radeon_i2c.c
parentba4e7d973dd09b66912ac4c0856add8b0703a997 (diff)
drm/radeon: introduce kernel modesetting for radeon hardware
Add kernel modesetting support to radeon driver, use the ttm memory manager to manage memory and DRM/GEM to provide userspace API. In order to avoid backward compatibility issue and to allow clean design and code the radeon kernel modesetting use different code path than old radeon/drm driver. When kernel modesetting is enabled the IOCTL of radeon/drm driver are considered as invalid and an error message is printed in the log and they return failure. KMS enabled userspace will use new API to talk with the radeon/drm driver. The new API provide functions to create/destroy/share/mmap buffer object which are then managed by the kernel memory manager (here TTM). In order to submit command to the GPU the userspace provide a buffer holding the command stream, along this buffer userspace have to provide a list of buffer object used by the command stream. The kernel radeon driver will then place buffer in GPU accessible memory and will update command stream to reflect the position of the different buffers. The kernel will also perform security check on command stream provided by the user, we want to catch and forbid any illegal use of the GPU such as DMA into random system memory or into memory not owned by the process supplying the command stream. This part of the code is still incomplete and this why we propose that patch as a staging driver addition, future security might forbid current experimental userspace to run. This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX (radeon up to X1950). Works is underway to provide support for R6XX, R7XX and newer hardware (radeon from HD2XXX to HD4XXX). Authors: Jerome Glisse <jglisse@redhat.com> Dave Airlie <airlied@redhat.com> Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_i2c.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_i2c.c209
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 */
34bool 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
62void 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
108static 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
122static 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
134static 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
146static 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
158struct 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;
191out_free:
192 drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER);
193 return NULL;
194
195}
196
197void 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
206struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
207{
208 return NULL;
209}