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