drm/radeon: Import the Radeon KMS driver from FreeBSD
[dragonfly.git] / sys / dev / drm / radeon / atombios_i2c.c
1 /*
2  * Copyright 2011 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Alex Deucher
23  *
24  * $FreeBSD: head/sys/dev/drm2/radeon/atombios_i2c.c 254885 2013-08-25 19:37:15Z dumbbell $
25  */
26
27 #include <drm/drmP.h>
28 #include <uapi_drm/radeon_drm.h>
29 #include <bus/iicbus/iic.h>
30 #include <bus/iicbus/iiconf.h>
31 #include <bus/iicbus/iicbus.h>
32 #include "radeon.h"
33 #include "atom.h"
34 #include "iicbus_if.h"
35 #include "iicbb_if.h"
36
37 #define TARGET_HW_I2C_CLOCK 50
38
39 /* these are a limitation of ProcessI2cChannelTransaction not the hw */
40 #define ATOM_MAX_HW_I2C_WRITE 2
41 #define ATOM_MAX_HW_I2C_READ  255
42
43 static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
44                                  u8 slave_addr, u8 flags,
45                                  u8 *buf, u8 num)
46 {
47         struct drm_device *dev = chan->dev;
48         struct radeon_device *rdev = dev->dev_private;
49         PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION args;
50         int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);
51         unsigned char *base;
52         u16 out;
53
54         memset(&args, 0, sizeof(args));
55
56         base = (unsigned char *)rdev->mode_info.atom_context->scratch;
57
58         if (flags & HW_I2C_WRITE) {
59                 if (num > ATOM_MAX_HW_I2C_WRITE) {
60                         DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 2)\n", num);
61                         return EINVAL;
62                 }
63                 memcpy(&out, buf, num);
64                 args.lpI2CDataOut = cpu_to_le16(out);
65         }
66
67         args.ucI2CSpeed = TARGET_HW_I2C_CLOCK;
68         args.ucRegIndex = 0;
69         args.ucTransBytes = num;
70         args.ucSlaveAddr = slave_addr << 1;
71         args.ucLineNumber = chan->rec.i2c_id;
72
73         atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
74
75         /* error */
76         if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
77                 DRM_DEBUG_KMS("hw_i2c error\n");
78                 return EIO;
79         }
80
81         if (!(flags & HW_I2C_WRITE))
82                 memcpy(buf, base, num);
83
84         return 0;
85 }
86
87 static int
88 radeon_atom_hw_i2c_xfer(device_t dev, struct iic_msg *msgs, u_int num)
89 {
90         struct radeon_i2c_chan *i2c = device_get_softc(dev);
91         struct iic_msg *p;
92         int i, remaining, current_count, buffer_offset, max_bytes, ret;
93         u8 buf = 0, flags;
94
95         /* check for bus probe */
96         p = &msgs[0];
97         if ((num == 1) && (p->len == 0)) {
98                 ret = radeon_process_i2c_ch(i2c,
99                                             p->slave, HW_I2C_WRITE,
100                                             &buf, 1);
101                 if (ret)
102                         return ret;
103                 else
104                         return (0);
105         }
106
107         for (i = 0; i < num; i++) {
108                 p = &msgs[i];
109                 remaining = p->len;
110                 buffer_offset = 0;
111                 /* max_bytes are a limitation of ProcessI2cChannelTransaction not the hw */
112                 if (p->flags & IIC_M_RD) {
113                         max_bytes = ATOM_MAX_HW_I2C_READ;
114                         flags = HW_I2C_READ;
115                 } else {
116                         max_bytes = ATOM_MAX_HW_I2C_WRITE;
117                         flags = HW_I2C_WRITE;
118                 }
119                 while (remaining) {
120                         if (remaining > max_bytes)
121                                 current_count = max_bytes;
122                         else
123                                 current_count = remaining;
124                         ret = radeon_process_i2c_ch(i2c,
125                                                     p->slave, flags,
126                                                     &p->buf[buffer_offset], current_count);
127                         if (ret)
128                                 return ret;
129                         remaining -= current_count;
130                         buffer_offset += current_count;
131                 }
132         }
133
134         return (0);
135 }
136
137 static int
138 radeon_atom_hw_i2c_probe(device_t dev)
139 {
140
141         return (BUS_PROBE_SPECIFIC);
142 }
143
144 static int
145 radeon_atom_hw_i2c_attach(device_t dev)
146 {
147         struct radeon_i2c_chan *i2c;
148         device_t iic_dev;
149
150         i2c = device_get_softc(dev);
151         device_set_desc(dev, i2c->name);
152
153         /* add generic bit-banging code */
154         iic_dev = device_add_child(dev, "iicbus", -1);
155         if (iic_dev == NULL)
156                 return (ENXIO);
157         device_quiet(iic_dev);
158
159         /* attach and probe added child */
160         bus_generic_attach(dev);
161
162         return (0);
163 }
164
165 static int
166 radeon_atom_hw_i2c_detach(device_t dev)
167 {
168         /* detach bit-banding code. */
169         bus_generic_detach(dev);
170
171         /* delete bit-banding code. */
172         device_delete_children(dev);
173         return (0);
174 }
175
176 static int
177 radeon_atom_hw_i2c_reset(device_t dev, u_char speed,
178     u_char addr, u_char *oldaddr)
179 {
180
181         return (0);
182 }
183
184 static device_method_t radeon_atom_hw_i2c_methods[] = {
185         DEVMETHOD(device_probe,         radeon_atom_hw_i2c_probe),
186         DEVMETHOD(device_attach,        radeon_atom_hw_i2c_attach),
187         DEVMETHOD(device_detach,        radeon_atom_hw_i2c_detach),
188         DEVMETHOD(iicbus_reset,         radeon_atom_hw_i2c_reset),
189         DEVMETHOD(iicbus_transfer,      radeon_atom_hw_i2c_xfer),
190         DEVMETHOD_END
191 };
192
193 static driver_t radeon_atom_hw_i2c_driver = {
194         "radeon_atom_hw_i2c",
195         radeon_atom_hw_i2c_methods,
196         0
197 };
198
199 static devclass_t radeon_atom_hw_i2c_devclass;
200 DRIVER_MODULE_ORDERED(radeon_atom_hw_i2c, drm, radeon_atom_hw_i2c_driver,
201     radeon_atom_hw_i2c_devclass, 0, 0, SI_ORDER_ANY);