159191f35SAleksandr Rybalko /*- 259191f35SAleksandr Rybalko * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 359191f35SAleksandr Rybalko * 459191f35SAleksandr Rybalko * Copyright (c) 2021 ARM Ltd 559191f35SAleksandr Rybalko * 659191f35SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 759191f35SAleksandr Rybalko * modification, are permitted provided that the following conditions 859191f35SAleksandr Rybalko * are met: 959191f35SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1059191f35SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1159191f35SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1259191f35SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 1359191f35SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 1459191f35SAleksandr Rybalko * 1559191f35SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1659191f35SAleksandr Rybalko * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1759191f35SAleksandr Rybalko * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1859191f35SAleksandr Rybalko * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1959191f35SAleksandr Rybalko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2059191f35SAleksandr Rybalko * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2159191f35SAleksandr Rybalko * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2259191f35SAleksandr Rybalko * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2359191f35SAleksandr Rybalko * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2459191f35SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2559191f35SAleksandr Rybalko * SUCH DAMAGE. 2659191f35SAleksandr Rybalko * 2759191f35SAleksandr Rybalko * $FreeBSD$ 2859191f35SAleksandr Rybalko */ 2959191f35SAleksandr Rybalko 3059191f35SAleksandr Rybalko /* Arm CoreLink CMN-600 Coherent Mesh Network Driver */ 3159191f35SAleksandr Rybalko 3259191f35SAleksandr Rybalko #include <sys/cdefs.h> 3359191f35SAleksandr Rybalko __FBSDID("$FreeBSD$"); 3459191f35SAleksandr Rybalko 3559191f35SAleksandr Rybalko #include "opt_acpi.h" 3659191f35SAleksandr Rybalko 3759191f35SAleksandr Rybalko #include <sys/param.h> 3859191f35SAleksandr Rybalko #include <sys/bus.h> 3959191f35SAleksandr Rybalko #include <sys/kernel.h> 4059191f35SAleksandr Rybalko #include <sys/malloc.h> 4159191f35SAleksandr Rybalko #include <sys/module.h> 4259191f35SAleksandr Rybalko #include <sys/proc.h> 4359191f35SAleksandr Rybalko #include <sys/rman.h> 4459191f35SAleksandr Rybalko #include <sys/smp.h> 4559191f35SAleksandr Rybalko #include <sys/sysctl.h> 4659191f35SAleksandr Rybalko 4759191f35SAleksandr Rybalko #include <machine/bus.h> 4859191f35SAleksandr Rybalko #include <machine/cpu.h> 4959191f35SAleksandr Rybalko 5059191f35SAleksandr Rybalko #include <contrib/dev/acpica/include/acpi.h> 5159191f35SAleksandr Rybalko #include <dev/acpica/acpivar.h> 5259191f35SAleksandr Rybalko 5359191f35SAleksandr Rybalko #include <machine/cmn600_reg.h> 5459191f35SAleksandr Rybalko 5559191f35SAleksandr Rybalko #define RD4(sc, r) bus_read_4((sc)->sc_res[0], (r)) 5659191f35SAleksandr Rybalko #define RD8(sc, r) bus_read_8((sc)->sc_res[0], (r)) 5759191f35SAleksandr Rybalko #define WR4(sc, r, v) bus_write_4((sc)->sc_res[0], (r), (v)) 5859191f35SAleksandr Rybalko #define WR8(sc, r, v) bus_write_8((sc)->sc_res[0], (r), (v)) 5959191f35SAleksandr Rybalko #define FLD(v, n) (((v) & n ## _MASK) >> n ## _SHIFT) 6059191f35SAleksandr Rybalko 6159191f35SAleksandr Rybalko static char *cmn600_ids[] = { 6259191f35SAleksandr Rybalko "ARMHC600", 6359191f35SAleksandr Rybalko NULL 6459191f35SAleksandr Rybalko }; 6559191f35SAleksandr Rybalko 6659191f35SAleksandr Rybalko static struct resource_spec cmn600_res_spec[] = { 6759191f35SAleksandr Rybalko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 6859191f35SAleksandr Rybalko { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_UNMAPPED | RF_OPTIONAL }, 6959191f35SAleksandr Rybalko { SYS_RES_IRQ, 0, RF_ACTIVE }, 7059191f35SAleksandr Rybalko { -1, 0 } 7159191f35SAleksandr Rybalko }; 7259191f35SAleksandr Rybalko 7359191f35SAleksandr Rybalko struct cmn600_node; 7459191f35SAleksandr Rybalko 7559191f35SAleksandr Rybalko typedef uint64_t (*nd_read_8_t)(struct cmn600_node *, uint32_t); 7659191f35SAleksandr Rybalko typedef uint32_t (*nd_read_4_t)(struct cmn600_node *, uint32_t); 7759191f35SAleksandr Rybalko typedef void (*nd_write_8_t)(struct cmn600_node *, uint32_t, uint64_t); 7859191f35SAleksandr Rybalko typedef void (*nd_write_4_t)(struct cmn600_node *, uint32_t, uint32_t); 7959191f35SAleksandr Rybalko 8059191f35SAleksandr Rybalko struct cmn600_node { 8159191f35SAleksandr Rybalko struct cmn600_softc *sc; 8259191f35SAleksandr Rybalko off_t nd_offset; 8359191f35SAleksandr Rybalko int nd_type; 8459191f35SAleksandr Rybalko uint16_t nd_id; 8559191f35SAleksandr Rybalko uint16_t nd_logical_id; 8659191f35SAleksandr Rybalko uint8_t nd_x, nd_y, nd_port, nd_sub; 8759191f35SAleksandr Rybalko uint16_t nd_child_count; 8859191f35SAleksandr Rybalko uint32_t nd_paired; 8959191f35SAleksandr Rybalko struct cmn600_node *nd_parent; 9059191f35SAleksandr Rybalko nd_read_8_t nd_read8; 9159191f35SAleksandr Rybalko nd_read_4_t nd_read4; 9259191f35SAleksandr Rybalko nd_write_8_t nd_write8; 9359191f35SAleksandr Rybalko nd_write_4_t nd_write4; 9459191f35SAleksandr Rybalko struct cmn600_node **nd_children; 9559191f35SAleksandr Rybalko }; 9659191f35SAleksandr Rybalko 9759191f35SAleksandr Rybalko struct cmn600_softc { 9859191f35SAleksandr Rybalko device_t sc_dev; 9959191f35SAleksandr Rybalko int sc_unit; 10059191f35SAleksandr Rybalko int sc_domain; 10159191f35SAleksandr Rybalko int sc_longid; 10259191f35SAleksandr Rybalko int sc_mesh_x; 10359191f35SAleksandr Rybalko int sc_mesh_y; 10459191f35SAleksandr Rybalko struct resource *sc_res[3]; 10559191f35SAleksandr Rybalko void *sc_ih; 10659191f35SAleksandr Rybalko int sc_r2; 10759191f35SAleksandr Rybalko int sc_rev; 10859191f35SAleksandr Rybalko struct cmn600_node *sc_rootnode; 10959191f35SAleksandr Rybalko struct cmn600_node *sc_dtcnode; 11059191f35SAleksandr Rybalko struct cmn600_node *sc_dvmnode; 11159191f35SAleksandr Rybalko struct cmn600_node *sc_xpnodes[64]; 11259191f35SAleksandr Rybalko int (*sc_pmu_ih)(struct trapframe *tf, int unit, int i); 11359191f35SAleksandr Rybalko }; 11459191f35SAleksandr Rybalko 11559191f35SAleksandr Rybalko static struct cmn600_pmc cmn600_pmcs[CMN600_UNIT_MAX]; 11659191f35SAleksandr Rybalko static int cmn600_npmcs = 0; 11759191f35SAleksandr Rybalko 11859191f35SAleksandr Rybalko static int cmn600_acpi_detach(device_t dev); 11959191f35SAleksandr Rybalko static int cmn600_intr(void *arg); 12059191f35SAleksandr Rybalko 12159191f35SAleksandr Rybalko static void 12259191f35SAleksandr Rybalko cmn600_pmc_register(int unit, void *arg, int domain) 12359191f35SAleksandr Rybalko { 12459191f35SAleksandr Rybalko 12559191f35SAleksandr Rybalko if (unit >= CMN600_UNIT_MAX) { 12659191f35SAleksandr Rybalko /* TODO */ 12759191f35SAleksandr Rybalko return; 12859191f35SAleksandr Rybalko } 12959191f35SAleksandr Rybalko 13059191f35SAleksandr Rybalko cmn600_pmcs[unit].arg = arg; 13159191f35SAleksandr Rybalko cmn600_pmcs[unit].domain = domain; 13259191f35SAleksandr Rybalko cmn600_npmcs++; 13359191f35SAleksandr Rybalko } 13459191f35SAleksandr Rybalko 13559191f35SAleksandr Rybalko static void 13659191f35SAleksandr Rybalko cmn600_pmc_unregister(int unit) 13759191f35SAleksandr Rybalko { 13859191f35SAleksandr Rybalko 13959191f35SAleksandr Rybalko cmn600_pmcs[unit].arg = NULL; 14059191f35SAleksandr Rybalko cmn600_npmcs--; 14159191f35SAleksandr Rybalko } 14259191f35SAleksandr Rybalko 14359191f35SAleksandr Rybalko int 14459191f35SAleksandr Rybalko cmn600_pmc_nunits(void) 14559191f35SAleksandr Rybalko { 14659191f35SAleksandr Rybalko 14759191f35SAleksandr Rybalko return (cmn600_npmcs); 14859191f35SAleksandr Rybalko } 14959191f35SAleksandr Rybalko 15059191f35SAleksandr Rybalko int 15159191f35SAleksandr Rybalko cmn600_pmc_getunit(int unit, void **arg, int *domain) 15259191f35SAleksandr Rybalko { 15359191f35SAleksandr Rybalko 15459191f35SAleksandr Rybalko if (unit >= cmn600_npmcs) 15559191f35SAleksandr Rybalko return (EINVAL); 15659191f35SAleksandr Rybalko if (cmn600_pmcs[unit].arg == NULL) 15759191f35SAleksandr Rybalko return (EINVAL); 15859191f35SAleksandr Rybalko *arg = cmn600_pmcs[unit].arg; 15959191f35SAleksandr Rybalko *domain = cmn600_pmcs[unit].domain; 16059191f35SAleksandr Rybalko return (0); 16159191f35SAleksandr Rybalko } 16259191f35SAleksandr Rybalko 16359191f35SAleksandr Rybalko int 16459191f35SAleksandr Rybalko pmu_cmn600_rev(void *arg) 16559191f35SAleksandr Rybalko { 16659191f35SAleksandr Rybalko struct cmn600_softc *sc; 16759191f35SAleksandr Rybalko 16859191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 16959191f35SAleksandr Rybalko switch (sc->sc_rev) { 17059191f35SAleksandr Rybalko case 0x0: 17159191f35SAleksandr Rybalko return (0x100); 17259191f35SAleksandr Rybalko case 0x1: 17359191f35SAleksandr Rybalko return (0x101); 17459191f35SAleksandr Rybalko case 0x2: 17559191f35SAleksandr Rybalko return (0x102); 17659191f35SAleksandr Rybalko case 0x3: 17759191f35SAleksandr Rybalko return (0x103); 17859191f35SAleksandr Rybalko case 0x4: 17959191f35SAleksandr Rybalko return (0x200); 18059191f35SAleksandr Rybalko case 0x5: 18159191f35SAleksandr Rybalko return (0x300); 18259191f35SAleksandr Rybalko case 0x6: 18359191f35SAleksandr Rybalko return (0x301); 18459191f35SAleksandr Rybalko } 18559191f35SAleksandr Rybalko return (0x302); /* Unknown revision. */ 18659191f35SAleksandr Rybalko } 18759191f35SAleksandr Rybalko 18859191f35SAleksandr Rybalko static uint64_t 18959191f35SAleksandr Rybalko cmn600_node_read8(struct cmn600_node *nd, uint32_t reg) 19059191f35SAleksandr Rybalko { 19159191f35SAleksandr Rybalko 19259191f35SAleksandr Rybalko return (RD8(nd->sc, nd->nd_offset + reg)); 19359191f35SAleksandr Rybalko } 19459191f35SAleksandr Rybalko 19559191f35SAleksandr Rybalko static void 19659191f35SAleksandr Rybalko cmn600_node_write8(struct cmn600_node *nd, uint32_t reg, uint64_t val) 19759191f35SAleksandr Rybalko { 19859191f35SAleksandr Rybalko 19959191f35SAleksandr Rybalko WR8(nd->sc, nd->nd_offset + reg, val); 20059191f35SAleksandr Rybalko } 20159191f35SAleksandr Rybalko 20259191f35SAleksandr Rybalko static uint32_t 20359191f35SAleksandr Rybalko cmn600_node_read4(struct cmn600_node *nd, uint32_t reg) 20459191f35SAleksandr Rybalko { 20559191f35SAleksandr Rybalko 20659191f35SAleksandr Rybalko return (RD4(nd->sc, nd->nd_offset + reg)); 20759191f35SAleksandr Rybalko } 20859191f35SAleksandr Rybalko 20959191f35SAleksandr Rybalko static void 21059191f35SAleksandr Rybalko cmn600_node_write4(struct cmn600_node *nd, uint32_t reg, uint32_t val) 21159191f35SAleksandr Rybalko { 21259191f35SAleksandr Rybalko 21359191f35SAleksandr Rybalko WR4(nd->sc, nd->nd_offset + reg, val); 21459191f35SAleksandr Rybalko } 21559191f35SAleksandr Rybalko 21659191f35SAleksandr Rybalko static const char * 21759191f35SAleksandr Rybalko cmn600_node_type_str(int type) 21859191f35SAleksandr Rybalko { 21959191f35SAleksandr Rybalko 22059191f35SAleksandr Rybalko #define NAME_OF(t, n) case NODE_TYPE_ ## t: return n 22159191f35SAleksandr Rybalko switch (type) { 22259191f35SAleksandr Rybalko NAME_OF(INVALID, "<invalid node>"); 22359191f35SAleksandr Rybalko NAME_OF(DVM, "DVM"); 22459191f35SAleksandr Rybalko NAME_OF(CFG, "CFG"); 22559191f35SAleksandr Rybalko NAME_OF(DTC, "DTC"); 22659191f35SAleksandr Rybalko NAME_OF(HN_I, "HN-I"); 22759191f35SAleksandr Rybalko NAME_OF(HN_F, "HN-F"); 22859191f35SAleksandr Rybalko NAME_OF(XP, "XP"); 22959191f35SAleksandr Rybalko NAME_OF(SBSX, "SBSX"); 23059191f35SAleksandr Rybalko NAME_OF(RN_I, "RN-I"); 23159191f35SAleksandr Rybalko NAME_OF(RN_D, "RN-D"); 23259191f35SAleksandr Rybalko NAME_OF(RN_SAM, "RN-SAM"); 23359191f35SAleksandr Rybalko NAME_OF(CXRA, "CXRA"); 23459191f35SAleksandr Rybalko NAME_OF(CXHA, "CXHA"); 23559191f35SAleksandr Rybalko NAME_OF(CXLA, "CXLA"); 23659191f35SAleksandr Rybalko default: 23759191f35SAleksandr Rybalko return "<unknown node>"; 23859191f35SAleksandr Rybalko } 23959191f35SAleksandr Rybalko #undef NAME_OF 24059191f35SAleksandr Rybalko } 24159191f35SAleksandr Rybalko 24259191f35SAleksandr Rybalko static const char * 24359191f35SAleksandr Rybalko cmn600_xpport_dev_type_str(uint8_t type) 24459191f35SAleksandr Rybalko { 24559191f35SAleksandr Rybalko 24659191f35SAleksandr Rybalko #define NAME_OF(t, n) case POR_MXP_PX_INFO_DEV_TYPE_ ## t: return n 24759191f35SAleksandr Rybalko switch (type) { 24859191f35SAleksandr Rybalko NAME_OF(RN_I, "RN-I"); 24959191f35SAleksandr Rybalko NAME_OF(RN_D, "RN-D"); 25059191f35SAleksandr Rybalko NAME_OF(RN_F_CHIB, "RN-F CHIB"); 25159191f35SAleksandr Rybalko NAME_OF(RN_F_CHIB_ESAM, "RN-F CHIB ESAM"); 25259191f35SAleksandr Rybalko NAME_OF(RN_F_CHIA, "RN-F CHIA"); 25359191f35SAleksandr Rybalko NAME_OF(RN_F_CHIA_ESAM, "RN-F CHIA ESAM"); 25459191f35SAleksandr Rybalko NAME_OF(HN_T, "HN-T"); 25559191f35SAleksandr Rybalko NAME_OF(HN_I, "HN-I"); 25659191f35SAleksandr Rybalko NAME_OF(HN_D, "HN-D"); 25759191f35SAleksandr Rybalko NAME_OF(SN_F, "SN-F"); 25859191f35SAleksandr Rybalko NAME_OF(SBSX, "SBSX"); 25959191f35SAleksandr Rybalko NAME_OF(HN_F, "HN-F"); 26059191f35SAleksandr Rybalko NAME_OF(CXHA, "CXHA"); 26159191f35SAleksandr Rybalko NAME_OF(CXRA, "CXRA"); 26259191f35SAleksandr Rybalko NAME_OF(CXRH, "CXRH"); 26359191f35SAleksandr Rybalko default: 26459191f35SAleksandr Rybalko return "<unknown>"; 26559191f35SAleksandr Rybalko } 26659191f35SAleksandr Rybalko #undef NAME_OF 26759191f35SAleksandr Rybalko } 26859191f35SAleksandr Rybalko 26959191f35SAleksandr Rybalko static void 27059191f35SAleksandr Rybalko cmn600_dump_node(struct cmn600_node *node, int lvl) 27159191f35SAleksandr Rybalko { 27259191f35SAleksandr Rybalko int i; 27359191f35SAleksandr Rybalko 27459191f35SAleksandr Rybalko for (i = 0; i < lvl; i++) printf(" "); 27559191f35SAleksandr Rybalko printf("%s [%dx%d:%d:%d] id: 0x%x @0x%lx Logical Id: 0x%x", 27659191f35SAleksandr Rybalko cmn600_node_type_str(node->nd_type), node->nd_x, node->nd_y, 27759191f35SAleksandr Rybalko node->nd_port, node->nd_sub, node->nd_id, node->nd_offset, 27859191f35SAleksandr Rybalko node->nd_logical_id); 27959191f35SAleksandr Rybalko if (node->nd_child_count > 0) 28059191f35SAleksandr Rybalko printf(", Children: %d", node->nd_child_count); 28159191f35SAleksandr Rybalko printf("\n"); 28259191f35SAleksandr Rybalko if (node->nd_type == NODE_TYPE_XP) 28359191f35SAleksandr Rybalko printf("\tPort 0: %s\n\tPort 1: %s\n", 28459191f35SAleksandr Rybalko cmn600_xpport_dev_type_str(node->nd_read4(node, 28559191f35SAleksandr Rybalko POR_MXP_P0_INFO) & 0x1f), 28659191f35SAleksandr Rybalko cmn600_xpport_dev_type_str(node->nd_read4(node, 28759191f35SAleksandr Rybalko POR_MXP_P1_INFO) & 0x1f)); 28859191f35SAleksandr Rybalko } 28959191f35SAleksandr Rybalko 29059191f35SAleksandr Rybalko static void 29159191f35SAleksandr Rybalko cmn600_dump_node_recursive(struct cmn600_node *node, int lvl) 29259191f35SAleksandr Rybalko { 29359191f35SAleksandr Rybalko int i; 29459191f35SAleksandr Rybalko 29559191f35SAleksandr Rybalko cmn600_dump_node(node, lvl); 29659191f35SAleksandr Rybalko for (i = 0; i < node->nd_child_count; i++) { 29759191f35SAleksandr Rybalko cmn600_dump_node_recursive(node->nd_children[i], lvl + 1); 29859191f35SAleksandr Rybalko } 29959191f35SAleksandr Rybalko } 30059191f35SAleksandr Rybalko 30159191f35SAleksandr Rybalko static void 30259191f35SAleksandr Rybalko cmn600_dump_nodes_tree(struct cmn600_softc *sc) 30359191f35SAleksandr Rybalko { 30459191f35SAleksandr Rybalko 30559191f35SAleksandr Rybalko device_printf(sc->sc_dev, " nodes:\n"); 30659191f35SAleksandr Rybalko cmn600_dump_node_recursive(sc->sc_rootnode, 0); 30759191f35SAleksandr Rybalko } 30859191f35SAleksandr Rybalko 30959191f35SAleksandr Rybalko static int 31059191f35SAleksandr Rybalko cmn600_sysctl_dump_nodes(SYSCTL_HANDLER_ARGS) 31159191f35SAleksandr Rybalko { 31259191f35SAleksandr Rybalko struct cmn600_softc *sc; 31359191f35SAleksandr Rybalko uint32_t val; 31459191f35SAleksandr Rybalko int err; 31559191f35SAleksandr Rybalko 31659191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg1; 31759191f35SAleksandr Rybalko val = 0; 31859191f35SAleksandr Rybalko err = sysctl_handle_int(oidp, &val, 0, req); 31959191f35SAleksandr Rybalko 32059191f35SAleksandr Rybalko if (err) 32159191f35SAleksandr Rybalko return (err); 32259191f35SAleksandr Rybalko 32359191f35SAleksandr Rybalko if (val != 0) 32459191f35SAleksandr Rybalko cmn600_dump_nodes_tree(sc); 32559191f35SAleksandr Rybalko 32659191f35SAleksandr Rybalko return (0); 32759191f35SAleksandr Rybalko } 32859191f35SAleksandr Rybalko 32959191f35SAleksandr Rybalko static struct cmn600_node * 33059191f35SAleksandr Rybalko cmn600_create_node(struct cmn600_softc *sc, off_t node_offset, 33159191f35SAleksandr Rybalko struct cmn600_node *parent, int lvl) 33259191f35SAleksandr Rybalko { 33359191f35SAleksandr Rybalko struct cmn600_node *node; 33459191f35SAleksandr Rybalko off_t child_offset; 33559191f35SAleksandr Rybalko uint64_t val; 33659191f35SAleksandr Rybalko int i; 33759191f35SAleksandr Rybalko 33859191f35SAleksandr Rybalko node = malloc(sizeof(struct cmn600_node), M_DEVBUF, M_WAITOK); 33959191f35SAleksandr Rybalko if (node == NULL) 34059191f35SAleksandr Rybalko return (NULL); 34159191f35SAleksandr Rybalko 34259191f35SAleksandr Rybalko node->sc = sc; 34359191f35SAleksandr Rybalko node->nd_offset = node_offset; 34459191f35SAleksandr Rybalko node->nd_parent = parent; 34559191f35SAleksandr Rybalko node->nd_read4 = cmn600_node_read4; 34659191f35SAleksandr Rybalko node->nd_read8 = cmn600_node_read8; 34759191f35SAleksandr Rybalko node->nd_write4 = cmn600_node_write4; 34859191f35SAleksandr Rybalko node->nd_write8 = cmn600_node_write8; 34959191f35SAleksandr Rybalko 35059191f35SAleksandr Rybalko val = node->nd_read8(node, POR_CFGM_NODE_INFO); 35159191f35SAleksandr Rybalko node->nd_type = FLD(val, POR_CFGM_NODE_INFO_NODE_TYPE); 35259191f35SAleksandr Rybalko node->nd_id = FLD(val, POR_CFGM_NODE_INFO_NODE_ID); 35359191f35SAleksandr Rybalko node->nd_logical_id = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID); 35459191f35SAleksandr Rybalko 35559191f35SAleksandr Rybalko val = node->nd_read8(node, POR_CFGM_CHILD_INFO); 35659191f35SAleksandr Rybalko node->nd_child_count = FLD(val, POR_CFGM_CHILD_INFO_CHILD_COUNT); 35759191f35SAleksandr Rybalko child_offset = FLD(val, POR_CFGM_CHILD_INFO_CHILD_PTR_OFFSET); 35859191f35SAleksandr Rybalko 35959191f35SAleksandr Rybalko if (parent == NULL) { 36059191f35SAleksandr Rybalko /* Find XP node with Id 8. It have to be last in a row. */ 36159191f35SAleksandr Rybalko for (i = 0; i < node->nd_child_count; i++) { 36259191f35SAleksandr Rybalko val = node->nd_read8(node, child_offset + (i * 8)); 36359191f35SAleksandr Rybalko val &= POR_CFGM_CHILD_POINTER_BASE_MASK; 36459191f35SAleksandr Rybalko val = RD8(sc, val + POR_CFGM_NODE_INFO); 36559191f35SAleksandr Rybalko 36659191f35SAleksandr Rybalko if (FLD(val, POR_CFGM_NODE_INFO_NODE_ID) != 8) 36759191f35SAleksandr Rybalko continue; 36859191f35SAleksandr Rybalko 36959191f35SAleksandr Rybalko sc->sc_mesh_x = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID); 37059191f35SAleksandr Rybalko sc->sc_mesh_y = node->nd_child_count / sc->sc_mesh_x; 37159191f35SAleksandr Rybalko if (bootverbose) 37259191f35SAleksandr Rybalko printf("Mesh width X/Y %d/%d\n", sc->sc_mesh_x, 37359191f35SAleksandr Rybalko sc->sc_mesh_y); 37459191f35SAleksandr Rybalko 37559191f35SAleksandr Rybalko if ((sc->sc_mesh_x > 4) || (sc->sc_mesh_y > 4)) 37659191f35SAleksandr Rybalko sc->sc_longid = 1; 37759191f35SAleksandr Rybalko break; 37859191f35SAleksandr Rybalko } 37959191f35SAleksandr Rybalko 38059191f35SAleksandr Rybalko val = node->nd_read8(node, POR_INFO_GLOBAL); 38159191f35SAleksandr Rybalko sc->sc_r2 = (val & POR_INFO_GLOBAL_R2_ENABLE) ? 1 : 0; 38259191f35SAleksandr Rybalko val = node->nd_read4(node, POR_CFGM_PERIPH_ID_2_PERIPH_ID_3); 38359191f35SAleksandr Rybalko sc->sc_rev = FLD(val, POR_CFGM_PERIPH_ID_2_REV); 38459191f35SAleksandr Rybalko if (bootverbose) 38559191f35SAleksandr Rybalko printf(" Rev: %d, R2_ENABLE = %s\n", sc->sc_rev, 38659191f35SAleksandr Rybalko sc->sc_r2 ? "true" : "false"); 38759191f35SAleksandr Rybalko } 38859191f35SAleksandr Rybalko node->nd_sub = FLD(node->nd_id, NODE_ID_SUB); 38959191f35SAleksandr Rybalko node->nd_port = FLD(node->nd_id, NODE_ID_PORT); 39059191f35SAleksandr Rybalko node->nd_paired = 0; 39159191f35SAleksandr Rybalko if (sc->sc_longid == 1) { 39259191f35SAleksandr Rybalko node->nd_x = FLD(node->nd_id, NODE_ID_X3B); 39359191f35SAleksandr Rybalko node->nd_y = FLD(node->nd_id, NODE_ID_Y3B); 39459191f35SAleksandr Rybalko } else { 39559191f35SAleksandr Rybalko node->nd_x = FLD(node->nd_id, NODE_ID_X2B); 39659191f35SAleksandr Rybalko node->nd_y = FLD(node->nd_id, NODE_ID_Y2B); 39759191f35SAleksandr Rybalko } 39859191f35SAleksandr Rybalko 39959191f35SAleksandr Rybalko if (bootverbose) { 40059191f35SAleksandr Rybalko cmn600_dump_node(node, lvl); 40159191f35SAleksandr Rybalko } 40259191f35SAleksandr Rybalko 40359191f35SAleksandr Rybalko node->nd_children = (struct cmn600_node **)mallocarray( 40459191f35SAleksandr Rybalko node->nd_child_count, sizeof(struct cmn600_node *), M_DEVBUF, 40559191f35SAleksandr Rybalko M_WAITOK); 40659191f35SAleksandr Rybalko if (node->nd_children == NULL) 40759191f35SAleksandr Rybalko goto FAIL; 40859191f35SAleksandr Rybalko for (i = 0; i < node->nd_child_count; i++) { 40959191f35SAleksandr Rybalko val = node->nd_read8(node, child_offset + (i * 8)); 41059191f35SAleksandr Rybalko node->nd_children[i] = cmn600_create_node(sc, val & 41159191f35SAleksandr Rybalko POR_CFGM_CHILD_POINTER_BASE_MASK, node, lvl + 1); 41259191f35SAleksandr Rybalko } 41359191f35SAleksandr Rybalko switch (node->nd_type) { 41459191f35SAleksandr Rybalko case NODE_TYPE_DTC: 41559191f35SAleksandr Rybalko sc->sc_dtcnode = node; 41659191f35SAleksandr Rybalko break; 41759191f35SAleksandr Rybalko case NODE_TYPE_DVM: 41859191f35SAleksandr Rybalko sc->sc_dvmnode = node; 41959191f35SAleksandr Rybalko break; 42059191f35SAleksandr Rybalko case NODE_TYPE_XP: 42159191f35SAleksandr Rybalko sc->sc_xpnodes[node->nd_id >> NODE_ID_X2B_SHIFT] = node; 42259191f35SAleksandr Rybalko break; 42359191f35SAleksandr Rybalko default: 42459191f35SAleksandr Rybalko break; 42559191f35SAleksandr Rybalko } 42659191f35SAleksandr Rybalko return (node); 42759191f35SAleksandr Rybalko FAIL: 42859191f35SAleksandr Rybalko free(node, M_DEVBUF); 42959191f35SAleksandr Rybalko return (NULL); 43059191f35SAleksandr Rybalko } 43159191f35SAleksandr Rybalko 43259191f35SAleksandr Rybalko static void 43359191f35SAleksandr Rybalko cmn600_destroy_node(struct cmn600_node *node) 43459191f35SAleksandr Rybalko { 43559191f35SAleksandr Rybalko int i; 43659191f35SAleksandr Rybalko 43759191f35SAleksandr Rybalko for (i = 0; i < node->nd_child_count; i++) { 43859191f35SAleksandr Rybalko if (node->nd_children[i] == NULL) 43959191f35SAleksandr Rybalko continue; 44059191f35SAleksandr Rybalko cmn600_destroy_node(node->nd_children[i]); 44159191f35SAleksandr Rybalko } 44259191f35SAleksandr Rybalko free(node->nd_children, M_DEVBUF); 44359191f35SAleksandr Rybalko free(node, M_DEVBUF); 44459191f35SAleksandr Rybalko } 44559191f35SAleksandr Rybalko 44659191f35SAleksandr Rybalko static int 44759191f35SAleksandr Rybalko cmn600_find_node(struct cmn600_softc *sc, int node_id, int type, 44859191f35SAleksandr Rybalko struct cmn600_node **node) 44959191f35SAleksandr Rybalko { 45059191f35SAleksandr Rybalko struct cmn600_node *xp, *child; 45159191f35SAleksandr Rybalko uint8_t xp_xy; 45259191f35SAleksandr Rybalko int i; 45359191f35SAleksandr Rybalko 45459191f35SAleksandr Rybalko switch (type) { 45559191f35SAleksandr Rybalko case NODE_TYPE_INVALID: 45659191f35SAleksandr Rybalko return (ENXIO); 45759191f35SAleksandr Rybalko case NODE_TYPE_CFG: 45859191f35SAleksandr Rybalko *node = sc->sc_rootnode; 45959191f35SAleksandr Rybalko return (0); 46059191f35SAleksandr Rybalko case NODE_TYPE_DTC: 46159191f35SAleksandr Rybalko *node = sc->sc_dtcnode; 46259191f35SAleksandr Rybalko return (0); 46359191f35SAleksandr Rybalko case NODE_TYPE_DVM: 46459191f35SAleksandr Rybalko *node = sc->sc_dvmnode; 46559191f35SAleksandr Rybalko return (0); 46659191f35SAleksandr Rybalko default: 46759191f35SAleksandr Rybalko break; 46859191f35SAleksandr Rybalko } 46959191f35SAleksandr Rybalko 47059191f35SAleksandr Rybalko xp_xy = node_id >> NODE_ID_X2B_SHIFT; 47159191f35SAleksandr Rybalko if (xp_xy >= 64) 47259191f35SAleksandr Rybalko return (ENXIO); 47359191f35SAleksandr Rybalko if (sc->sc_xpnodes[xp_xy] == NULL) 47459191f35SAleksandr Rybalko return (ENOENT); 47559191f35SAleksandr Rybalko 47659191f35SAleksandr Rybalko switch (type) { 47759191f35SAleksandr Rybalko case NODE_TYPE_XP: 47859191f35SAleksandr Rybalko *node = sc->sc_xpnodes[xp_xy]; 47959191f35SAleksandr Rybalko return (0); 48059191f35SAleksandr Rybalko default: 48159191f35SAleksandr Rybalko xp = sc->sc_xpnodes[xp_xy]; 48259191f35SAleksandr Rybalko for (i = 0; i < xp->nd_child_count; i++) { 48359191f35SAleksandr Rybalko child = xp->nd_children[i]; 48459191f35SAleksandr Rybalko if (child->nd_id == node_id && child->nd_type == type) { 48559191f35SAleksandr Rybalko *node = child; 48659191f35SAleksandr Rybalko return (0); 48759191f35SAleksandr Rybalko } 48859191f35SAleksandr Rybalko } 48959191f35SAleksandr Rybalko } 49059191f35SAleksandr Rybalko return (ENOENT); 49159191f35SAleksandr Rybalko } 49259191f35SAleksandr Rybalko 49359191f35SAleksandr Rybalko int 49459191f35SAleksandr Rybalko pmu_cmn600_alloc_localpmc(void *arg, int nodeid, int node_type, int *counter) 49559191f35SAleksandr Rybalko { 49659191f35SAleksandr Rybalko struct cmn600_node *node; 49759191f35SAleksandr Rybalko struct cmn600_softc *sc; 49859191f35SAleksandr Rybalko uint32_t new, old; 49959191f35SAleksandr Rybalko int i, ret; 50059191f35SAleksandr Rybalko 50159191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 50259191f35SAleksandr Rybalko switch (node_type) { 50359191f35SAleksandr Rybalko case NODE_TYPE_CXLA: 50459191f35SAleksandr Rybalko break; 50559191f35SAleksandr Rybalko default: 50659191f35SAleksandr Rybalko node_type = NODE_TYPE_XP; 50759191f35SAleksandr Rybalko /* Parent XP node has always zero port and device bits. */ 50859191f35SAleksandr Rybalko nodeid &= ~0x07; 50959191f35SAleksandr Rybalko } 51059191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 51159191f35SAleksandr Rybalko if (ret != 0) 51259191f35SAleksandr Rybalko return (ret); 51359191f35SAleksandr Rybalko for (i = 0; i < 4; i++) { 51459191f35SAleksandr Rybalko new = old = node->nd_paired; 51559191f35SAleksandr Rybalko if (old == 0xf) 51659191f35SAleksandr Rybalko return (EBUSY); 51759191f35SAleksandr Rybalko if ((old & (1 << i)) != 0) 51859191f35SAleksandr Rybalko continue; 51959191f35SAleksandr Rybalko new |= 1 << i; 52059191f35SAleksandr Rybalko if (atomic_cmpset_32(&node->nd_paired, old, new) != 0) 52159191f35SAleksandr Rybalko break; 52259191f35SAleksandr Rybalko } 52359191f35SAleksandr Rybalko *counter = i; 52459191f35SAleksandr Rybalko return (0); 52559191f35SAleksandr Rybalko } 52659191f35SAleksandr Rybalko 52759191f35SAleksandr Rybalko int 52859191f35SAleksandr Rybalko pmu_cmn600_free_localpmc(void *arg, int nodeid, int node_type, int counter) 52959191f35SAleksandr Rybalko { 53059191f35SAleksandr Rybalko struct cmn600_node *node; 53159191f35SAleksandr Rybalko struct cmn600_softc *sc; 53259191f35SAleksandr Rybalko uint32_t new, old; 53359191f35SAleksandr Rybalko int ret; 53459191f35SAleksandr Rybalko 53559191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 53659191f35SAleksandr Rybalko switch (node_type) { 53759191f35SAleksandr Rybalko case NODE_TYPE_CXLA: 53859191f35SAleksandr Rybalko break; 53959191f35SAleksandr Rybalko default: 54059191f35SAleksandr Rybalko node_type = NODE_TYPE_XP; 54159191f35SAleksandr Rybalko } 54259191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 54359191f35SAleksandr Rybalko if (ret != 0) 54459191f35SAleksandr Rybalko return (ret); 54559191f35SAleksandr Rybalko 54659191f35SAleksandr Rybalko do { 54759191f35SAleksandr Rybalko new = old = node->nd_paired; 54859191f35SAleksandr Rybalko new &= ~(1 << counter); 54959191f35SAleksandr Rybalko } while (atomic_cmpset_32(&node->nd_paired, old, new) == 0); 55059191f35SAleksandr Rybalko return (0); 55159191f35SAleksandr Rybalko } 55259191f35SAleksandr Rybalko 55359191f35SAleksandr Rybalko uint32_t 55459191f35SAleksandr Rybalko pmu_cmn600_rd4(void *arg, int nodeid, int node_type, off_t reg) 55559191f35SAleksandr Rybalko { 55659191f35SAleksandr Rybalko struct cmn600_node *node; 55759191f35SAleksandr Rybalko struct cmn600_softc *sc; 55859191f35SAleksandr Rybalko int ret; 55959191f35SAleksandr Rybalko 56059191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 56159191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 56259191f35SAleksandr Rybalko if (ret != 0) 56359191f35SAleksandr Rybalko return (UINT32_MAX); 56459191f35SAleksandr Rybalko return (cmn600_node_read4(node, reg)); 56559191f35SAleksandr Rybalko } 56659191f35SAleksandr Rybalko 56759191f35SAleksandr Rybalko int 56859191f35SAleksandr Rybalko pmu_cmn600_wr4(void *arg, int nodeid, int node_type, off_t reg, uint32_t val) 56959191f35SAleksandr Rybalko { 57059191f35SAleksandr Rybalko struct cmn600_node *node; 57159191f35SAleksandr Rybalko struct cmn600_softc *sc; 57259191f35SAleksandr Rybalko int ret; 57359191f35SAleksandr Rybalko 57459191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 57559191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 57659191f35SAleksandr Rybalko if (ret != 0) 57759191f35SAleksandr Rybalko return (ret); 57859191f35SAleksandr Rybalko cmn600_node_write4(node, reg, val); 57959191f35SAleksandr Rybalko return (0); 58059191f35SAleksandr Rybalko } 58159191f35SAleksandr Rybalko 58259191f35SAleksandr Rybalko uint64_t 58359191f35SAleksandr Rybalko pmu_cmn600_rd8(void *arg, int nodeid, int node_type, off_t reg) 58459191f35SAleksandr Rybalko { 58559191f35SAleksandr Rybalko struct cmn600_node *node; 58659191f35SAleksandr Rybalko struct cmn600_softc *sc; 58759191f35SAleksandr Rybalko int ret; 58859191f35SAleksandr Rybalko 58959191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 59059191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 59159191f35SAleksandr Rybalko if (ret != 0) 59259191f35SAleksandr Rybalko return (UINT64_MAX); 59359191f35SAleksandr Rybalko return (cmn600_node_read8(node, reg)); 59459191f35SAleksandr Rybalko } 59559191f35SAleksandr Rybalko 59659191f35SAleksandr Rybalko int 59759191f35SAleksandr Rybalko pmu_cmn600_wr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) 59859191f35SAleksandr Rybalko { 59959191f35SAleksandr Rybalko struct cmn600_node *node; 60059191f35SAleksandr Rybalko struct cmn600_softc *sc; 60159191f35SAleksandr Rybalko int ret; 60259191f35SAleksandr Rybalko 60359191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 60459191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 60559191f35SAleksandr Rybalko if (ret != 0) 60659191f35SAleksandr Rybalko return (ret); 60759191f35SAleksandr Rybalko cmn600_node_write8(node, reg, val); 60859191f35SAleksandr Rybalko return (0); 60959191f35SAleksandr Rybalko } 61059191f35SAleksandr Rybalko 61159191f35SAleksandr Rybalko int 61259191f35SAleksandr Rybalko pmu_cmn600_set8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) 61359191f35SAleksandr Rybalko { 61459191f35SAleksandr Rybalko struct cmn600_node *node; 61559191f35SAleksandr Rybalko struct cmn600_softc *sc; 61659191f35SAleksandr Rybalko int ret; 61759191f35SAleksandr Rybalko 61859191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 61959191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 62059191f35SAleksandr Rybalko if (ret != 0) 62159191f35SAleksandr Rybalko return (ret); 62259191f35SAleksandr Rybalko cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) | val); 62359191f35SAleksandr Rybalko return (0); 62459191f35SAleksandr Rybalko } 62559191f35SAleksandr Rybalko 62659191f35SAleksandr Rybalko int 62759191f35SAleksandr Rybalko pmu_cmn600_clr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) 62859191f35SAleksandr Rybalko { 62959191f35SAleksandr Rybalko struct cmn600_node *node; 63059191f35SAleksandr Rybalko struct cmn600_softc *sc; 63159191f35SAleksandr Rybalko int ret; 63259191f35SAleksandr Rybalko 63359191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 63459191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 63559191f35SAleksandr Rybalko if (ret != 0) 63659191f35SAleksandr Rybalko return (ret); 63759191f35SAleksandr Rybalko cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) & ~val); 63859191f35SAleksandr Rybalko return (0); 63959191f35SAleksandr Rybalko } 64059191f35SAleksandr Rybalko 64159191f35SAleksandr Rybalko int 64259191f35SAleksandr Rybalko pmu_cmn600_md8(void *arg, int nodeid, int node_type, off_t reg, uint64_t mask, 64359191f35SAleksandr Rybalko uint64_t val) 64459191f35SAleksandr Rybalko { 64559191f35SAleksandr Rybalko struct cmn600_node *node; 64659191f35SAleksandr Rybalko struct cmn600_softc *sc; 64759191f35SAleksandr Rybalko int ret; 64859191f35SAleksandr Rybalko 64959191f35SAleksandr Rybalko sc = (struct cmn600_softc *)arg; 65059191f35SAleksandr Rybalko ret = cmn600_find_node(sc, nodeid, node_type, &node); 65159191f35SAleksandr Rybalko if (ret != 0) 65259191f35SAleksandr Rybalko return (ret); 65359191f35SAleksandr Rybalko cmn600_node_write8(node, reg, (cmn600_node_read8(node, reg) & ~mask) | 65459191f35SAleksandr Rybalko val); 65559191f35SAleksandr Rybalko return (0); 65659191f35SAleksandr Rybalko } 65759191f35SAleksandr Rybalko 65859191f35SAleksandr Rybalko static int 65959191f35SAleksandr Rybalko cmn600_acpi_probe(device_t dev) 66059191f35SAleksandr Rybalko { 66159191f35SAleksandr Rybalko int err; 66259191f35SAleksandr Rybalko 66359191f35SAleksandr Rybalko err = ACPI_ID_PROBE(device_get_parent(dev), dev, cmn600_ids, NULL); 66459191f35SAleksandr Rybalko if (err <= 0) 66559191f35SAleksandr Rybalko device_set_desc(dev, "Arm CoreLink CMN-600 Coherent Mesh Network"); 66659191f35SAleksandr Rybalko 66759191f35SAleksandr Rybalko return (err); 66859191f35SAleksandr Rybalko } 66959191f35SAleksandr Rybalko 67059191f35SAleksandr Rybalko static int 67159191f35SAleksandr Rybalko cmn600_acpi_attach(device_t dev) 67259191f35SAleksandr Rybalko { 67359191f35SAleksandr Rybalko struct sysctl_ctx_list *ctx; 67459191f35SAleksandr Rybalko struct sysctl_oid_list *child; 67559191f35SAleksandr Rybalko struct cmn600_softc *sc; 67659191f35SAleksandr Rybalko int cpu, domain, i, u; 67759191f35SAleksandr Rybalko const char *dname; 67859191f35SAleksandr Rybalko rman_res_t count, periph_base, rootnode_base; 67959191f35SAleksandr Rybalko struct cmn600_node *node; 68059191f35SAleksandr Rybalko 68159191f35SAleksandr Rybalko dname = device_get_name(dev); 68259191f35SAleksandr Rybalko sc = device_get_softc(dev); 68359191f35SAleksandr Rybalko sc->sc_dev = dev; 68459191f35SAleksandr Rybalko u = device_get_unit(dev); 68559191f35SAleksandr Rybalko sc->sc_unit = u; 68659191f35SAleksandr Rybalko domain = 0; 68759191f35SAleksandr Rybalko 68859191f35SAleksandr Rybalko if ((resource_int_value(dname, u, "domain", &domain) == 0 || 68959191f35SAleksandr Rybalko bus_get_domain(dev, &domain) == 0) && domain < MAXMEMDOM) { 69059191f35SAleksandr Rybalko sc->sc_domain = domain; 69159191f35SAleksandr Rybalko } 69259191f35SAleksandr Rybalko if (domain == -1) /* NUMA not supported. Use single domain. */ 69359191f35SAleksandr Rybalko domain = 0; 69459191f35SAleksandr Rybalko sc->sc_domain = domain; 69559191f35SAleksandr Rybalko device_printf(dev, "domain=%d\n", sc->sc_domain); 69659191f35SAleksandr Rybalko 69759191f35SAleksandr Rybalko cpu = CPU_FFS(&cpuset_domain[domain]) - 1; 69859191f35SAleksandr Rybalko 69959191f35SAleksandr Rybalko i = bus_alloc_resources(dev, cmn600_res_spec, sc->sc_res); 70059191f35SAleksandr Rybalko if (i != 0) { 70159191f35SAleksandr Rybalko device_printf(dev, "cannot allocate resources for device (%d)\n", 70259191f35SAleksandr Rybalko i); 70359191f35SAleksandr Rybalko return (i); 70459191f35SAleksandr Rybalko } 70559191f35SAleksandr Rybalko 70659191f35SAleksandr Rybalko bus_get_resource(dev, cmn600_res_spec[0].type, cmn600_res_spec[0].rid, 70759191f35SAleksandr Rybalko &periph_base, &count); 70859191f35SAleksandr Rybalko bus_get_resource(dev, cmn600_res_spec[1].type, cmn600_res_spec[1].rid, 70959191f35SAleksandr Rybalko &rootnode_base, &count); 71059191f35SAleksandr Rybalko rootnode_base -= periph_base; 71159191f35SAleksandr Rybalko if (bootverbose) 71259191f35SAleksandr Rybalko printf("ROOTNODE at %lx x %lx\n", rootnode_base, count); 71359191f35SAleksandr Rybalko 71459191f35SAleksandr Rybalko sc->sc_rootnode = cmn600_create_node(sc, rootnode_base, NULL, 0); 71559191f35SAleksandr Rybalko ctx = device_get_sysctl_ctx(sc->sc_dev); 71659191f35SAleksandr Rybalko 71759191f35SAleksandr Rybalko child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); 71859191f35SAleksandr Rybalko SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dump_nodes", CTLTYPE_INT | 71959191f35SAleksandr Rybalko CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, cmn600_sysctl_dump_nodes, 72059191f35SAleksandr Rybalko "U", "Dump CMN-600 nodes tree"); 72159191f35SAleksandr Rybalko 72259191f35SAleksandr Rybalko node = sc->sc_dtcnode; 72359191f35SAleksandr Rybalko if (node == NULL) 72459191f35SAleksandr Rybalko return (ENXIO); 72559191f35SAleksandr Rybalko 72659191f35SAleksandr Rybalko cmn600_pmc_register(sc->sc_unit, (void *)sc, domain); 72759191f35SAleksandr Rybalko 72859191f35SAleksandr Rybalko node->nd_write8(node, POR_DT_PMCR, 0); 72959191f35SAleksandr Rybalko node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL); 73059191f35SAleksandr Rybalko node->nd_write8(node, POR_DT_PMCR, POR_DT_PMCR_OVFL_INTR_EN); 73159191f35SAleksandr Rybalko node->nd_write8(node, POR_DT_DTC_CTL, POR_DT_DTC_CTL_DT_EN); 73259191f35SAleksandr Rybalko 73359191f35SAleksandr Rybalko if (bus_setup_intr(dev, sc->sc_res[2], INTR_TYPE_MISC | INTR_MPSAFE, 73459191f35SAleksandr Rybalko cmn600_intr, NULL, sc, &sc->sc_ih)) { 73559191f35SAleksandr Rybalko bus_release_resources(dev, cmn600_res_spec, sc->sc_res); 73659191f35SAleksandr Rybalko device_printf(dev, "cannot setup interrupt handler\n"); 73759191f35SAleksandr Rybalko cmn600_acpi_detach(dev); 73859191f35SAleksandr Rybalko return (ENXIO); 73959191f35SAleksandr Rybalko } 74059191f35SAleksandr Rybalko if (bus_bind_intr(dev, sc->sc_res[2], cpu)) { 74159191f35SAleksandr Rybalko bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih); 74259191f35SAleksandr Rybalko bus_release_resources(dev, cmn600_res_spec, sc->sc_res); 74359191f35SAleksandr Rybalko device_printf(dev, "cannot setup interrupt handler\n"); 74459191f35SAleksandr Rybalko cmn600_acpi_detach(dev); 74559191f35SAleksandr Rybalko return (ENXIO); 74659191f35SAleksandr Rybalko } 74759191f35SAleksandr Rybalko return (0); 74859191f35SAleksandr Rybalko } 74959191f35SAleksandr Rybalko 75059191f35SAleksandr Rybalko static int 75159191f35SAleksandr Rybalko cmn600_acpi_detach(device_t dev) 75259191f35SAleksandr Rybalko { 75359191f35SAleksandr Rybalko struct cmn600_softc *sc; 75459191f35SAleksandr Rybalko struct cmn600_node *node; 75559191f35SAleksandr Rybalko 75659191f35SAleksandr Rybalko sc = device_get_softc(dev); 75759191f35SAleksandr Rybalko if (sc->sc_res[2] != NULL) { 75859191f35SAleksandr Rybalko bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih); 75959191f35SAleksandr Rybalko } 76059191f35SAleksandr Rybalko 76159191f35SAleksandr Rybalko node = sc->sc_dtcnode; 76259191f35SAleksandr Rybalko node->nd_write4(node, POR_DT_DTC_CTL, 76359191f35SAleksandr Rybalko node->nd_read4(node, POR_DT_DTC_CTL) & ~POR_DT_DTC_CTL_DT_EN); 76459191f35SAleksandr Rybalko node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL); 76559191f35SAleksandr Rybalko 76659191f35SAleksandr Rybalko cmn600_pmc_unregister(sc->sc_unit); 76759191f35SAleksandr Rybalko cmn600_destroy_node(sc->sc_rootnode); 76859191f35SAleksandr Rybalko bus_release_resources(dev, cmn600_res_spec, sc->sc_res); 76959191f35SAleksandr Rybalko 77059191f35SAleksandr Rybalko return (0); 77159191f35SAleksandr Rybalko } 77259191f35SAleksandr Rybalko 77359191f35SAleksandr Rybalko int 77459191f35SAleksandr Rybalko cmn600_pmu_intr_cb(void *arg, int (*handler)(struct trapframe *tf, int unit, 77559191f35SAleksandr Rybalko int i)) 77659191f35SAleksandr Rybalko { 77759191f35SAleksandr Rybalko struct cmn600_softc *sc; 77859191f35SAleksandr Rybalko 77959191f35SAleksandr Rybalko sc = (struct cmn600_softc *) arg; 78059191f35SAleksandr Rybalko sc->sc_pmu_ih = handler; 78159191f35SAleksandr Rybalko return (0); 78259191f35SAleksandr Rybalko } 78359191f35SAleksandr Rybalko 78459191f35SAleksandr Rybalko static int 78559191f35SAleksandr Rybalko cmn600_intr(void *arg) 78659191f35SAleksandr Rybalko { 78759191f35SAleksandr Rybalko struct cmn600_node *node; 78859191f35SAleksandr Rybalko struct cmn600_softc *sc; 78959191f35SAleksandr Rybalko struct trapframe *tf; 79059191f35SAleksandr Rybalko uint64_t mask, ready, val; 79159191f35SAleksandr Rybalko int i; 79259191f35SAleksandr Rybalko 79359191f35SAleksandr Rybalko tf = PCPU_GET(curthread)->td_intr_frame; 79459191f35SAleksandr Rybalko sc = (struct cmn600_softc *) arg; 79559191f35SAleksandr Rybalko node = sc->sc_dtcnode; 79659191f35SAleksandr Rybalko val = node->nd_read8(node, POR_DT_PMOVSR); 79759191f35SAleksandr Rybalko if (val & POR_DT_PMOVSR_CYCLE_COUNTER) 79859191f35SAleksandr Rybalko node->nd_write8(node, POR_DT_PMOVSR_CLR, 79959191f35SAleksandr Rybalko POR_DT_PMOVSR_CYCLE_COUNTER); 80059191f35SAleksandr Rybalko if (val & POR_DT_PMOVSR_EVENT_COUNTERS) { 80159191f35SAleksandr Rybalko for (ready = 0, i = 0; i < 8; i++) { 80259191f35SAleksandr Rybalko mask = 1 << i; 80359191f35SAleksandr Rybalko if ((val & mask) == 0) 80459191f35SAleksandr Rybalko continue; 80559191f35SAleksandr Rybalko if (sc->sc_pmu_ih != NULL) 80659191f35SAleksandr Rybalko sc->sc_pmu_ih(tf, sc->sc_unit, i); 80759191f35SAleksandr Rybalko ready |= mask; 80859191f35SAleksandr Rybalko 80959191f35SAleksandr Rybalko } 81059191f35SAleksandr Rybalko node->nd_write8(node, POR_DT_PMOVSR_CLR, ready); 81159191f35SAleksandr Rybalko } 81259191f35SAleksandr Rybalko 81359191f35SAleksandr Rybalko return (FILTER_HANDLED); 81459191f35SAleksandr Rybalko } 81559191f35SAleksandr Rybalko 81659191f35SAleksandr Rybalko static device_method_t cmn600_acpi_methods[] = { 81759191f35SAleksandr Rybalko /* Device interface */ 81859191f35SAleksandr Rybalko DEVMETHOD(device_probe, cmn600_acpi_probe), 81959191f35SAleksandr Rybalko DEVMETHOD(device_attach, cmn600_acpi_attach), 82059191f35SAleksandr Rybalko DEVMETHOD(device_detach, cmn600_acpi_detach), 82159191f35SAleksandr Rybalko 82259191f35SAleksandr Rybalko /* End */ 82359191f35SAleksandr Rybalko DEVMETHOD_END 82459191f35SAleksandr Rybalko }; 82559191f35SAleksandr Rybalko 82659191f35SAleksandr Rybalko static driver_t cmn600_acpi_driver = { 82759191f35SAleksandr Rybalko "cmn600", 82859191f35SAleksandr Rybalko cmn600_acpi_methods, 82959191f35SAleksandr Rybalko sizeof(struct cmn600_softc), 83059191f35SAleksandr Rybalko }; 83159191f35SAleksandr Rybalko 8329a777495SJohn Baldwin DRIVER_MODULE(cmn600, acpi, cmn600_acpi_driver, 0, 0); 83359191f35SAleksandr Rybalko MODULE_VERSION(cmn600, 1); 834