1 /* $OpenBSD: bcm2835_clock.c,v 1.3 2022/04/06 18:59:28 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Tobias Heider <tobhe@openbsd.org> 5 * Copyright (c) 2019 Neil Ashford <ashfordneil0@gmail.com> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /*- 21 * Copyright (c) 2017 Jared D. McNeill <jmcneill@invisible.ca> 22 * All rights reserved. 23 * 24 * Redistribution and use in source and binary forms, with or without 25 * modification, are permitted provided that the following conditions 26 * are met: 27 * 1. Redistributions of source code must retain the above copyright 28 * notice, this list of conditions and the following disclaimer. 29 * 2. Redistributions in binary form must reproduce the above copyright 30 * notice, this list of conditions and the following disclaimer in the 31 * documentation and/or other materials provided with the distribution. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 36 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 37 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 38 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 40 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 41 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 */ 45 46 #include <sys/param.h> 47 #include <sys/device.h> 48 #include <sys/systm.h> 49 50 #include <machine/fdt.h> 51 52 #include <dev/ofw/fdt.h> 53 #include <dev/ofw/ofw_clock.h> 54 #include <dev/ofw/openfirm.h> 55 56 #include <dev/ic/bcm2835_mbox.h> 57 #include <dev/ic/bcm2835_vcprop.h> 58 59 enum { 60 BCMCLOCK_CLOCK_TIMER = 17, 61 BCMCLOCK_CLOCK_UART = 19, 62 BCMCLOCK_CLOCK_VPU = 20, 63 BCMCLOCK_CLOCK_V3D = 21, 64 BCMCLOCK_CLOCK_ISP = 22, 65 BCMCLOCK_CLOCK_H264 = 23, 66 BCMCLOCK_CLOCK_VEC = 24, 67 BCMCLOCK_CLOCK_HSM = 25, 68 BCMCLOCK_CLOCK_SDRAM = 26, 69 BCMCLOCK_CLOCK_TSENS = 27, 70 BCMCLOCK_CLOCK_EMMC = 28, 71 BCMCLOCK_CLOCK_PERIIMAGE = 29, 72 BCMCLOCK_CLOCK_PWM = 30, 73 BCMCLOCK_CLOCK_PCM = 31, 74 BCMCLOCK_NCLOCK 75 }; 76 77 78 struct bcmclock_softc { 79 struct device sc_dev; 80 struct clock_device sc_cd; 81 82 }; 83 84 int bcmclock_match(struct device *, void *, void *); 85 void bcmclock_attach(struct device *, struct device *, void *); 86 87 const struct cfattach bcmclock_ca = { 88 sizeof(struct bcmclock_softc), 89 bcmclock_match, 90 bcmclock_attach, 91 }; 92 93 uint32_t bcmclock_get_frequency(void *, uint32_t *); 94 95 struct cfdriver bcmclock_cd = { NULL, "bcmclock", DV_DULL }; 96 97 int 98 bcmclock_match(struct device *parent, void *match, void *aux) 99 { 100 struct fdt_attach_args *faa = aux; 101 102 return (OF_is_compatible(faa->fa_node, "brcm,bcm2711-cprman") || 103 OF_is_compatible(faa->fa_node, "brcm,bcm2835-cprman")); 104 } 105 106 void 107 bcmclock_attach(struct device *parent, struct device *self, void *aux) 108 { 109 struct bcmclock_softc *sc = (struct bcmclock_softc *)self; 110 struct fdt_attach_args *faa = aux; 111 112 printf("\n"); 113 114 sc->sc_cd.cd_node = faa->fa_node; 115 sc->sc_cd.cd_cookie = sc; 116 sc->sc_cd.cd_get_frequency = bcmclock_get_frequency; 117 118 clock_register(&sc->sc_cd); 119 } 120 121 uint32_t 122 bcmclock_get_frequency(void *cookie, uint32_t *cells) 123 { 124 struct request { 125 struct vcprop_buffer_hdr vb_hdr; 126 struct vcprop_tag_clockrate vbt_clkrate; 127 struct vcprop_tag end; 128 } __attribute((aligned(16), packed)); 129 130 uint32_t result; 131 struct request req = { 132 .vb_hdr = { 133 .vpb_len = sizeof(req), 134 .vpb_rcode = VCPROP_PROCESS_REQUEST, 135 }, 136 .vbt_clkrate = { 137 .tag = { 138 .vpt_tag = VCPROPTAG_GET_CLOCKRATE, 139 .vpt_len = VCPROPTAG_LEN(req.vbt_clkrate), 140 .vpt_rcode = VCPROPTAG_REQUEST 141 }, 142 }, 143 .end = { 144 .vpt_tag = VCPROPTAG_NULL 145 } 146 }; 147 148 switch (cells[0]) { 149 case BCMCLOCK_CLOCK_TIMER: 150 break; 151 case BCMCLOCK_CLOCK_UART: 152 req.vbt_clkrate.id = VCPROP_CLK_UART; 153 break; 154 case BCMCLOCK_CLOCK_VPU: 155 req.vbt_clkrate.id = VCPROP_CLK_CORE; 156 break; 157 case BCMCLOCK_CLOCK_V3D: 158 req.vbt_clkrate.id = VCPROP_CLK_V3D; 159 break; 160 case BCMCLOCK_CLOCK_ISP: 161 req.vbt_clkrate.id = VCPROP_CLK_ISP; 162 break; 163 case BCMCLOCK_CLOCK_H264: 164 req.vbt_clkrate.id = VCPROP_CLK_H264; 165 break; 166 case BCMCLOCK_CLOCK_VEC: 167 break; 168 case BCMCLOCK_CLOCK_HSM: 169 break; 170 case BCMCLOCK_CLOCK_SDRAM: 171 req.vbt_clkrate.id = VCPROP_CLK_SDRAM; 172 break; 173 case BCMCLOCK_CLOCK_TSENS: 174 break; 175 case BCMCLOCK_CLOCK_EMMC: 176 req.vbt_clkrate.id = VCPROP_CLK_EMMC; 177 break; 178 case BCMCLOCK_CLOCK_PERIIMAGE: 179 break; 180 case BCMCLOCK_CLOCK_PWM: 181 req.vbt_clkrate.id = VCPROP_CLK_PWM; 182 break; 183 case BCMCLOCK_CLOCK_PCM: 184 break; 185 } 186 187 if (req.vbt_clkrate.id == 0) { 188 printf("bcmclock[unknown]: request to unknown clock type %d\n", 189 cells[0]); 190 return 0; 191 } 192 193 bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result); 194 195 if (vcprop_tag_success_p(&req.vbt_clkrate.tag)) 196 return req.vbt_clkrate.rate; 197 198 printf("bcmclock[unknown]: vcprop result %x:%x\n", req.vb_hdr.vpb_rcode, 199 req.vbt_clkrate.tag.vpt_rcode); 200 201 return 0; 202 } 203