/* $OpenBSD: bcm2835_clock.c,v 1.2 2020/04/19 16:48:39 kettenis Exp $ */ /* * Copyright (c) 2020 Tobias Heider * Copyright (c) 2019 Neil Ashford * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Copyright (c) 2017 Jared D. McNeill * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include enum { BCMCLOCK_CLOCK_TIMER = 17, BCMCLOCK_CLOCK_UART = 19, BCMCLOCK_CLOCK_VPU = 20, BCMCLOCK_CLOCK_V3D = 21, BCMCLOCK_CLOCK_ISP = 22, BCMCLOCK_CLOCK_H264 = 23, BCMCLOCK_CLOCK_VEC = 24, BCMCLOCK_CLOCK_HSM = 25, BCMCLOCK_CLOCK_SDRAM = 26, BCMCLOCK_CLOCK_TSENS = 27, BCMCLOCK_CLOCK_EMMC = 28, BCMCLOCK_CLOCK_PERIIMAGE = 29, BCMCLOCK_CLOCK_PWM = 30, BCMCLOCK_CLOCK_PCM = 31, BCMCLOCK_NCLOCK }; struct bcmclock_softc { struct device sc_dev; struct clock_device sc_cd; }; int bcmclock_match(struct device *, void *, void *); void bcmclock_attach(struct device *, struct device *, void *); struct cfattach bcmclock_ca = { sizeof(struct bcmclock_softc), bcmclock_match, bcmclock_attach, }; uint32_t bcmclock_get_frequency(void *, uint32_t *); struct cfdriver bcmclock_cd = { NULL, "bcmclock", DV_DULL }; int bcmclock_match(struct device *parent, void *match, void *aux) { struct fdt_attach_args *faa = aux; return (OF_is_compatible(faa->fa_node, "brcm,bcm2711-cprman") || OF_is_compatible(faa->fa_node, "brcm,bcm2835-cprman")); } void bcmclock_attach(struct device *parent, struct device *self, void *aux) { struct bcmclock_softc *sc = (struct bcmclock_softc *)self; struct fdt_attach_args *faa = aux; printf("\n"); sc->sc_cd.cd_node = faa->fa_node; sc->sc_cd.cd_cookie = sc; sc->sc_cd.cd_get_frequency = bcmclock_get_frequency; clock_register(&sc->sc_cd); } uint32_t bcmclock_get_frequency(void *cookie, uint32_t *cells) { struct request { struct vcprop_buffer_hdr vb_hdr; struct vcprop_tag_clockrate vbt_clkrate; struct vcprop_tag end; } __attribute((aligned(16), packed)); uint32_t result; struct request req = { .vb_hdr = { .vpb_len = sizeof(req), .vpb_rcode = VCPROP_PROCESS_REQUEST, }, .vbt_clkrate = { .tag = { .vpt_tag = VCPROPTAG_GET_CLOCKRATE, .vpt_len = VCPROPTAG_LEN(req.vbt_clkrate), .vpt_rcode = VCPROPTAG_REQUEST }, }, .end = { .vpt_tag = VCPROPTAG_NULL } }; switch (cells[0]) { case BCMCLOCK_CLOCK_TIMER: break; case BCMCLOCK_CLOCK_UART: req.vbt_clkrate.id = VCPROP_CLK_UART; break; case BCMCLOCK_CLOCK_VPU: req.vbt_clkrate.id = VCPROP_CLK_CORE; break; case BCMCLOCK_CLOCK_V3D: req.vbt_clkrate.id = VCPROP_CLK_V3D; break; case BCMCLOCK_CLOCK_ISP: req.vbt_clkrate.id = VCPROP_CLK_ISP; break; case BCMCLOCK_CLOCK_H264: req.vbt_clkrate.id = VCPROP_CLK_H264; break; case BCMCLOCK_CLOCK_VEC: break; case BCMCLOCK_CLOCK_HSM: break; case BCMCLOCK_CLOCK_SDRAM: req.vbt_clkrate.id = VCPROP_CLK_SDRAM; break; case BCMCLOCK_CLOCK_TSENS: break; case BCMCLOCK_CLOCK_EMMC: req.vbt_clkrate.id = VCPROP_CLK_EMMC; break; case BCMCLOCK_CLOCK_PERIIMAGE: break; case BCMCLOCK_CLOCK_PWM: req.vbt_clkrate.id = VCPROP_CLK_PWM; break; case BCMCLOCK_CLOCK_PCM: break; } if (req.vbt_clkrate.id == 0) { printf("bcmclock[unknown]: request to unknown clock type %d\n", cells[0]); return 0; } bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result); if (vcprop_tag_success_p(&req.vbt_clkrate.tag)) return req.vbt_clkrate.rate; printf("bcmclock[unknown]: vcprop result %x:%x\n", req.vb_hdr.vpb_rcode, req.vbt_clkrate.tag.vpt_rcode); return 0; }