11.1Sjmcneill/* $NetBSD: miniipc.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 REGENTS AND CONTRIBUTORS ``AS IS'' AND 171.1Sjmcneill * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181.1Sjmcneill * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191.1Sjmcneill * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 201.1Sjmcneill * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211.1Sjmcneill * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221.1Sjmcneill * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231.1Sjmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241.1Sjmcneill * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sjmcneill * 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 "miniipc.h" 341.1Sjmcneill#include "sdmmc.h" 351.1Sjmcneill#include "cache.h" 361.1Sjmcneill#include "timer.h" 371.1Sjmcneill 381.1Sjmcneill#define MINIIPC_INFO_PTR 0x13fffffc 391.1Sjmcneill 401.1Sjmcneill#define HW_BASE 0x0d800000 411.1Sjmcneill#define HW_IPC_PPCMSG (HW_BASE + 0x00) 421.1Sjmcneill#define HW_IPC_PPCMSG_INDEX_OUT_MASK __BITS(31, 16) 431.1Sjmcneill#define HW_IPC_PPCMSG_INDEX_IN_MASK __BITS(15, 0) 441.1Sjmcneill#define HW_IPC_PPCCTRL (HW_BASE + 0x04) 451.1Sjmcneill#define HW_IPC_PPCCTRL_IN __BIT(2) 461.1Sjmcneill#define HW_IPC_PPCCTRL_OUT __BIT(0) 471.1Sjmcneill#define HW_IPC_ARMMSG (HW_BASE + 0x08) 481.1Sjmcneill#define HW_IPC_ARMMSG_INDEX_OUT_MASK __BITS(15, 0) 491.1Sjmcneill 501.1Sjmcneill/* IPC request flags */ 511.1Sjmcneill#define IPC_SLOW 0x00 521.1Sjmcneill#define IPC_FAST 0x01 531.1Sjmcneill 541.1Sjmcneill/* IPC devices and requests */ 551.1Sjmcneill#define IPC_DEV_SYS 0x00 561.1Sjmcneill#define IPC_SYS_PING 0x0000 571.1Sjmcneill#define IPC_DEV_SDMMC 0x07 581.1Sjmcneill#define IPC_SDMMC_ACK 0x0000 591.1Sjmcneill#define IPC_SDMMC_READ 0x0001 601.1Sjmcneill#define IPC_SDMMC_WRITE 0x0002 611.1Sjmcneill#define IPC_SDMMC_STATE 0x0003 621.1Sjmcneill#define IPC_SDMMC_SIZE 0x0004 631.1Sjmcneill 641.1Sjmcneillstatic volatile ipc_info_header_t *infohdr; 651.1Sjmcneillstatic uint32_t index_in; 661.1Sjmcneillstatic uint32_t index_out; 671.1Sjmcneillstatic uint32_t request_tag; 681.1Sjmcneill 691.1Sjmcneillstatic uint32_t 701.1Sjmcneillminiipc_next_index_in(void) 711.1Sjmcneill{ 721.1Sjmcneill return (index_in + 1) % infohdr->ipc_in_size; 731.1Sjmcneill} 741.1Sjmcneill 751.1Sjmcneillstatic uint32_t 761.1Sjmcneillminiipc_next_index_out(void) 771.1Sjmcneill{ 781.1Sjmcneill return (index_out + 1) % infohdr->ipc_out_size; 791.1Sjmcneill} 801.1Sjmcneill 811.1Sjmcneillbool 821.1Sjmcneillminiipc_probe(void) 831.1Sjmcneill{ 841.1Sjmcneill paddr_t pa; 851.1Sjmcneill 861.1Sjmcneill pa = in32(MINIIPC_INFO_PTR); 871.1Sjmcneill if (pa == 0 || pa == 0xffffffff) { 881.1Sjmcneill printf("No MINI IPC pointer at 0x%x\n", MINIIPC_INFO_PTR); 891.1Sjmcneill return false; 901.1Sjmcneill } 911.1Sjmcneill infohdr = (ipc_info_header_t *)pa; 921.1Sjmcneill cache_dcbi((void *)infohdr, sizeof(*infohdr)); 931.1Sjmcneill 941.1Sjmcneill if (memcmp((void *)infohdr->magic, "IPC", 3) != 0) { 951.1Sjmcneill return false; 961.1Sjmcneill } 971.1Sjmcneill 981.1Sjmcneill index_in = __SHIFTOUT(in32(HW_IPC_PPCMSG), HW_IPC_PPCMSG_INDEX_IN_MASK); 991.1Sjmcneill index_out = __SHIFTOUT(in32(HW_IPC_PPCMSG), HW_IPC_PPCMSG_INDEX_OUT_MASK); 1001.1Sjmcneill 1011.1Sjmcneill miniipc_ping(); 1021.1Sjmcneill 1031.1Sjmcneill return true; 1041.1Sjmcneill} 1051.1Sjmcneill 1061.1Sjmcneillstatic int 1071.1Sjmcneillminiipc_sendrecv(const ipc_request_t *req_in, ipc_request_t *req_out) 1081.1Sjmcneill{ 1091.1Sjmcneill volatile ipc_request_t *req; 1101.1Sjmcneill int retry, error = 0; 1111.1Sjmcneill 1121.1Sjmcneill req = &infohdr->ipc_in[index_in]; 1131.1Sjmcneill 1141.1Sjmcneill *req = *req_in; 1151.1Sjmcneill req->tag = ++request_tag; 1161.1Sjmcneill 1171.1Sjmcneill#ifdef MINIIPC_DEBUG 1181.1Sjmcneill printf("IPC[%u] -> req code 0x%x tag %u args %u %u %u %u %u %u\n", 1191.1Sjmcneill index_in, req->code, req->tag, 1201.1Sjmcneill req->args[0], req->args[1], req->args[2], req->args[3], 1211.1Sjmcneill req->args[4], req->args[5]); 1221.1Sjmcneill#endif 1231.1Sjmcneill 1241.1Sjmcneill cache_dcbf((void *)req, sizeof(*req)); 1251.1Sjmcneill 1261.1Sjmcneill req = &infohdr->ipc_out[index_out]; 1271.1Sjmcneill cache_dcbf((void *)req, sizeof(*req)); 1281.1Sjmcneill 1291.1Sjmcneill index_in = miniipc_next_index_in(); 1301.1Sjmcneill 1311.1Sjmcneill out32(HW_IPC_PPCMSG, 1321.1Sjmcneill (in32(HW_IPC_PPCMSG) & ~HW_IPC_PPCMSG_INDEX_IN_MASK) | 1331.1Sjmcneill __SHIFTIN(index_in, HW_IPC_PPCMSG_INDEX_IN_MASK)); 1341.1Sjmcneill out32(HW_IPC_PPCCTRL, in32(HW_IPC_PPCCTRL) | HW_IPC_PPCCTRL_OUT); 1351.1Sjmcneill 1361.1Sjmcneill retry = 10000000; 1371.1Sjmcneill while (__SHIFTOUT(in32(HW_IPC_ARMMSG), HW_IPC_ARMMSG_INDEX_OUT_MASK) == 1381.1Sjmcneill index_out) { 1391.1Sjmcneill timer_udelay(1); 1401.1Sjmcneill if (--retry == 0) { 1411.1Sjmcneill#ifdef MINIIPC_DEBUG 1421.1Sjmcneill printf("HW_IPC_PPCMSG: 0x%x\n", in32(HW_IPC_PPCMSG)); 1431.1Sjmcneill printf("HW_IPC_ARMMSG: 0x%x\n", in32(HW_IPC_ARMMSG)); 1441.1Sjmcneill#endif 1451.1Sjmcneill error = ETIMEDOUT; 1461.1Sjmcneill break; 1471.1Sjmcneill } 1481.1Sjmcneill } 1491.1Sjmcneill 1501.1Sjmcneill req = &infohdr->ipc_out[index_out]; 1511.1Sjmcneill cache_dcbi((void *)req, sizeof(*req)); 1521.1Sjmcneill 1531.1Sjmcneill#ifdef MINIIPC_DEBUG 1541.1Sjmcneill printf("IPC[%u] <- req code 0x%x tag %u args %u %u %u %u %u %u\n", 1551.1Sjmcneill index_out, req->code, req->tag, 1561.1Sjmcneill req->args[0], req->args[1], req->args[2], req->args[3], 1571.1Sjmcneill req->args[4], req->args[5]); 1581.1Sjmcneill#endif 1591.1Sjmcneill 1601.1Sjmcneill *req_out = *req; 1611.1Sjmcneill 1621.1Sjmcneill#ifdef MINIIPC_DEBUG 1631.1Sjmcneill printf(" DUMP OUTPUT RING\n"); 1641.1Sjmcneill for (int n = 0; n < infohdr->ipc_out_size; n++) { 1651.1Sjmcneill req = &infohdr->ipc_out[n]; 1661.1Sjmcneill cache_dcbi((void *)req, sizeof(*req)); 1671.1Sjmcneill printf(" debug IPC[%u] <- req code 0x%x tag %u args %u %u %u %u %u %u\n", 1681.1Sjmcneill n, req->code, req->tag, 1691.1Sjmcneill req->args[0], req->args[1], req->args[2], req->args[3], 1701.1Sjmcneill req->args[4], req->args[5]); 1711.1Sjmcneill } 1721.1Sjmcneill printf(" END OUTPUT RING\n"); 1731.1Sjmcneill#endif 1741.1Sjmcneill 1751.1Sjmcneill index_out = miniipc_next_index_out(); 1761.1Sjmcneill out32(HW_IPC_PPCMSG, 1771.1Sjmcneill (in32(HW_IPC_PPCMSG) & ~HW_IPC_PPCMSG_INDEX_OUT_MASK) | 1781.1Sjmcneill __SHIFTIN(index_out, HW_IPC_PPCMSG_INDEX_OUT_MASK)); 1791.1Sjmcneill 1801.1Sjmcneill return error; 1811.1Sjmcneill} 1821.1Sjmcneill 1831.1Sjmcneillint 1841.1Sjmcneillminiipc_ping(void) 1851.1Sjmcneill{ 1861.1Sjmcneill ipc_request_t req = { 1871.1Sjmcneill .flags = IPC_FAST, 1881.1Sjmcneill .device = IPC_DEV_SYS, 1891.1Sjmcneill .req = IPC_SYS_PING, 1901.1Sjmcneill }; 1911.1Sjmcneill 1921.1Sjmcneill return miniipc_sendrecv(&req, &req); 1931.1Sjmcneill} 1941.1Sjmcneill 1951.1Sjmcneillint 1961.1Sjmcneillminiipc_sdmmc_ack(uint32_t *ack) 1971.1Sjmcneill{ 1981.1Sjmcneill ipc_request_t req = { 1991.1Sjmcneill .flags = IPC_SLOW, 2001.1Sjmcneill .device = IPC_DEV_SDMMC, 2011.1Sjmcneill .req = IPC_SDMMC_ACK, 2021.1Sjmcneill }; 2031.1Sjmcneill int error; 2041.1Sjmcneill 2051.1Sjmcneill error = miniipc_sendrecv(&req, &req); 2061.1Sjmcneill if (error != 0) { 2071.1Sjmcneill *ack = 0; 2081.1Sjmcneill return error; 2091.1Sjmcneill } 2101.1Sjmcneill 2111.1Sjmcneill *ack = req.args[0]; 2121.1Sjmcneill return 0; 2131.1Sjmcneill} 2141.1Sjmcneill 2151.1Sjmcneillint 2161.1Sjmcneillminiipc_sdmmc_state(uint32_t *state) 2171.1Sjmcneill{ 2181.1Sjmcneill ipc_request_t req = { 2191.1Sjmcneill .flags = IPC_SLOW, 2201.1Sjmcneill .device = IPC_DEV_SDMMC, 2211.1Sjmcneill .req = IPC_SDMMC_STATE, 2221.1Sjmcneill }; 2231.1Sjmcneill int error; 2241.1Sjmcneill 2251.1Sjmcneill error = miniipc_sendrecv(&req, &req); 2261.1Sjmcneill if (error != 0) { 2271.1Sjmcneill *state = 0; 2281.1Sjmcneill return error; 2291.1Sjmcneill } 2301.1Sjmcneill 2311.1Sjmcneill *state = req.args[0]; 2321.1Sjmcneill return 0; 2331.1Sjmcneill} 2341.1Sjmcneill 2351.1Sjmcneillint 2361.1Sjmcneillminiipc_sdmmc_size(uint32_t *size) 2371.1Sjmcneill{ 2381.1Sjmcneill ipc_request_t req = { 2391.1Sjmcneill .flags = IPC_SLOW, 2401.1Sjmcneill .device = IPC_DEV_SDMMC, 2411.1Sjmcneill .req = IPC_SDMMC_SIZE, 2421.1Sjmcneill }; 2431.1Sjmcneill int error; 2441.1Sjmcneill 2451.1Sjmcneill error = miniipc_sendrecv(&req, &req); 2461.1Sjmcneill if (error != 0) { 2471.1Sjmcneill *size = 0; 2481.1Sjmcneill return error; 2491.1Sjmcneill } 2501.1Sjmcneill 2511.1Sjmcneill *size = req.args[0]; 2521.1Sjmcneill return 0; 2531.1Sjmcneill} 2541.1Sjmcneill 2551.1Sjmcneillint 2561.1Sjmcneillminiipc_sdmmc_read(uint32_t start_blkno, uint32_t nblks, void *buf) 2571.1Sjmcneill{ 2581.1Sjmcneill ipc_request_t req = { 2591.1Sjmcneill .flags = IPC_SLOW, 2601.1Sjmcneill .device = IPC_DEV_SDMMC, 2611.1Sjmcneill .req = IPC_SDMMC_READ, 2621.1Sjmcneill .args = { start_blkno, nblks, (uint32_t)buf }, 2631.1Sjmcneill }; 2641.1Sjmcneill int error; 2651.1Sjmcneill 2661.1Sjmcneill if (((uint32_t)buf & (CACHE_LINE_SIZE - 1)) != 0) { 2671.1Sjmcneill cache_dcbf(buf, nblks * SDMMC_BLOCK_SIZE); 2681.1Sjmcneill } 2691.1Sjmcneill error = miniipc_sendrecv(&req, &req); 2701.1Sjmcneill if (error != 0) { 2711.1Sjmcneill return error; 2721.1Sjmcneill } else if (req.args[0] != 0) { 2731.1Sjmcneill printf("read block %u (nblks = %u) failed: %d\n", 2741.1Sjmcneill start_blkno, nblks, (int)req.args[0]); 2751.1Sjmcneill error = EIO; 2761.1Sjmcneill return error; 2771.1Sjmcneill } 2781.1Sjmcneill cache_dcbi(buf, nblks * SDMMC_BLOCK_SIZE); 2791.1Sjmcneill 2801.1Sjmcneill return 0; 2811.1Sjmcneill} 282