bcm2835_cprman.c revision 1.4
11.4Sskrll/* $NetBSD: bcm2835_cprman.c,v 1.4 2019/12/30 15:36:37 skrll Exp $ */ 21.1Sskrll 31.1Sskrll/*- 41.1Sskrll * Copyright (c) 2017 Jared D. McNeill <jmcneill@invisible.ca> 51.1Sskrll * All rights reserved. 61.1Sskrll * 71.1Sskrll * Redistribution and use in source and binary forms, with or without 81.1Sskrll * modification, are permitted provided that the following conditions 91.1Sskrll * are met: 101.1Sskrll * 1. Redistributions of source code must retain the above copyright 111.1Sskrll * notice, this list of conditions and the following disclaimer. 121.1Sskrll * 2. Redistributions in binary form must reproduce the above copyright 131.1Sskrll * notice, this list of conditions and the following disclaimer in the 141.1Sskrll * documentation and/or other materials provided with the distribution. 151.1Sskrll * 161.1Sskrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Sskrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Sskrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Sskrll * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Sskrll * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Sskrll * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Sskrll * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Sskrll * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Sskrll * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sskrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sskrll * SUCH DAMAGE. 271.1Sskrll */ 281.1Sskrll 291.1Sskrll#include <sys/cdefs.h> 301.4Sskrll__KERNEL_RCSID(0, "$NetBSD: bcm2835_cprman.c,v 1.4 2019/12/30 15:36:37 skrll Exp $"); 311.1Sskrll 321.1Sskrll#include <sys/param.h> 331.1Sskrll#include <sys/systm.h> 341.1Sskrll#include <sys/device.h> 351.1Sskrll#include <sys/kmem.h> 361.1Sskrll#include <sys/bus.h> 371.1Sskrll 381.1Sskrll#include <dev/clk/clk_backend.h> 391.1Sskrll 401.1Sskrll#include <dev/fdt/fdtvar.h> 411.1Sskrll 421.1Sskrll#include <arm/broadcom/bcm2835var.h> 431.1Sskrll 441.1Sskrllenum { 451.1Sskrll CPRMAN_CLOCK_TIMER = 17, 461.1Sskrll CPRMAN_CLOCK_UART = 19, 471.1Sskrll CPRMAN_CLOCK_VPU = 20, 481.1Sskrll CPRMAN_CLOCK_V3D = 21, 491.1Sskrll CPRMAN_CLOCK_ISP = 22, 501.1Sskrll CPRMAN_CLOCK_H264 = 23, 511.1Sskrll CPRMAN_CLOCK_VEC = 24, 521.1Sskrll CPRMAN_CLOCK_HSM = 25, 531.1Sskrll CPRMAN_CLOCK_SDRAM = 26, 541.1Sskrll CPRMAN_CLOCK_TSENS = 27, 551.1Sskrll CPRMAN_CLOCK_EMMC = 28, 561.1Sskrll CPRMAN_CLOCK_PERIIMAGE = 29, 571.1Sskrll CPRMAN_CLOCK_PWM = 30, 581.1Sskrll CPRMAN_CLOCK_PCM = 31, 591.4Sskrll CPRMAN_CLOCK_EMMC2 = 51, 601.1Sskrll CPRMAN_NCLOCK 611.1Sskrll}; 621.1Sskrll 631.1Sskrllstruct cprman_clk { 641.1Sskrll struct clk base; 651.1Sskrll u_int id; 661.1Sskrll}; 671.1Sskrll 681.1Sskrllstruct cprman_softc { 691.1Sskrll device_t sc_dev; 701.1Sskrll int sc_phandle; 711.1Sskrll 721.1Sskrll struct clk_domain sc_clkdom; 731.1Sskrll struct cprman_clk sc_clk[CPRMAN_NCLOCK]; 741.1Sskrll}; 751.1Sskrll 761.1Sskrll 771.1Sskrllstatic struct clk * 781.2Saymericcprman_decode(device_t dev, int cc_phandle, const void *data, size_t len) 791.1Sskrll{ 801.1Sskrll struct cprman_softc * const sc = device_private(dev); 811.1Sskrll struct cprman_clk *clk; 821.1Sskrll const u_int *spec = data; 831.1Sskrll u_int id; 841.1Sskrll 851.1Sskrll if (len != 4) 861.1Sskrll return NULL; 871.1Sskrll 881.1Sskrll id = be32toh(spec[0]); 891.1Sskrll 901.1Sskrll if (id >= CPRMAN_NCLOCK) 911.1Sskrll return NULL; 921.1Sskrll clk = &sc->sc_clk[id]; 931.1Sskrll if (clk->base.name == NULL) 941.1Sskrll return NULL; 951.1Sskrll 961.1Sskrll return &clk->base; 971.1Sskrll} 981.1Sskrll 991.1Sskrllstatic const struct fdtbus_clock_controller_func cprman_fdt_funcs = { 1001.1Sskrll .decode = cprman_decode 1011.1Sskrll}; 1021.1Sskrll 1031.1Sskrllstatic struct clk * 1041.1Sskrllcprman_get(void *priv, const char *name) 1051.1Sskrll{ 1061.1Sskrll struct cprman_softc * const sc = priv; 1071.1Sskrll u_int n; 1081.1Sskrll 1091.1Sskrll for (n = 0; n < __arraycount(sc->sc_clk); n++) { 1101.1Sskrll if (sc->sc_clk[n].base.name == NULL) 1111.1Sskrll continue; 1121.1Sskrll if (strcmp(sc->sc_clk[n].base.name, name) == 0) 1131.1Sskrll return &sc->sc_clk[n].base; 1141.1Sskrll } 1151.1Sskrll 1161.1Sskrll return NULL; 1171.1Sskrll} 1181.1Sskrll 1191.1Sskrllstatic void 1201.1Sskrllcprman_put(void *priv, struct clk *clk) 1211.1Sskrll{ 1221.1Sskrll} 1231.1Sskrll 1241.1Sskrllstatic u_int 1251.1Sskrllcprman_get_rate(void *priv, struct clk *baseclk) 1261.1Sskrll{ 1271.1Sskrll //struct cprman_softc * const sc = priv; 1281.1Sskrll struct cprman_clk *clk = container_of(baseclk, struct cprman_clk, base); 1291.1Sskrll 1301.1Sskrll switch (clk->id) { 1311.1Sskrll case CPRMAN_CLOCK_UART: 1321.1Sskrll return bcm283x_clk_get_rate_uart(); 1331.1Sskrll case CPRMAN_CLOCK_VPU: 1341.1Sskrll return bcm283x_clk_get_rate_vpu(); 1351.1Sskrll case CPRMAN_CLOCK_EMMC: 1361.1Sskrll return bcm283x_clk_get_rate_emmc(); 1371.4Sskrll case CPRMAN_CLOCK_EMMC2: 1381.4Sskrll return bcm283x_clk_get_rate_emmc2(); 1391.1Sskrll default: 1401.1Sskrll panic("unsupported clock id %d\n", clk->id); 1411.1Sskrll } 1421.1Sskrll} 1431.1Sskrll 1441.1Sskrllstatic const struct clk_funcs cprman_clk_funcs = { 1451.1Sskrll .get = cprman_get, 1461.1Sskrll .put = cprman_put, 1471.1Sskrll .get_rate = cprman_get_rate, 1481.1Sskrll}; 1491.1Sskrll 1501.1Sskrllstatic void 1511.1Sskrllcprman_add_clock(struct cprman_softc *sc, u_int id, const char *name) 1521.1Sskrll{ 1531.1Sskrll sc->sc_clk[id].base.domain = &sc->sc_clkdom; 1541.1Sskrll sc->sc_clk[id].base.name = name; 1551.1Sskrll sc->sc_clk[id].id = id; 1561.1Sskrll} 1571.1Sskrll 1581.1Sskrllstatic int 1591.1Sskrllcprman_match(device_t parent, cfdata_t cf, void *aux) 1601.1Sskrll{ 1611.3Sskrll const char * const compatible[] = { 1621.3Sskrll "brcm,bcm2835-cprman", 1631.3Sskrll "brcm,bcm2711-cprman", 1641.3Sskrll NULL }; 1651.1Sskrll const struct fdt_attach_args *faa = aux; 1661.1Sskrll 1671.1Sskrll return of_match_compatible(faa->faa_phandle, compatible); 1681.1Sskrll} 1691.1Sskrll 1701.1Sskrllstatic void 1711.1Sskrllcprman_attach(device_t parent, device_t self, void *aux) 1721.1Sskrll{ 1731.1Sskrll struct cprman_softc * const sc = device_private(self); 1741.1Sskrll const struct fdt_attach_args *faa = aux; 1751.1Sskrll const int phandle = faa->faa_phandle; 1761.1Sskrll 1771.1Sskrll sc->sc_dev = self; 1781.1Sskrll sc->sc_phandle = phandle; 1791.1Sskrll sc->sc_clkdom.funcs = &cprman_clk_funcs; 1801.1Sskrll sc->sc_clkdom.priv = sc; 1811.1Sskrll 1821.1Sskrll cprman_add_clock(sc, CPRMAN_CLOCK_UART, "uart"); 1831.1Sskrll cprman_add_clock(sc, CPRMAN_CLOCK_VPU, "vpu"); 1841.1Sskrll cprman_add_clock(sc, CPRMAN_CLOCK_EMMC, "emmc"); 1851.4Sskrll cprman_add_clock(sc, CPRMAN_CLOCK_EMMC2, "emmc2"); 1861.1Sskrll 1871.1Sskrll aprint_naive("\n"); 1881.1Sskrll aprint_normal(": BCM283x Clock Controller\n"); 1891.1Sskrll 1901.1Sskrll fdtbus_register_clock_controller(self, phandle, &cprman_fdt_funcs); 1911.1Sskrll} 1921.1Sskrll 1931.1SskrllCFATTACH_DECL_NEW(bcmcprman_fdt, sizeof(struct cprman_softc), 1941.1Sskrll cprman_match, cprman_attach, NULL, NULL); 195