Home | History | Annotate | Line # | Download | only in dev
      1  1.2  jmcneill /* $NetBSD: avenc.c,v 1.2 2024/10/13 16:21:37 jmcneill Exp $ */
      2  1.1  jmcneill 
      3  1.1  jmcneill /*-
      4  1.1  jmcneill  * Copyright (c) 2024 Jared McNeill <jmcneill (at) invisible.ca>
      5  1.1  jmcneill  * All rights reserved.
      6  1.1  jmcneill  *
      7  1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      8  1.1  jmcneill  * modification, are permitted provided that the following conditions
      9  1.1  jmcneill  * are met:
     10  1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     11  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     12  1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     15  1.1  jmcneill  *
     16  1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.1  jmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.1  jmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.1  jmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.1  jmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1  jmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1  jmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1  jmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1  jmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1  jmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1  jmcneill  * POSSIBILITY OF SUCH DAMAGE.
     27  1.1  jmcneill  */
     28  1.1  jmcneill 
     29  1.1  jmcneill #include <sys/cdefs.h>
     30  1.2  jmcneill __KERNEL_RCSID(0, "$NetBSD: avenc.c,v 1.2 2024/10/13 16:21:37 jmcneill Exp $");
     31  1.1  jmcneill 
     32  1.1  jmcneill #include <sys/param.h>
     33  1.1  jmcneill #include <sys/systm.h>
     34  1.1  jmcneill #include <sys/kernel.h>
     35  1.1  jmcneill #include <sys/device.h>
     36  1.1  jmcneill #include <sys/conf.h>
     37  1.1  jmcneill #include <sys/bus.h>
     38  1.1  jmcneill #include <sys/kmem.h>
     39  1.2  jmcneill #include <machine/wii.h>
     40  1.1  jmcneill 
     41  1.1  jmcneill #include <lib/libkern/libkern.h>	/* hexdump */
     42  1.1  jmcneill 
     43  1.1  jmcneill #include <dev/i2c/i2cvar.h>
     44  1.1  jmcneill 
     45  1.1  jmcneill #include "avenc.h"
     46  1.2  jmcneill #include "vireg.h"
     47  1.1  jmcneill 
     48  1.1  jmcneill #define AVENC_DEBUG		0
     49  1.1  jmcneill 
     50  1.1  jmcneill #define AVENC_ADDR		0x70
     51  1.1  jmcneill 
     52  1.1  jmcneill #define AVENC_VOLUME		0x71
     53  1.1  jmcneill #define  AVENC_VOLUME_RIGHT	__BITS(15,8)
     54  1.1  jmcneill #define  AVENC_VOLUME_LEFT	__BITS(7,0)
     55  1.1  jmcneill 
     56  1.1  jmcneill #define RD1			avenc_read_1
     57  1.1  jmcneill #define RD2			avenc_read_2
     58  1.2  jmcneill #define WR1			avenc_write_1
     59  1.1  jmcneill #define WR2			avenc_write_2
     60  1.2  jmcneill #define WR4			avenc_write_4
     61  1.2  jmcneill #define WRBUF			avenc_write_buf
     62  1.1  jmcneill 
     63  1.1  jmcneill static i2c_tag_t avenc_tag;
     64  1.1  jmcneill static i2c_addr_t avenc_addr;
     65  1.1  jmcneill 
     66  1.1  jmcneill static uint8_t
     67  1.1  jmcneill avenc_read_1(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg)
     68  1.1  jmcneill {
     69  1.1  jmcneill 	uint8_t val;
     70  1.1  jmcneill 
     71  1.1  jmcneill 	if (iic_smbus_read_byte(tag, addr, reg, &val, 0) != 0) {
     72  1.1  jmcneill 		val = 0xff;
     73  1.1  jmcneill 	}
     74  1.1  jmcneill 
     75  1.1  jmcneill 	return val;
     76  1.1  jmcneill }
     77  1.1  jmcneill 
     78  1.1  jmcneill static uint16_t
     79  1.1  jmcneill avenc_read_2(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg)
     80  1.1  jmcneill {
     81  1.2  jmcneill 	uint8_t vbuf[2];
     82  1.1  jmcneill 
     83  1.2  jmcneill 	if (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &reg, 1,
     84  1.2  jmcneill 	    	     vbuf, sizeof(vbuf), 0) != 0) {
     85  1.2  jmcneill 		return 0xffff;
     86  1.2  jmcneill 	} else {
     87  1.2  jmcneill 		return ((uint16_t)vbuf[0] << 8) | vbuf[1];
     88  1.1  jmcneill 	}
     89  1.2  jmcneill }
     90  1.1  jmcneill 
     91  1.2  jmcneill static void
     92  1.2  jmcneill avenc_write_1(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t val)
     93  1.2  jmcneill {
     94  1.2  jmcneill 	iic_smbus_write_byte(tag, addr, reg, val, 0);
     95  1.1  jmcneill }
     96  1.1  jmcneill 
     97  1.1  jmcneill static void
     98  1.1  jmcneill avenc_write_2(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint16_t val)
     99  1.1  jmcneill {
    100  1.2  jmcneill 	uint8_t vbuf[2];
    101  1.2  jmcneill 
    102  1.2  jmcneill 	vbuf[0] = (val >> 8) & 0xff;
    103  1.2  jmcneill 	vbuf[1] = val & 0xff;
    104  1.2  jmcneill 
    105  1.2  jmcneill 	iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &reg, 1,
    106  1.2  jmcneill 		 vbuf, sizeof(vbuf), 0);
    107  1.2  jmcneill }
    108  1.2  jmcneill 
    109  1.2  jmcneill static void
    110  1.2  jmcneill avenc_write_4(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint32_t val)
    111  1.2  jmcneill {
    112  1.2  jmcneill 	uint8_t vbuf[4];
    113  1.2  jmcneill 
    114  1.2  jmcneill 	vbuf[0] = (val >> 24) & 0xff;
    115  1.2  jmcneill 	vbuf[1] = (val >> 16) & 0xff;
    116  1.2  jmcneill 	vbuf[2] = (val >> 8) & 0xff;
    117  1.2  jmcneill 	vbuf[3] = val & 0xff;
    118  1.2  jmcneill 
    119  1.2  jmcneill 	iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &reg, 1,
    120  1.2  jmcneill 		 vbuf, sizeof(vbuf), 0);
    121  1.2  jmcneill }
    122  1.2  jmcneill 
    123  1.2  jmcneill static void
    124  1.2  jmcneill avenc_write_buf(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t *buf,
    125  1.2  jmcneill     size_t buflen)
    126  1.2  jmcneill {
    127  1.2  jmcneill 	iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &reg, 1,
    128  1.2  jmcneill 		 buf, buflen, 0);
    129  1.1  jmcneill }
    130  1.1  jmcneill 
    131  1.1  jmcneill void
    132  1.1  jmcneill avenc_get_volume(uint8_t *left, uint8_t *right)
    133  1.1  jmcneill {
    134  1.1  jmcneill 	uint16_t val;
    135  1.1  jmcneill 
    136  1.1  jmcneill 	if (avenc_addr == 0) {
    137  1.1  jmcneill 		*left = *right = 0;
    138  1.1  jmcneill 		return;
    139  1.1  jmcneill 	}
    140  1.1  jmcneill 
    141  1.1  jmcneill 	iic_acquire_bus(avenc_tag, 0);
    142  1.1  jmcneill 	val = RD2(avenc_tag, avenc_addr, AVENC_VOLUME);
    143  1.1  jmcneill 	iic_release_bus(avenc_tag, 0);
    144  1.1  jmcneill 
    145  1.1  jmcneill 	*left = __SHIFTOUT(val, AVENC_VOLUME_LEFT);
    146  1.1  jmcneill 	*right = __SHIFTOUT(val, AVENC_VOLUME_RIGHT);
    147  1.1  jmcneill }
    148  1.1  jmcneill 
    149  1.1  jmcneill void
    150  1.1  jmcneill avenc_set_volume(uint8_t left, uint8_t right)
    151  1.1  jmcneill {
    152  1.1  jmcneill 	uint16_t val;
    153  1.1  jmcneill 
    154  1.1  jmcneill 	if (avenc_addr == 0) {
    155  1.1  jmcneill 		return;
    156  1.1  jmcneill 	}
    157  1.1  jmcneill 
    158  1.1  jmcneill 	val = __SHIFTIN(left, AVENC_VOLUME_LEFT) |
    159  1.1  jmcneill 	      __SHIFTIN(right, AVENC_VOLUME_RIGHT);
    160  1.1  jmcneill 
    161  1.1  jmcneill 	iic_acquire_bus(avenc_tag, 0);
    162  1.1  jmcneill 	WR2(avenc_tag, avenc_addr, AVENC_VOLUME, val);
    163  1.1  jmcneill 	iic_release_bus(avenc_tag, 0);
    164  1.1  jmcneill }
    165  1.1  jmcneill 
    166  1.1  jmcneill static void
    167  1.2  jmcneill avenc_dump_regs(const char *pfx, i2c_tag_t tag, i2c_addr_t addr)
    168  1.1  jmcneill {
    169  1.1  jmcneill 	uint8_t regdump[0x100];
    170  1.1  jmcneill 	unsigned int reg;
    171  1.1  jmcneill 
    172  1.1  jmcneill 	iic_acquire_bus(tag, 0);
    173  1.1  jmcneill 
    174  1.1  jmcneill 	for (reg = 0; reg < sizeof(regdump); reg++) {
    175  1.1  jmcneill 		regdump[reg] = RD1(tag, addr, reg);
    176  1.1  jmcneill 	}
    177  1.1  jmcneill 
    178  1.1  jmcneill 	iic_release_bus(tag, 0);
    179  1.1  jmcneill 
    180  1.2  jmcneill 	hexdump(printf, pfx, regdump, sizeof(regdump));
    181  1.2  jmcneill }
    182  1.2  jmcneill 
    183  1.2  jmcneill static void
    184  1.2  jmcneill avenc_init(i2c_tag_t tag, i2c_addr_t addr)
    185  1.2  jmcneill {
    186  1.2  jmcneill 	uint8_t mvinit[26] = {};
    187  1.2  jmcneill 	uint8_t ginit[] = {
    188  1.2  jmcneill 		0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00,
    189  1.2  jmcneill 		0x10, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x60,
    190  1.2  jmcneill 		0x80, 0xa0, 0xeb, 0x10, 0x00, 0x20, 0x00, 0x40,
    191  1.2  jmcneill 		0x00, 0x60, 0x00, 0x80, 0x00, 0xa0, 0x00, 0xeb,
    192  1.2  jmcneill 		0x00
    193  1.2  jmcneill 	};
    194  1.2  jmcneill 	uint8_t video_fmt;
    195  1.2  jmcneill 
    196  1.2  jmcneill 	video_fmt = 0;
    197  1.2  jmcneill 	if (__SHIFTOUT(in16(VI_BASE + VI_DCR), VI_DCR_FMT) == VI_DCR_FMT_PAL) {
    198  1.2  jmcneill 		video_fmt |= 0x02;
    199  1.2  jmcneill 	}
    200  1.2  jmcneill 	if ((in16(VI_BASE + VI_VISEL) & VI_VISEL_COMPONENT_CABLE) != 0) {
    201  1.2  jmcneill 		video_fmt |= 0x20;
    202  1.2  jmcneill 	}
    203  1.2  jmcneill 
    204  1.2  jmcneill 	iic_acquire_bus(tag, 0);
    205  1.2  jmcneill 	WR1(tag, addr, 0x6a, 1);
    206  1.2  jmcneill 	WR1(tag, addr, 0x65, 3);
    207  1.2  jmcneill 	WR1(tag, addr, 0x01, video_fmt);
    208  1.2  jmcneill 	WR1(tag, addr, 0x00, 0);
    209  1.2  jmcneill 	WR1(tag, addr, 0x02, 7);
    210  1.2  jmcneill 	WR2(tag, addr, 0x05, 0);
    211  1.2  jmcneill 	WR2(tag, addr, 0x08, 0);
    212  1.2  jmcneill 	WR4(tag, addr, 0x7a, 0);
    213  1.2  jmcneill 	WRBUF(tag, addr, 0x40, mvinit, sizeof(mvinit));
    214  1.2  jmcneill 	WR1(tag, addr, 0x0a, 0);
    215  1.2  jmcneill 	WR1(tag, addr, 0x03, 1);
    216  1.2  jmcneill 	WRBUF(tag, addr, 0x10, ginit, sizeof(ginit));
    217  1.2  jmcneill 	WR1(tag, addr, 0x04, 1);
    218  1.2  jmcneill 	WR4(tag, addr, 0x7a, 0);
    219  1.2  jmcneill 	WR2(tag, addr, 0x08, 0);
    220  1.2  jmcneill 	WR1(tag, addr, 0x03, 1);
    221  1.2  jmcneill 	WR1(tag, addr, 0x6e, 0);
    222  1.2  jmcneill 	iic_release_bus(tag, 0);
    223  1.2  jmcneill 
    224  1.2  jmcneill 	avenc_set_volume(0x8e, 0x8e);
    225  1.1  jmcneill }
    226  1.1  jmcneill 
    227  1.2  jmcneill 
    228  1.1  jmcneill static int
    229  1.1  jmcneill avenc_match(device_t parent, cfdata_t match, void *aux)
    230  1.1  jmcneill {
    231  1.1  jmcneill 	struct i2c_attach_args *ia = aux;
    232  1.1  jmcneill 
    233  1.1  jmcneill 	return ia->ia_addr == AVENC_ADDR;
    234  1.1  jmcneill }
    235  1.1  jmcneill 
    236  1.1  jmcneill static void
    237  1.1  jmcneill avenc_attach(device_t parent, device_t self, void *aux)
    238  1.1  jmcneill {
    239  1.1  jmcneill 	struct i2c_attach_args *ia = aux;
    240  1.1  jmcneill 	i2c_tag_t tag = ia->ia_tag;
    241  1.1  jmcneill 	i2c_addr_t addr = ia->ia_addr;
    242  1.1  jmcneill 
    243  1.1  jmcneill 	KASSERT(device_unit(self) == 0);
    244  1.1  jmcneill 
    245  1.1  jmcneill 	aprint_naive("\n");
    246  1.1  jmcneill 	aprint_normal(": A/V Encoder\n");
    247  1.1  jmcneill 
    248  1.1  jmcneill 	if (AVENC_DEBUG) {
    249  1.2  jmcneill 		avenc_dump_regs("avenc pre ", tag, addr);
    250  1.1  jmcneill 	}
    251  1.1  jmcneill 
    252  1.1  jmcneill 	avenc_tag = tag;
    253  1.1  jmcneill 	avenc_addr = addr;
    254  1.2  jmcneill 
    255  1.2  jmcneill 	avenc_init(tag, addr);
    256  1.2  jmcneill 
    257  1.2  jmcneill 	if (AVENC_DEBUG) {
    258  1.2  jmcneill 		avenc_dump_regs("avenc post", tag, addr);
    259  1.2  jmcneill 	}
    260  1.1  jmcneill }
    261  1.1  jmcneill 
    262  1.1  jmcneill CFATTACH_DECL_NEW(avenc, 0, avenc_match, avenc_attach, NULL, NULL);
    263