radeonfb_i2c.c revision 1.4
1/*- 2 * Copyright (c) 2006 Itronix Inc. 3 * All rights reserved. 4 * 5 * Written by Garrett D'Amore for Itronix Inc. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of Itronix Inc. may not be used to endorse 16 * or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * ATI Technologies Inc. ("ATI") has not assisted in the creation of, and 34 * does not endorse, this software. ATI will not be responsible or liable 35 * for any actual or alleged damage or loss caused by or in connection with 36 * the use of or reliance on this software. 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: radeonfb_i2c.c,v 1.4 2022/09/25 17:52:25 thorpej Exp $"); 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/device.h> 45#include <sys/systm.h> 46#include <sys/bus.h> 47 48#include <dev/i2c/i2cvar.h> 49#include <dev/i2c/i2c_bitbang.h> 50#include <dev/i2c/ddcvar.h> 51 52#include <dev/pci/radeonfbreg.h> 53#include <dev/pci/radeonfbvar.h> 54 55/* i2c support */ 56static int radeonfb_i2c_acquire_bus(void *, int); 57static void radeonfb_i2c_release_bus(void *, int); 58static int radeonfb_i2c_send_start(void *, int); 59static int radeonfb_i2c_send_stop(void *, int); 60static int radeonfb_i2c_initiate_xfer(void *, i2c_addr_t, int); 61static int radeonfb_i2c_read_byte(void *, uint8_t *, int); 62static int radeonfb_i2c_write_byte(void *, uint8_t, int); 63 64/* i2c bit-bang glue */ 65static void radeonfb_i2cbb_set_bits(void *, uint32_t); 66static void radeonfb_i2cbb_set_dir(void *, uint32_t); 67static uint32_t radeonfb_i2cbb_read(void *); 68 69/* 70 * I2C bit-bang operations 71 */ 72void 73radeonfb_i2cbb_set_bits(void *cookie, uint32_t bits) 74{ 75 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 76 struct radeonfb_softc *sc = ric->ric_softc; 77 78 PATCH32(sc, ric->ric_register, bits, 79 ~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1)); 80} 81 82void 83radeonfb_i2cbb_set_dir(void *cookie, uint32_t bits) 84{ 85 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 86 struct radeonfb_softc *sc = ric->ric_softc; 87 88 PATCH32(sc, ric->ric_register, bits, ~(RADEON_GPIO_EN_0)); 89} 90 91uint32_t 92radeonfb_i2cbb_read(void *cookie) 93{ 94 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 95 struct radeonfb_softc *sc = ric->ric_softc; 96 97 /* output bit is 0 shifted, input bit is shifted 8 */ 98 return (GET32(sc, ric->ric_register) >> RADEON_GPIO_Y_SHIFT_0); 99} 100 101static const struct i2c_bitbang_ops radeonfb_i2cbb_ops = { 102 radeonfb_i2cbb_set_bits, 103 radeonfb_i2cbb_set_dir, 104 radeonfb_i2cbb_read, 105 { 106 RADEON_GPIO_A_0, /* SDA */ 107 RADEON_GPIO_A_1, /* SCL */ 108 RADEON_GPIO_EN_0, /* SDA output */ 109 0, /* SDA input */ 110 } 111}; 112 113/* 114 * I2C support 115 */ 116int 117radeonfb_i2c_acquire_bus(void *cookie, int flags) 118{ 119 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 120 struct radeonfb_softc *sc = ric->ric_softc; 121 int i; 122 123 /* 124 * Some hardware seems to have hardware/software combined access 125 * to the DVI I2C. We want to use software. 126 */ 127 if (ric->ric_register == RADEON_GPIO_DVI_DDC) { 128 129 /* ask for software access to I2C bus */ 130 SET32(sc, ric->ric_register, RADEON_GPIO_SW_USE); 131 132 /* 133 * wait for the chip to give up access. we don't make 134 * this a hard timeout, because some hardware might 135 * not implement this negotiation protocol 136 */ 137 for (i = RADEON_TIMEOUT; i; i--) { 138 if (GET32(sc, ric->ric_register) & RADEON_GPIO_SW_USE) 139 break; 140 } 141 } 142 143 /* enable the I2C clock */ 144 SET32(sc, ric->ric_register, RADEON_GPIO_EN_1); 145 146 return 0; 147} 148 149void 150radeonfb_i2c_release_bus(void *cookie, int flags) 151{ 152 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 153 struct radeonfb_softc *sc = ric->ric_softc; 154 155 if (ric->ric_register == RADEON_GPIO_DVI_DDC) { 156 /* we no longer "want" I2C, and we're "done" with it */ 157 CLR32(sc, ric->ric_register, RADEON_GPIO_SW_USE); 158 SET32(sc, ric->ric_register, RADEON_GPIO_SW_DONE); 159 } 160} 161 162int 163radeonfb_i2c_send_start(void *cookie, int flags) 164{ 165 166 return i2c_bitbang_send_start(cookie, flags, &radeonfb_i2cbb_ops); 167} 168 169int 170radeonfb_i2c_send_stop(void *cookie, int flags) 171{ 172 173 return i2c_bitbang_send_stop(cookie, flags, &radeonfb_i2cbb_ops); 174} 175 176int 177radeonfb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 178{ 179 180 return i2c_bitbang_initiate_xfer(cookie, addr, flags, 181 &radeonfb_i2cbb_ops); 182} 183 184int 185radeonfb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 186{ 187 188 return i2c_bitbang_read_byte(cookie, valp, flags, &radeonfb_i2cbb_ops); 189} 190 191int 192radeonfb_i2c_write_byte(void *cookie, uint8_t val, int flags) 193{ 194 195 return i2c_bitbang_write_byte(cookie, val, flags, &radeonfb_i2cbb_ops); 196} 197 198void 199radeonfb_i2c_init(struct radeonfb_softc *sc) 200{ 201 int i; 202 203 for (i = 0; i < 4; i++) { 204 struct i2c_controller *icc = &sc->sc_i2c[i].ric_controller; 205 206 sc->sc_i2c[i].ric_softc = sc; 207 iic_tag_init(icc); 208 icc->ic_cookie = &sc->sc_i2c[i]; 209 icc->ic_acquire_bus = radeonfb_i2c_acquire_bus; 210 icc->ic_release_bus = radeonfb_i2c_release_bus; 211 icc->ic_send_start = radeonfb_i2c_send_start; 212 icc->ic_send_stop = radeonfb_i2c_send_stop; 213 icc->ic_initiate_xfer = radeonfb_i2c_initiate_xfer; 214 icc->ic_read_byte = radeonfb_i2c_read_byte; 215 icc->ic_write_byte = radeonfb_i2c_write_byte; 216 } 217 218 /* index == ddctype (RADEON_DDC_XX) - 1 */ 219 sc->sc_i2c[0].ric_register = RADEON_GPIO_MONID; 220 sc->sc_i2c[1].ric_register = RADEON_GPIO_DVI_DDC; 221 sc->sc_i2c[2].ric_register = RADEON_GPIO_VGA_DDC; 222 sc->sc_i2c[3].ric_register = RADEON_GPIO_CRT2_DDC; 223} 224 225int 226radeonfb_i2c_read_edid(struct radeonfb_softc *sc, int ddctype, uint8_t *data) 227{ 228 229 if ((ddctype < 1) || (ddctype > 4)) 230 return EINVAL; 231 232 ddctype--; 233 return (ddc_read_edid(&sc->sc_i2c[ddctype].ric_controller, data, 128)); 234} 235