1e1453c9eSEmmanuel Vadot /*- 2e1453c9eSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3e1453c9eSEmmanuel Vadot * 4e1453c9eSEmmanuel Vadot * Copyright (c) 2018 Rubicon Communications, LLC (Netgate) 5e1453c9eSEmmanuel Vadot * 6e1453c9eSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 7e1453c9eSEmmanuel Vadot * modification, are permitted provided that the following conditions 8e1453c9eSEmmanuel Vadot * are met: 9e1453c9eSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 10e1453c9eSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 11e1453c9eSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 12e1453c9eSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 13e1453c9eSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 14e1453c9eSEmmanuel Vadot * 15e1453c9eSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16e1453c9eSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e1453c9eSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e1453c9eSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19e1453c9eSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e1453c9eSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e1453c9eSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e1453c9eSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e1453c9eSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e1453c9eSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e1453c9eSEmmanuel Vadot * SUCH DAMAGE. 26e1453c9eSEmmanuel Vadot * 27e1453c9eSEmmanuel Vadot * $FreeBSD$ 28e1453c9eSEmmanuel Vadot */ 29e1453c9eSEmmanuel Vadot 30e1453c9eSEmmanuel Vadot #include <sys/cdefs.h> 31e1453c9eSEmmanuel Vadot __FBSDID("$FreeBSD$"); 32e1453c9eSEmmanuel Vadot 33e1453c9eSEmmanuel Vadot #include <sys/param.h> 34e1453c9eSEmmanuel Vadot #include <sys/systm.h> 35e1453c9eSEmmanuel Vadot #include <sys/bus.h> 36e1453c9eSEmmanuel Vadot 37e1453c9eSEmmanuel Vadot #include <sys/kernel.h> 38e1453c9eSEmmanuel Vadot #include <sys/module.h> 39e1453c9eSEmmanuel Vadot #include <sys/rman.h> 40e1453c9eSEmmanuel Vadot #include <sys/lock.h> 41e1453c9eSEmmanuel Vadot #include <sys/mutex.h> 42e1453c9eSEmmanuel Vadot 43e1453c9eSEmmanuel Vadot #include <machine/bus.h> 44e1453c9eSEmmanuel Vadot #include <machine/resource.h> 45e1453c9eSEmmanuel Vadot #include <machine/intr.h> 46e1453c9eSEmmanuel Vadot 474b84206bSMichal Meloun #include <dev/extres/clk/clk_fixed.h> 484b84206bSMichal Meloun #include <dev/extres/syscon/syscon.h> 49e1453c9eSEmmanuel Vadot 50e1453c9eSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 51e1453c9eSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 52e1453c9eSEmmanuel Vadot 534b84206bSMichal Meloun #include "syscon_if.h" 54e1453c9eSEmmanuel Vadot 55e1453c9eSEmmanuel Vadot static struct clk_fixed_def ap806_clk_cluster_0 = { 56e1453c9eSEmmanuel Vadot .clkdef.id = 0, 57e1453c9eSEmmanuel Vadot .clkdef.name = "ap806-cpu-cluster-0", 58e1453c9eSEmmanuel Vadot .freq = 0, 59e1453c9eSEmmanuel Vadot }; 60e1453c9eSEmmanuel Vadot 61e1453c9eSEmmanuel Vadot static struct clk_fixed_def ap806_clk_cluster_1 = { 62e1453c9eSEmmanuel Vadot .clkdef.id = 1, 63e1453c9eSEmmanuel Vadot .clkdef.name = "ap806-cpu-cluster-1", 64e1453c9eSEmmanuel Vadot .freq = 0, 65e1453c9eSEmmanuel Vadot }; 66e1453c9eSEmmanuel Vadot 67e1453c9eSEmmanuel Vadot static struct clk_fixed_def ap806_clk_fixed = { 68e1453c9eSEmmanuel Vadot .clkdef.id = 2, 69e1453c9eSEmmanuel Vadot .clkdef.name = "ap806-fixed", 70e1453c9eSEmmanuel Vadot .freq = 1200000000, 71e1453c9eSEmmanuel Vadot }; 72e1453c9eSEmmanuel Vadot 73e1453c9eSEmmanuel Vadot /* Thoses are the only exported clocks AFAICT */ 74e1453c9eSEmmanuel Vadot 75e1453c9eSEmmanuel Vadot static const char *mss_parents[] = {"ap806-fixed"}; 76e1453c9eSEmmanuel Vadot static struct clk_fixed_def ap806_clk_mss = { 77e1453c9eSEmmanuel Vadot .clkdef.id = 3, 78e1453c9eSEmmanuel Vadot .clkdef.name = "ap806-mss", 79e1453c9eSEmmanuel Vadot .clkdef.parent_names = mss_parents, 80e1453c9eSEmmanuel Vadot .clkdef.parent_cnt = 1, 81e1453c9eSEmmanuel Vadot .mult = 1, 82e1453c9eSEmmanuel Vadot .div = 6, 83e1453c9eSEmmanuel Vadot }; 84e1453c9eSEmmanuel Vadot 85e1453c9eSEmmanuel Vadot static const char *sdio_parents[] = {"ap806-fixed"}; 86e1453c9eSEmmanuel Vadot static struct clk_fixed_def ap806_clk_sdio = { 87e1453c9eSEmmanuel Vadot .clkdef.id = 4, 88e1453c9eSEmmanuel Vadot .clkdef.name = "ap806-sdio", 89e1453c9eSEmmanuel Vadot .clkdef.parent_names = sdio_parents, 90e1453c9eSEmmanuel Vadot .clkdef.parent_cnt = 1, 91e1453c9eSEmmanuel Vadot .mult = 1, 92e1453c9eSEmmanuel Vadot .div = 3, 93e1453c9eSEmmanuel Vadot }; 94e1453c9eSEmmanuel Vadot 95e1453c9eSEmmanuel Vadot struct mv_ap806_clock_softc { 96e1453c9eSEmmanuel Vadot device_t dev; 974b84206bSMichal Meloun struct syscon *syscon; 98e1453c9eSEmmanuel Vadot }; 99e1453c9eSEmmanuel Vadot 100e1453c9eSEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 101e1453c9eSEmmanuel Vadot {"marvell,ap806-clock", 1}, 102e1453c9eSEmmanuel Vadot {NULL, 0} 103e1453c9eSEmmanuel Vadot }; 104e1453c9eSEmmanuel Vadot 1054b84206bSMichal Meloun #define RD4(sc, reg) SYSCON_READ_4((sc)->syscon, (reg)) 1064b84206bSMichal Meloun #define WR4(sc, reg, val) SYSCON_WRITE_4((sc)->syscon, (reg), (val)) 107e1453c9eSEmmanuel Vadot 108e1453c9eSEmmanuel Vadot static int 109e1453c9eSEmmanuel Vadot mv_ap806_clock_probe(device_t dev) 110e1453c9eSEmmanuel Vadot { 111e1453c9eSEmmanuel Vadot 112e1453c9eSEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 113e1453c9eSEmmanuel Vadot return (ENXIO); 114e1453c9eSEmmanuel Vadot 115e1453c9eSEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 116e1453c9eSEmmanuel Vadot return (ENXIO); 117e1453c9eSEmmanuel Vadot 118e1453c9eSEmmanuel Vadot device_set_desc(dev, "Marvell AP806 Clock Controller"); 119e1453c9eSEmmanuel Vadot return (BUS_PROBE_DEFAULT); 120e1453c9eSEmmanuel Vadot } 121e1453c9eSEmmanuel Vadot 122e1453c9eSEmmanuel Vadot static int 123e1453c9eSEmmanuel Vadot mv_ap806_clock_attach(device_t dev) 124e1453c9eSEmmanuel Vadot { 125e1453c9eSEmmanuel Vadot struct mv_ap806_clock_softc *sc; 126e1453c9eSEmmanuel Vadot struct clkdom *clkdom; 127e1453c9eSEmmanuel Vadot uint64_t clock_freq; 128e1453c9eSEmmanuel Vadot uint32_t reg; 129e1453c9eSEmmanuel Vadot 130e1453c9eSEmmanuel Vadot sc = device_get_softc(dev); 131e1453c9eSEmmanuel Vadot sc->dev = dev; 132e1453c9eSEmmanuel Vadot 1334b84206bSMichal Meloun if (SYSCON_GET_HANDLE(sc->dev, &sc->syscon) != 0 || 1344b84206bSMichal Meloun sc->syscon == NULL) { 1354b84206bSMichal Meloun device_printf(dev, "cannot get syscon for device\n"); 136e1453c9eSEmmanuel Vadot return (ENXIO); 137e1453c9eSEmmanuel Vadot } 138e1453c9eSEmmanuel Vadot 139e1453c9eSEmmanuel Vadot reg = RD4(sc, 0x400); 140e1453c9eSEmmanuel Vadot switch (reg & 0x1f) { 141e1453c9eSEmmanuel Vadot case 0x0: 142e1453c9eSEmmanuel Vadot case 0x1: 143e1453c9eSEmmanuel Vadot clock_freq = 2000000000; 144e1453c9eSEmmanuel Vadot break; 145*a86b0839SMarcin Wojtas case 0x4: 146*a86b0839SMarcin Wojtas clock_freq = 1600000000; 147*a86b0839SMarcin Wojtas break; 148e1453c9eSEmmanuel Vadot case 0x6: 149e1453c9eSEmmanuel Vadot clock_freq = 1800000000; 150e1453c9eSEmmanuel Vadot break; 151*a86b0839SMarcin Wojtas case 0x7: 152*a86b0839SMarcin Wojtas clock_freq = 1800000000; 153*a86b0839SMarcin Wojtas break; 154*a86b0839SMarcin Wojtas case 0xb: 155*a86b0839SMarcin Wojtas clock_freq = 1600000000; 156*a86b0839SMarcin Wojtas break; 157e1453c9eSEmmanuel Vadot case 0xd: 158e1453c9eSEmmanuel Vadot clock_freq = 1600000000; 159e1453c9eSEmmanuel Vadot break; 160*a86b0839SMarcin Wojtas case 0x13: 161*a86b0839SMarcin Wojtas clock_freq = 1000000000; 162*a86b0839SMarcin Wojtas break; 163e1453c9eSEmmanuel Vadot case 0x14: 164e1453c9eSEmmanuel Vadot clock_freq = 1333000000; 165e1453c9eSEmmanuel Vadot break; 166*a86b0839SMarcin Wojtas case 0x17: 167*a86b0839SMarcin Wojtas clock_freq = 1333000000; 168*a86b0839SMarcin Wojtas break; 169*a86b0839SMarcin Wojtas case 0x19: 170*a86b0839SMarcin Wojtas clock_freq = 1200000000; 171*a86b0839SMarcin Wojtas break; 172*a86b0839SMarcin Wojtas case 0x1a: 173*a86b0839SMarcin Wojtas clock_freq = 1400000000; 174*a86b0839SMarcin Wojtas break; 175*a86b0839SMarcin Wojtas case 0x1b: 176*a86b0839SMarcin Wojtas clock_freq = 600000000; 177*a86b0839SMarcin Wojtas break; 178*a86b0839SMarcin Wojtas case 0x1c: 179*a86b0839SMarcin Wojtas clock_freq = 800000000; 180*a86b0839SMarcin Wojtas break; 181*a86b0839SMarcin Wojtas case 0x1d: 182*a86b0839SMarcin Wojtas clock_freq = 1000000000; 183*a86b0839SMarcin Wojtas break; 184e1453c9eSEmmanuel Vadot default: 1854b84206bSMichal Meloun device_printf(dev, "Cannot guess clock freq with reg %x\n", 1864b84206bSMichal Meloun reg & 0x1f); 187e1453c9eSEmmanuel Vadot return (ENXIO); 188e1453c9eSEmmanuel Vadot break; 189e1453c9eSEmmanuel Vadot }; 190e1453c9eSEmmanuel Vadot 191e1453c9eSEmmanuel Vadot ap806_clk_cluster_0.freq = clock_freq; 192e1453c9eSEmmanuel Vadot ap806_clk_cluster_1.freq = clock_freq; 193e1453c9eSEmmanuel Vadot clkdom = clkdom_create(dev); 194e1453c9eSEmmanuel Vadot 195e1453c9eSEmmanuel Vadot clknode_fixed_register(clkdom, &ap806_clk_cluster_0); 196e1453c9eSEmmanuel Vadot clknode_fixed_register(clkdom, &ap806_clk_cluster_1); 197e1453c9eSEmmanuel Vadot clknode_fixed_register(clkdom, &ap806_clk_fixed); 198e1453c9eSEmmanuel Vadot clknode_fixed_register(clkdom, &ap806_clk_mss); 199e1453c9eSEmmanuel Vadot clknode_fixed_register(clkdom, &ap806_clk_sdio); 200e1453c9eSEmmanuel Vadot 201e1453c9eSEmmanuel Vadot clkdom_finit(clkdom); 202e1453c9eSEmmanuel Vadot 203e1453c9eSEmmanuel Vadot if (bootverbose) 204e1453c9eSEmmanuel Vadot clkdom_dump(clkdom); 205e1453c9eSEmmanuel Vadot return (0); 206e1453c9eSEmmanuel Vadot } 207e1453c9eSEmmanuel Vadot 208e1453c9eSEmmanuel Vadot static int 209e1453c9eSEmmanuel Vadot mv_ap806_clock_detach(device_t dev) 210e1453c9eSEmmanuel Vadot { 211e1453c9eSEmmanuel Vadot 212e1453c9eSEmmanuel Vadot return (EBUSY); 213e1453c9eSEmmanuel Vadot } 214e1453c9eSEmmanuel Vadot 215e1453c9eSEmmanuel Vadot static device_method_t mv_ap806_clock_methods[] = { 216e1453c9eSEmmanuel Vadot /* Device interface */ 217e1453c9eSEmmanuel Vadot DEVMETHOD(device_probe, mv_ap806_clock_probe), 218e1453c9eSEmmanuel Vadot DEVMETHOD(device_attach, mv_ap806_clock_attach), 219e1453c9eSEmmanuel Vadot DEVMETHOD(device_detach, mv_ap806_clock_detach), 220e1453c9eSEmmanuel Vadot 221e1453c9eSEmmanuel Vadot DEVMETHOD_END 222e1453c9eSEmmanuel Vadot }; 223e1453c9eSEmmanuel Vadot 224e1453c9eSEmmanuel Vadot static devclass_t mv_ap806_clock_devclass; 225e1453c9eSEmmanuel Vadot 226e1453c9eSEmmanuel Vadot static driver_t mv_ap806_clock_driver = { 227e1453c9eSEmmanuel Vadot "mv_ap806_clock", 228e1453c9eSEmmanuel Vadot mv_ap806_clock_methods, 229e1453c9eSEmmanuel Vadot sizeof(struct mv_ap806_clock_softc), 230e1453c9eSEmmanuel Vadot }; 231e1453c9eSEmmanuel Vadot 232e1453c9eSEmmanuel Vadot EARLY_DRIVER_MODULE(mv_ap806_clock, simplebus, mv_ap806_clock_driver, 233e1453c9eSEmmanuel Vadot mv_ap806_clock_devclass, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_LATE); 234