1 1.4 thorpej /* $NetBSD: videopll.c,v 1.4 2023/12/20 15:29:04 thorpej Exp $ */ 2 1.1 macallan 3 1.1 macallan /* 4 1.1 macallan * Copyright (c) 2012 Michael Lorenz 5 1.1 macallan * All rights reserved. 6 1.1 macallan * 7 1.1 macallan * Redistribution and use in source and binary forms, with or without 8 1.1 macallan * modification, are permitted provided that the following conditions 9 1.1 macallan * are met: 10 1.1 macallan * 1. Redistributions of source code must retain the above copyright 11 1.1 macallan * notice, this list of conditions and the following disclaimer. 12 1.1 macallan * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 macallan * notice, this list of conditions and the following disclaimer in the 14 1.1 macallan * documentation and/or other materials provided with the distribution. 15 1.1 macallan * 16 1.1 macallan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 macallan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 macallan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 macallan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 macallan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 macallan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 macallan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 macallan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 macallan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 macallan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 macallan */ 27 1.1 macallan 28 1.1 macallan /* 29 1.1 macallan * A driver for the iic-controlled PLLs used in early Apple onboard video 30 1.2 macallan * hardware. For now we support /valkyrie only but others use very similar 31 1.1 macallan * schemes to program their pixel clock so adding support for those should 32 1.1 macallan * be simple enough. 33 1.1 macallan */ 34 1.1 macallan 35 1.1 macallan #include <sys/cdefs.h> 36 1.4 thorpej __KERNEL_RCSID(0, "$NetBSD: videopll.c,v 1.4 2023/12/20 15:29:04 thorpej Exp $"); 37 1.1 macallan 38 1.1 macallan #include <sys/param.h> 39 1.1 macallan #include <sys/systm.h> 40 1.1 macallan #include <sys/kernel.h> 41 1.1 macallan #include <sys/device.h> 42 1.1 macallan 43 1.1 macallan #include <dev/ofw/openfirm.h> 44 1.1 macallan #include <dev/i2c/i2cvar.h> 45 1.1 macallan #include <arch/macppc/dev/videopllvar.h> 46 1.1 macallan 47 1.1 macallan #include "opt_videopll.h" 48 1.1 macallan #ifdef VIDEOPLL_DEBUG 49 1.1 macallan #define DPRINTF printf 50 1.1 macallan #else 51 1.1 macallan #define DPRINTF while (0) printf 52 1.1 macallan #endif 53 1.1 macallan 54 1.1 macallan struct videopll_softc { 55 1.1 macallan device_t sc_dev; 56 1.1 macallan i2c_tag_t sc_tag; 57 1.1 macallan int sc_addr; 58 1.1 macallan }; 59 1.1 macallan 60 1.1 macallan static int videopll_match(device_t, cfdata_t, void *); 61 1.1 macallan static void videopll_attach(device_t, device_t, void *); 62 1.1 macallan 63 1.1 macallan CFATTACH_DECL_NEW(videopll, sizeof(struct videopll_softc), 64 1.1 macallan videopll_match, videopll_attach, NULL, NULL); 65 1.1 macallan 66 1.1 macallan static void *glob = NULL; 67 1.1 macallan 68 1.1 macallan static int 69 1.1 macallan videopll_match(device_t parent, cfdata_t cfdata, void *aux) 70 1.1 macallan { 71 1.1 macallan struct i2c_attach_args *ia = aux; 72 1.3 thorpej int match_result; 73 1.1 macallan 74 1.3 thorpej if (iic_use_direct_match(ia, cfdata, NULL, &match_result)) 75 1.3 thorpej return match_result; 76 1.3 thorpej 77 1.3 thorpej /* This driver is direct-config only. */ 78 1.2 macallan 79 1.1 macallan return 0; 80 1.1 macallan } 81 1.1 macallan 82 1.1 macallan static void 83 1.1 macallan videopll_attach(device_t parent, device_t self, void *aux) 84 1.1 macallan { 85 1.1 macallan struct i2c_attach_args *ia = aux; 86 1.1 macallan struct videopll_softc *sc = device_private(self); 87 1.1 macallan 88 1.1 macallan sc->sc_dev = self; 89 1.1 macallan sc->sc_tag = ia->ia_tag; 90 1.1 macallan sc->sc_addr = ia->ia_addr; 91 1.1 macallan aprint_normal(": Apple onboard video PLL\n"); 92 1.1 macallan glob = sc; 93 1.1 macallan } 94 1.1 macallan 95 1.1 macallan /* 96 1.1 macallan * pixel clock: 97 1.1 macallan * 3.9064MHz * 2^p2 * p1 / p0 98 1.1 macallan */ 99 1.1 macallan int 100 1.1 macallan videopll_set_freq(int freq) 101 1.1 macallan { 102 1.1 macallan struct videopll_softc *sc = glob; 103 1.1 macallan int p0, p1, p2; 104 1.1 macallan int freq_out, diff, diff_b = 100000000; 105 1.1 macallan int b0 = 0, b1 = 0, b2 = 0, freq_b = 0; 106 1.1 macallan uint8_t cmdbuf[4]; 107 1.1 macallan 108 1.1 macallan if (glob == NULL) 109 1.1 macallan return EIO; 110 1.1 macallan /* 111 1.1 macallan * XXX 112 1.1 macallan * The parameter ranges were taken from Linux' valkyriefb.c mode list. 113 1.1 macallan * We don't really know what exact parameters the PLL supports but 114 1.1 macallan * this should be enough for the modes we can actually support 115 1.1 macallan */ 116 1.1 macallan for (p2 = 2; p2 < 4; p2++) { 117 1.1 macallan for (p1 = 27; p1 < 43; p1++) { 118 1.1 macallan for (p0 = 11; p0 < 26; p0++) { 119 1.1 macallan freq_out = (3906400 * (1 << p2) * p1) / (p0 * 1000); 120 1.1 macallan diff = abs(freq - freq_out); 121 1.1 macallan if (diff < diff_b) { 122 1.1 macallan diff_b = diff; 123 1.1 macallan b0 = p0; 124 1.1 macallan b1 = p1; 125 1.1 macallan b2 = p2; 126 1.1 macallan freq_b = freq_out; 127 1.1 macallan } 128 1.1 macallan } 129 1.1 macallan } 130 1.1 macallan } 131 1.1 macallan if (freq_b == 0) 132 1.1 macallan return EINVAL; 133 1.1 macallan DPRINTF("param: %d %d %d -> %d\n", b0, b1, b2, freq_b); 134 1.1 macallan iic_acquire_bus(sc->sc_tag, 0); 135 1.1 macallan cmdbuf[0] = 1; 136 1.1 macallan cmdbuf[1] = b0; 137 1.1 macallan iic_exec(sc->sc_tag, I2C_OP_WRITE, 138 1.1 macallan sc->sc_addr, cmdbuf, 2, NULL, 0, 0); 139 1.1 macallan cmdbuf[0] = 2; 140 1.1 macallan cmdbuf[1] = b1; 141 1.1 macallan iic_exec(sc->sc_tag, I2C_OP_WRITE, 142 1.1 macallan sc->sc_addr, cmdbuf, 2, NULL, 0, 0); 143 1.1 macallan cmdbuf[0] = 3; 144 1.1 macallan cmdbuf[1] = b2; 145 1.1 macallan iic_exec(sc->sc_tag, I2C_OP_WRITE, 146 1.1 macallan sc->sc_addr, cmdbuf, 2, NULL, 0, 0); 147 1.1 macallan iic_release_bus(sc->sc_tag, 0); 148 1.1 macallan return 0; 149 1.1 macallan } 150 1.1 macallan 151 1.1 macallan 152 1.1 macallan 153