11.1Sjmcneill/* $NetBSD: gecko.c,v 1.1 2025/11/16 20:11:47 jmcneill Exp $ */
21.1Sjmcneill
31.1Sjmcneill/*-
41.1Sjmcneill * Copyright (c) 2025 Jared McNeill <jmcneill@invisible.ca>
51.1Sjmcneill * All rights reserved.
61.1Sjmcneill *
71.1Sjmcneill * Redistribution and use in source and binary forms, with or without
81.1Sjmcneill * modification, are permitted provided that the following conditions
91.1Sjmcneill * are met:
101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright
111.1Sjmcneill *    notice, this list of conditions and the following disclaimer.
121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
131.1Sjmcneill *    notice, this list of conditions and the following disclaimer in the
141.1Sjmcneill *    documentation and/or other materials provided with the distribution.
151.1Sjmcneill *
161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
171.1Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
181.1Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
191.1Sjmcneill * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
201.1Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211.1Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221.1Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231.1Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241.1Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251.1Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261.1Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
271.1Sjmcneill */
281.1Sjmcneill
291.1Sjmcneill#include <lib/libsa/stand.h>
301.1Sjmcneill
311.1Sjmcneill#include <machine/pio.h>
321.1Sjmcneill
331.1Sjmcneill#include "gecko.h"
341.1Sjmcneill#include "timer.h"
351.1Sjmcneill
361.1Sjmcneill#define EXI_BASE		0x0d806800
371.1Sjmcneill#define	EXI_CSR(n)		(EXI_BASE + 0x00 + (n) * 0x14)
381.1Sjmcneill#define  EXI_CSR_EXTINT		__BIT(11)
391.1Sjmcneill#define  EXI_CSR_EXTINTMASK	__BIT(10)
401.1Sjmcneill#define	 EXI_CSR_CS		__BITS(9,7)
411.1Sjmcneill#define	 EXI_CSR_CLK		__BITS(6,4)
421.1Sjmcneill#define	EXI_CR(n)		(EXI_BASE + 0x0c + (n) * 0x14)
431.1Sjmcneill#define	 EXI_CR_TLEN		__BITS(5,4)
441.1Sjmcneill#define  EXI_CR_RW		__BITS(3,2)
451.1Sjmcneill#define  EXI_CR_RW_READ		__SHIFTIN(0, EXI_CR_RW)
461.1Sjmcneill#define  EXI_CR_RW_WRITE	__SHIFTIN(1, EXI_CR_RW)
471.1Sjmcneill#define  EXI_CR_RW_READWRITE	__SHIFTIN(2, EXI_CR_RW)
481.1Sjmcneill#define	 EXI_CR_DMA		__BIT(1)
491.1Sjmcneill#define  EXI_CR_TSTART		__BIT(0)
501.1Sjmcneill#define	EXI_DATA(n)		(EXI_BASE + 0x10 + (n) * 0x14)
511.1Sjmcneill
521.1Sjmcneill#define SI_BASE			0x0d806400
531.1Sjmcneill#define SI_EXILK		(SI_BASE + 0x03c)
541.1Sjmcneill
551.1Sjmcneill#define	EXI_FREQ_32MHZ		5
561.1Sjmcneill
571.1Sjmcneill#define GECKO_CSR					\
581.1Sjmcneill	(__SHIFTIN(1, EXI_CSR_CS) |			\
591.1Sjmcneill	 __SHIFTIN(EXI_FREQ_32MHZ, EXI_CSR_CLK))
601.1Sjmcneill#define GECKO_CR(len, rdwr)				\
611.1Sjmcneill	(__SHIFTIN((len) - 1, EXI_CR_TLEN) | 		\
621.1Sjmcneill	 (rdwr) | EXI_CR_TSTART)
631.1Sjmcneill
641.1Sjmcneill#define GECKO_CMD_ID		0x9000
651.1Sjmcneill#define GECKO_CMD_RECV_BYTE	0xa000
661.1Sjmcneill#define GECKO_CMD_SEND_BYTE	0xb000
671.1Sjmcneill
681.1Sjmcneillstatic int gecko_chan = -1;
691.1Sjmcneillstatic int gecko_keycurrent;
701.1Sjmcneillstatic int gecko_keypending;
711.1Sjmcneill
721.1Sjmcneillstatic void
731.1Sjmcneillgecko_wait(void)
741.1Sjmcneill{
751.1Sjmcneill	int retry;
761.1Sjmcneill
771.1Sjmcneill	for (retry = 0; retry < 1000; retry++) {
781.1Sjmcneill		if ((in32(EXI_CR(gecko_chan)) & EXI_CR_TSTART) == 0) {
791.1Sjmcneill			return;
801.1Sjmcneill		}
811.1Sjmcneill	}
821.1Sjmcneill}
831.1Sjmcneill
841.1Sjmcneillstatic uint16_t
851.1Sjmcneillgecko_command(uint16_t command)
861.1Sjmcneill{
871.1Sjmcneill	uint16_t value;
881.1Sjmcneill
891.1Sjmcneill	out32(EXI_CSR(gecko_chan), GECKO_CSR);
901.1Sjmcneill	out32(EXI_DATA(gecko_chan), (uint32_t)command << 16);
911.1Sjmcneill	out32(EXI_CR(gecko_chan), GECKO_CR(2, EXI_CR_RW_READWRITE));
921.1Sjmcneill	gecko_wait();
931.1Sjmcneill	value = in32(EXI_DATA(gecko_chan)) >> 16;
941.1Sjmcneill	out32(EXI_CSR(gecko_chan), 0);
951.1Sjmcneill
961.1Sjmcneill	return value;
971.1Sjmcneill}
981.1Sjmcneill
991.1Sjmcneillstatic uint32_t
1001.1Sjmcneillgecko_id(void)
1011.1Sjmcneill{
1021.1Sjmcneill	uint32_t value;
1031.1Sjmcneill
1041.1Sjmcneill	out32(EXI_CSR(gecko_chan), GECKO_CSR);
1051.1Sjmcneill	out32(EXI_DATA(gecko_chan), 0);
1061.1Sjmcneill	out32(EXI_CR(gecko_chan), GECKO_CR(2, EXI_CR_RW_READWRITE));
1071.1Sjmcneill	gecko_wait();
1081.1Sjmcneill	out32(EXI_CR(gecko_chan), GECKO_CR(4, EXI_CR_RW_READWRITE));
1091.1Sjmcneill	gecko_wait();
1101.1Sjmcneill	value = in32(EXI_DATA(gecko_chan));
1111.1Sjmcneill	out32(EXI_CSR(gecko_chan), 0);
1121.1Sjmcneill
1131.1Sjmcneill	return value;
1141.1Sjmcneill}
1151.1Sjmcneill
1161.1Sjmcneillint
1171.1Sjmcneillgecko_getchar(void)
1181.1Sjmcneill{
1191.1Sjmcneill	int key;
1201.1Sjmcneill
1211.1Sjmcneill	if (gecko_chan == -1) {
1221.1Sjmcneill		return -1;
1231.1Sjmcneill	}
1241.1Sjmcneill
1251.1Sjmcneill	if (gecko_keypending) {
1261.1Sjmcneill		key = gecko_keycurrent;
1271.1Sjmcneill		gecko_keypending = 0;
1281.1Sjmcneill	} else {
1291.1Sjmcneill		uint16_t value;
1301.1Sjmcneill
1311.1Sjmcneill		do {
1321.1Sjmcneill			value = gecko_command(GECKO_CMD_RECV_BYTE);
1331.1Sjmcneill		} while ((value & 0x0800) == 0);
1341.1Sjmcneill		key = value & 0xff;
1351.1Sjmcneill	}
1361.1Sjmcneill
1371.1Sjmcneill	return key;
1381.1Sjmcneill}
1391.1Sjmcneill
1401.1Sjmcneillvoid
1411.1Sjmcneillgecko_putchar(int c)
1421.1Sjmcneill{
1431.1Sjmcneill	if (gecko_chan == -1) {
1441.1Sjmcneill		return;
1451.1Sjmcneill	}
1461.1Sjmcneill
1471.1Sjmcneill	c &= 0xff;
1481.1Sjmcneill	gecko_command(GECKO_CMD_SEND_BYTE | (c << 4));
1491.1Sjmcneill}
1501.1Sjmcneill
1511.1Sjmcneillint
1521.1Sjmcneillgecko_ischar(void)
1531.1Sjmcneill{
1541.1Sjmcneill	if (gecko_chan != -1 && !gecko_keypending) {
1551.1Sjmcneill		uint16_t value;
1561.1Sjmcneill
1571.1Sjmcneill		value = gecko_command(GECKO_CMD_RECV_BYTE);
1581.1Sjmcneill		if ((value & 0x0800) != 0) {
1591.1Sjmcneill			gecko_keycurrent = value & 0xff;
1601.1Sjmcneill			gecko_keypending = 1;
1611.1Sjmcneill		}
1621.1Sjmcneill	}
1631.1Sjmcneill
1641.1Sjmcneill	return gecko_keypending;
1651.1Sjmcneill}
1661.1Sjmcneill
1671.1Sjmcneillstatic int
1681.1Sjmcneillgecko_detect(void)
1691.1Sjmcneill{
1701.1Sjmcneill	int nsamples = 0;
1711.1Sjmcneill
1721.1Sjmcneill	/*
1731.1Sjmcneill	 * MINI may be still using EXI when we get here. Wait for it to go
1741.1Sjmcneill	 * idle before probing for Gecko.
1751.1Sjmcneill	 */
1761.1Sjmcneill	while (nsamples++ < 1000) {
1771.1Sjmcneill		if ((in32(EXI_CR(gecko_chan)) & EXI_CR_TSTART) != 0) {
1781.1Sjmcneill			printf("TSTART set, resetting samples\n");
1791.1Sjmcneill			nsamples = 0;
1801.1Sjmcneill		}
1811.1Sjmcneill		timer_udelay(1000);
1821.1Sjmcneill	}
1831.1Sjmcneill
1841.1Sjmcneill	out32(EXI_CSR(gecko_chan), 0);
1851.1Sjmcneill	out32(EXI_CSR(gecko_chan), EXI_CSR_EXTINT | EXI_CSR_EXTINTMASK);
1861.1Sjmcneill
1871.1Sjmcneill	return gecko_id() == 0 &&
1881.1Sjmcneill	       gecko_command(GECKO_CMD_ID) == 0x0470;
1891.1Sjmcneill}
1901.1Sjmcneill
1911.1Sjmcneillint
1921.1Sjmcneillgecko_probe(void)
1931.1Sjmcneill{
1941.1Sjmcneill	out32(SI_EXILK, 0);
1951.1Sjmcneill
1961.1Sjmcneill	gecko_chan = 0;
1971.1Sjmcneill	if (!gecko_detect()) {
1981.1Sjmcneill		gecko_chan = 1;
1991.1Sjmcneill		if (!gecko_detect()) {
2001.1Sjmcneill			gecko_chan = -1;
2011.1Sjmcneill		}
2021.1Sjmcneill	}
2031.1Sjmcneill
2041.1Sjmcneill	return gecko_chan;
2051.1Sjmcneill}
206