1*9fdf0c62Smpi /* $OpenBSD: exclock.c,v 1.10 2021/10/24 17:52:27 mpi Exp $ */
207829fe8Sbmercer /*
307829fe8Sbmercer * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
407829fe8Sbmercer *
507829fe8Sbmercer * Permission to use, copy, modify, and distribute this software for any
607829fe8Sbmercer * purpose with or without fee is hereby granted, provided that the above
707829fe8Sbmercer * copyright notice and this permission notice appear in all copies.
807829fe8Sbmercer *
907829fe8Sbmercer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1007829fe8Sbmercer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1107829fe8Sbmercer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1207829fe8Sbmercer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1307829fe8Sbmercer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1407829fe8Sbmercer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1507829fe8Sbmercer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1607829fe8Sbmercer */
1707829fe8Sbmercer
1807829fe8Sbmercer #include <sys/param.h>
1907829fe8Sbmercer #include <sys/systm.h>
2007829fe8Sbmercer #include <sys/device.h>
21fe1242bbSkettenis
2207829fe8Sbmercer #include <machine/bus.h>
2307829fe8Sbmercer #include <machine/fdt.h>
24fe1242bbSkettenis
25fe1242bbSkettenis #include <dev/ofw/openfirm.h>
26ebc46d47Skettenis #include <dev/ofw/ofw_clock.h>
27fe1242bbSkettenis #include <dev/ofw/fdt.h>
2807829fe8Sbmercer
2907829fe8Sbmercer /* registers */
3007829fe8Sbmercer #define CLOCK_APLL_CON0 0x0100
3107829fe8Sbmercer #define CLOCK_APLL_CON1 0x0104
3207829fe8Sbmercer #define CLOCK_BPLL_CON0 0x0110
3307829fe8Sbmercer #define CLOCK_BPLL_CON1 0x0114
3407829fe8Sbmercer #define CLOCK_EPLL_CON0 0x0130
3507829fe8Sbmercer #define CLOCK_EPLL_CON1 0x0134
3607829fe8Sbmercer #define CLOCK_EPLL_CON2 0x0138
3707829fe8Sbmercer #define CLOCK_VPLL_CON0 0x0140
3807829fe8Sbmercer #define CLOCK_VPLL_CON1 0x0144
3907829fe8Sbmercer #define CLOCK_VPLL_CON2 0x0148
4007829fe8Sbmercer #define CLOCK_CLK_DIV_CPU0 0x0500
4107829fe8Sbmercer #define CLOCK_CLK_DIV_CPU1 0x0504
4207829fe8Sbmercer #define CLOCK_CLK_DIV_TOP0 0x0510
4307829fe8Sbmercer #define CLOCK_CLK_DIV_TOP1 0x0514
4407829fe8Sbmercer #define CLOCK_PLL_DIV2_SEL 0x0A24
4507829fe8Sbmercer #define CLOCK_MPLL_CON0 0x4100
4607829fe8Sbmercer #define CLOCK_MPLL_CON1 0x4104
4707829fe8Sbmercer
4807829fe8Sbmercer /* bits and bytes */
4907829fe8Sbmercer #define MPLL_FOUT_SEL_SHIFT 0x4
5007829fe8Sbmercer #define MPLL_FOUT_SEL_MASK 0x1
5107829fe8Sbmercer #define BPLL_FOUT_SEL_SHIFT 0x0
5207829fe8Sbmercer #define BPLL_FOUT_SEL_MASK 0x1
5307829fe8Sbmercer
5407998b61Skettenis #define HCLK_FREQ 24000000
5507829fe8Sbmercer
5607829fe8Sbmercer #define HREAD4(sc, reg) \
5707829fe8Sbmercer (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
5807829fe8Sbmercer #define HWRITE4(sc, reg, val) \
5907829fe8Sbmercer bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
6007829fe8Sbmercer #define HSET4(sc, reg, bits) \
6107829fe8Sbmercer HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
6207829fe8Sbmercer #define HCLR4(sc, reg, bits) \
6307829fe8Sbmercer HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
6407829fe8Sbmercer
6507829fe8Sbmercer struct exclock_softc {
6607829fe8Sbmercer struct device sc_dev;
6707829fe8Sbmercer bus_space_tag_t sc_iot;
6807829fe8Sbmercer bus_space_handle_t sc_ioh;
69ebc46d47Skettenis
70ebc46d47Skettenis struct clock_device sc_cd;
7107829fe8Sbmercer };
7207829fe8Sbmercer
7307829fe8Sbmercer enum clocks {
7407829fe8Sbmercer /* OSC */
7507829fe8Sbmercer OSC, /* 24 MHz OSC */
7607829fe8Sbmercer
7707829fe8Sbmercer /* PLLs */
7807829fe8Sbmercer APLL, /* ARM core clock */
7907829fe8Sbmercer MPLL, /* System bus clock for memory controller */
8007829fe8Sbmercer BPLL, /* Graphic 3D processor clock and 1066 MHz clock for memory controller if necessary */
8107829fe8Sbmercer CPLL, /* Multi Format Video Hardware Codec clock */
8207829fe8Sbmercer GPLL, /* Graphic 3D processor clock or other clocks for DVFS flexibility */
8307829fe8Sbmercer EPLL, /* Audio interface clocks and clocks for other external device interfaces */
8407829fe8Sbmercer VPLL, /* dithered PLL, helps to reduce the EMI of display and camera */
8507998b61Skettenis KPLL,
8607829fe8Sbmercer };
8707829fe8Sbmercer
8807829fe8Sbmercer struct exclock_softc *exclock_sc;
8907829fe8Sbmercer
90fe1242bbSkettenis int exclock_match(struct device *, void *, void *);
91fe1242bbSkettenis void exclock_attach(struct device *, struct device *, void *);
9207998b61Skettenis uint32_t exclock_decode_pll_clk(enum clocks, unsigned int, unsigned int);
9307998b61Skettenis uint32_t exclock_get_pll_clk(struct exclock_softc *, enum clocks);
9407998b61Skettenis uint32_t exclock_get_armclk(struct exclock_softc *);
9507998b61Skettenis uint32_t exclock_get_kfcclk(struct exclock_softc *);
9607829fe8Sbmercer unsigned int exclock_get_i2cclk(void);
9707829fe8Sbmercer
98*9fdf0c62Smpi const struct cfattach exclock_ca = {
9907829fe8Sbmercer sizeof (struct exclock_softc), exclock_match, exclock_attach
10007829fe8Sbmercer };
10107829fe8Sbmercer
10207829fe8Sbmercer struct cfdriver exclock_cd = {
10307829fe8Sbmercer NULL, "exclock", DV_DULL
10407829fe8Sbmercer };
10507829fe8Sbmercer
10616042c3cSkettenis uint32_t exynos5250_get_frequency(void *, uint32_t *);
10716042c3cSkettenis int exynos5250_set_frequency(void *, uint32_t *, uint32_t);
10816042c3cSkettenis void exynos5250_enable(void *, uint32_t *, int);
10916042c3cSkettenis uint32_t exynos5420_get_frequency(void *, uint32_t *);
11016042c3cSkettenis int exynos5420_set_frequency(void *, uint32_t *, uint32_t);
11116042c3cSkettenis void exynos5420_enable(void *, uint32_t *, int);
112ebc46d47Skettenis
11307829fe8Sbmercer int
exclock_match(struct device * parent,void * match,void * aux)114fe1242bbSkettenis exclock_match(struct device *parent, void *match, void *aux)
11507829fe8Sbmercer {
116fe1242bbSkettenis struct fdt_attach_args *faa = aux;
11707829fe8Sbmercer
11807998b61Skettenis if (OF_is_compatible(faa->fa_node, "samsung,exynos5250-clock") ||
11907998b61Skettenis OF_is_compatible(faa->fa_node, "samsung,exynos5800-clock"))
12007998b61Skettenis return 10; /* Must beat syscon(4). */
12107998b61Skettenis
12207998b61Skettenis return 0;
12307829fe8Sbmercer }
12407829fe8Sbmercer
12507829fe8Sbmercer void
exclock_attach(struct device * parent,struct device * self,void * aux)126fe1242bbSkettenis exclock_attach(struct device *parent, struct device *self, void *aux)
12707829fe8Sbmercer {
12807829fe8Sbmercer struct exclock_softc *sc = (struct exclock_softc *)self;
129fe1242bbSkettenis struct fdt_attach_args *faa = aux;
13007829fe8Sbmercer
131fe1242bbSkettenis sc->sc_iot = faa->fa_iot;
132fe1242bbSkettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
133fe1242bbSkettenis faa->fa_reg[0].size, 0, &sc->sc_ioh))
13407829fe8Sbmercer panic("%s: bus_space_map failed!", __func__);
13507829fe8Sbmercer
136fe1242bbSkettenis exclock_sc = sc;
13707829fe8Sbmercer
13807998b61Skettenis printf("\n");
13907829fe8Sbmercer
14016042c3cSkettenis if (OF_is_compatible(faa->fa_node, "samsung,exynos5250-clock")) {
14116042c3cSkettenis /* Exynos 5250 */
14216042c3cSkettenis sc->sc_cd.cd_enable = exynos5250_enable;
14316042c3cSkettenis sc->sc_cd.cd_get_frequency = exynos5250_get_frequency;
14416042c3cSkettenis sc->sc_cd.cd_set_frequency = exynos5250_set_frequency;
14516042c3cSkettenis } else {
14616042c3cSkettenis /* Exynos 5420/5800 */
14716042c3cSkettenis sc->sc_cd.cd_enable = exynos5420_enable;
14816042c3cSkettenis sc->sc_cd.cd_get_frequency = exynos5420_get_frequency;
14916042c3cSkettenis sc->sc_cd.cd_set_frequency = exynos5420_set_frequency;
15016042c3cSkettenis }
15116042c3cSkettenis
152ebc46d47Skettenis sc->sc_cd.cd_node = faa->fa_node;
153ebc46d47Skettenis sc->sc_cd.cd_cookie = sc;
154ebc46d47Skettenis clock_register(&sc->sc_cd);
15507829fe8Sbmercer }
15607829fe8Sbmercer
15716042c3cSkettenis /*
15816042c3cSkettenis * Exynos 5250
15916042c3cSkettenis */
16016042c3cSkettenis
16107998b61Skettenis /* Clocks */
16207998b61Skettenis #define EXYNOS5250_CLK_ARM_CLK 9
16307998b61Skettenis
164ebc46d47Skettenis uint32_t
exynos5250_get_frequency(void * cookie,uint32_t * cells)16516042c3cSkettenis exynos5250_get_frequency(void *cookie, uint32_t *cells)
166ebc46d47Skettenis {
16707998b61Skettenis struct exclock_softc *sc = cookie;
168ebc46d47Skettenis uint32_t idx = cells[0];
169ebc46d47Skettenis
17007998b61Skettenis switch (idx) {
17107998b61Skettenis case EXYNOS5250_CLK_ARM_CLK:
17207998b61Skettenis return exclock_get_armclk(sc);
17307998b61Skettenis }
17407998b61Skettenis
175ebc46d47Skettenis printf("%s: 0x%08x\n", __func__, idx);
176ebc46d47Skettenis return 0;
177ebc46d47Skettenis }
178ebc46d47Skettenis
179ebc46d47Skettenis int
exynos5250_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)18016042c3cSkettenis exynos5250_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
181ebc46d47Skettenis {
182ebc46d47Skettenis uint32_t idx = cells[0];
183ebc46d47Skettenis
18407998b61Skettenis switch (idx) {
18507998b61Skettenis case EXYNOS5250_CLK_ARM_CLK:
18607998b61Skettenis return -1;
18707998b61Skettenis }
18807998b61Skettenis
189ebc46d47Skettenis printf("%s: 0x%08x\n", __func__, idx);
190ebc46d47Skettenis return -1;
191ebc46d47Skettenis }
192ebc46d47Skettenis
193ebc46d47Skettenis void
exynos5250_enable(void * cookie,uint32_t * cells,int on)19416042c3cSkettenis exynos5250_enable(void *cookie, uint32_t *cells, int on)
195ebc46d47Skettenis {
196ebc46d47Skettenis uint32_t idx = cells[0];
197ebc46d47Skettenis
198ebc46d47Skettenis printf("%s: 0x%08x\n", __func__, idx);
199ebc46d47Skettenis }
200ebc46d47Skettenis
20116042c3cSkettenis /*
20216042c3cSkettenis * Exynos 5420/5800
20316042c3cSkettenis */
20416042c3cSkettenis
20516042c3cSkettenis /* Clocks */
20616042c3cSkettenis #define EXYNOS5420_CLK_FIN_PLL 1
20716042c3cSkettenis #define EXYNOS5420_CLK_FOUT_RPLL 6
20816042c3cSkettenis #define EXYNOS5420_CLK_FOUT_SPLL 8
20907998b61Skettenis #define EXYNOS5420_CLK_ARM_CLK 13
21007998b61Skettenis #define EXYNOS5420_CLK_KFC_CLK 14
21116042c3cSkettenis #define EXYNOS5420_CLK_SCLK_MMC2 134
21216042c3cSkettenis #define EXYNOS5420_CLK_MMC2 353
21307998b61Skettenis #define EXYNOS5420_CLK_USBH20 365
21407998b61Skettenis #define EXYNOS5420_CLK_USBD300 366
21507998b61Skettenis #define EXYNOS5420_CLK_USBD301 367
21616042c3cSkettenis #define EXYNOS5420_CLK_SCLK_SPLL -1
21716042c3cSkettenis
21816042c3cSkettenis /* Registers */
21916042c3cSkettenis #define EXYNOS5420_RPLL_CON0 0x10140
22016042c3cSkettenis #define EXYNOS5420_RPLL_CON1 0x10144
22116042c3cSkettenis #define EXYNOS5420_SPLL_CON0 0x10160
22216042c3cSkettenis #define EXYNOS5420_SRC_TOP6 0x10218
22316042c3cSkettenis #define EXYNOS5420_DIV_FSYS1 0x1054c
22416042c3cSkettenis #define EXYNOS5420_SRC_FSYS 0x10244
22516042c3cSkettenis #define EXYNOS5420_GATE_TOP_SCLK_FSYS 0x10840
22616042c3cSkettenis #define EXYNOS5420_GATE_IP_FSYS 0x10944
22707998b61Skettenis #define EXYNOS5420_KPLL_CON0 0x28100
22807998b61Skettenis #define EXYNOS5420_SRC_KFC 0x28200
22907998b61Skettenis #define EXYNOS5420_DIV_KFC0 0x28500
23016042c3cSkettenis
23116042c3cSkettenis uint32_t
exynos5420_get_frequency(void * cookie,uint32_t * cells)23216042c3cSkettenis exynos5420_get_frequency(void *cookie, uint32_t *cells)
23316042c3cSkettenis {
23416042c3cSkettenis struct exclock_softc *sc = cookie;
23516042c3cSkettenis uint32_t idx = cells[0];
23616042c3cSkettenis uint32_t reg, div, mux;
23716042c3cSkettenis uint32_t kdiv, mdiv, pdiv, sdiv;
23816042c3cSkettenis uint64_t freq;
23916042c3cSkettenis
24016042c3cSkettenis switch (idx) {
24116042c3cSkettenis case EXYNOS5420_CLK_FIN_PLL:
24216042c3cSkettenis return 24000000;
24307998b61Skettenis case EXYNOS5420_CLK_ARM_CLK:
24407998b61Skettenis return exclock_get_armclk(sc);
24507998b61Skettenis case EXYNOS5420_CLK_KFC_CLK:
24607998b61Skettenis return exclock_get_kfcclk(sc);
24716042c3cSkettenis case EXYNOS5420_CLK_SCLK_MMC2:
24816042c3cSkettenis reg = HREAD4(sc, EXYNOS5420_DIV_FSYS1);
24916042c3cSkettenis div = ((reg >> 20) & ((1 << 10) - 1)) + 1;
25016042c3cSkettenis reg = HREAD4(sc, EXYNOS5420_SRC_FSYS);
25116042c3cSkettenis mux = ((reg >> 16) & ((1 << 3) - 1));
25216042c3cSkettenis switch (mux) {
25316042c3cSkettenis case 0:
25416042c3cSkettenis idx = EXYNOS5420_CLK_FIN_PLL;
25516042c3cSkettenis break;
25616042c3cSkettenis case 4:
25716042c3cSkettenis idx = EXYNOS5420_CLK_SCLK_SPLL;
25816042c3cSkettenis break;
25916042c3cSkettenis default:
26016042c3cSkettenis idx = 0;
26116042c3cSkettenis break;
26216042c3cSkettenis }
26316042c3cSkettenis return exynos5420_get_frequency(sc, &idx) / div;
26416042c3cSkettenis case EXYNOS5420_CLK_SCLK_SPLL:
26516042c3cSkettenis reg = HREAD4(sc, EXYNOS5420_SRC_TOP6);
26616042c3cSkettenis mux = ((reg >> 8) & ((1 << 1) - 1));
26716042c3cSkettenis switch (mux) {
26816042c3cSkettenis case 0:
26916042c3cSkettenis idx = EXYNOS5420_CLK_FIN_PLL;
27016042c3cSkettenis break;
27116042c3cSkettenis case 1:
27216042c3cSkettenis idx = EXYNOS5420_CLK_FOUT_SPLL;
27316042c3cSkettenis break;
27416042c3cSkettenis }
27516042c3cSkettenis return exynos5420_get_frequency(sc, &idx);
27616042c3cSkettenis case EXYNOS5420_CLK_FOUT_RPLL:
27716042c3cSkettenis reg = HREAD4(sc, EXYNOS5420_RPLL_CON0);
27816042c3cSkettenis mdiv = (reg >> 16) & 0x1ff;
27916042c3cSkettenis pdiv = (reg >> 8) & 0x3f;
28016042c3cSkettenis sdiv = (reg >> 0) & 0x7;
28116042c3cSkettenis reg = HREAD4(sc, EXYNOS5420_RPLL_CON1);
28216042c3cSkettenis kdiv = (reg >> 0) & 0xffff;
28316042c3cSkettenis idx = EXYNOS5420_CLK_FIN_PLL;
28416042c3cSkettenis freq = exynos5420_get_frequency(sc, &idx);
28516042c3cSkettenis freq = ((mdiv << 16) + kdiv) * freq / (pdiv * (1 << sdiv));
28616042c3cSkettenis return (freq >> 16);
28716042c3cSkettenis case EXYNOS5420_CLK_FOUT_SPLL:
28816042c3cSkettenis reg = HREAD4(sc, EXYNOS5420_SPLL_CON0);
28916042c3cSkettenis mdiv = (reg >> 16) & 0x3ff;
29016042c3cSkettenis pdiv = (reg >> 8) & 0x3f;
29116042c3cSkettenis sdiv = (reg >> 0) & 0x7;
29216042c3cSkettenis idx = EXYNOS5420_CLK_FIN_PLL;
29316042c3cSkettenis freq = exynos5420_get_frequency(sc, &idx);
29416042c3cSkettenis return mdiv * freq / (pdiv * (1 << sdiv));
29516042c3cSkettenis }
29616042c3cSkettenis
29716042c3cSkettenis printf("%s: 0x%08x\n", __func__, idx);
29816042c3cSkettenis return 0;
29916042c3cSkettenis }
30016042c3cSkettenis
30116042c3cSkettenis int
exynos5420_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)30216042c3cSkettenis exynos5420_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
30316042c3cSkettenis {
30416042c3cSkettenis uint32_t idx = cells[0];
30516042c3cSkettenis
30607998b61Skettenis switch (idx) {
30707998b61Skettenis case EXYNOS5420_CLK_ARM_CLK:
30807998b61Skettenis case EXYNOS5420_CLK_KFC_CLK:
30907998b61Skettenis return -1;
31007998b61Skettenis }
31107998b61Skettenis
31216042c3cSkettenis printf("%s: 0x%08x\n", __func__, idx);
31316042c3cSkettenis return -1;
31416042c3cSkettenis }
31516042c3cSkettenis
31616042c3cSkettenis void
exynos5420_enable(void * cookie,uint32_t * cells,int on)31716042c3cSkettenis exynos5420_enable(void *cookie, uint32_t *cells, int on)
31816042c3cSkettenis {
31916042c3cSkettenis uint32_t idx = cells[0];
32016042c3cSkettenis
32116042c3cSkettenis switch (idx) {
32216042c3cSkettenis case EXYNOS5420_CLK_SCLK_MMC2: /* CLK_GATE_TOP_SCLK_FSYS */
32316042c3cSkettenis case EXYNOS5420_CLK_MMC2: /* CLK_GATE_IP_FSYS */
32407998b61Skettenis case EXYNOS5420_CLK_USBH20: /* CLK_GATE_IP_FSYS */
32507998b61Skettenis case EXYNOS5420_CLK_USBD300: /* CLK_GATE_IP_FSYS */
32607998b61Skettenis case EXYNOS5420_CLK_USBD301: /* CLK_GATE_IP_FSYS */
32716042c3cSkettenis /* Enabled by default. */
32816042c3cSkettenis return;
32916042c3cSkettenis }
33016042c3cSkettenis
33116042c3cSkettenis printf("%s: 0x%08x\n", __func__, idx);
33216042c3cSkettenis }
33316042c3cSkettenis
33407998b61Skettenis uint32_t
exclock_decode_pll_clk(enum clocks pll,unsigned int r,unsigned int k)33507829fe8Sbmercer exclock_decode_pll_clk(enum clocks pll, unsigned int r, unsigned int k)
33607829fe8Sbmercer {
33707998b61Skettenis uint64_t freq;
33807998b61Skettenis uint32_t m, p, s = 0, mask, fout;
33907829fe8Sbmercer /*
34007829fe8Sbmercer * APLL_CON: MIDV [25:16]
34107829fe8Sbmercer * MPLL_CON: MIDV [25:16]
34207829fe8Sbmercer * EPLL_CON: MIDV [24:16]
34307829fe8Sbmercer * VPLL_CON: MIDV [24:16]
34407829fe8Sbmercer * BPLL_CON: MIDV [25:16]: Exynos5
34507829fe8Sbmercer */
34607829fe8Sbmercer
34707829fe8Sbmercer switch (pll)
34807829fe8Sbmercer {
34907829fe8Sbmercer case APLL:
35007829fe8Sbmercer case MPLL:
35107829fe8Sbmercer case BPLL:
35207998b61Skettenis case KPLL:
35307829fe8Sbmercer mask = 0x3ff;
35407829fe8Sbmercer break;
35507829fe8Sbmercer default:
35607829fe8Sbmercer mask = 0x1ff;
35707829fe8Sbmercer }
35807829fe8Sbmercer
35907829fe8Sbmercer m = (r >> 16) & mask;
36007829fe8Sbmercer
36107829fe8Sbmercer /* PDIV [13:8] */
36207829fe8Sbmercer p = (r >> 8) & 0x3f;
36307829fe8Sbmercer /* SDIV [2:0] */
36407829fe8Sbmercer s = r & 0x7;
36507829fe8Sbmercer
36607829fe8Sbmercer freq = HCLK_FREQ;
36707829fe8Sbmercer
36807829fe8Sbmercer if (pll == EPLL) {
36907829fe8Sbmercer k = k & 0xffff;
37007829fe8Sbmercer /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
37107829fe8Sbmercer fout = (m + k / 65536) * (freq / (p * (1 << s)));
37207829fe8Sbmercer } else if (pll == VPLL) {
37307829fe8Sbmercer k = k & 0xfff;
37407829fe8Sbmercer /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
37507829fe8Sbmercer fout = (m + k / 1024) * (freq / (p * (1 << s)));
37607829fe8Sbmercer } else {
37707829fe8Sbmercer /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
37807829fe8Sbmercer fout = m * (freq / (p * (1 << s)));
37907829fe8Sbmercer }
38007829fe8Sbmercer
38107829fe8Sbmercer return fout;
38207829fe8Sbmercer }
38307829fe8Sbmercer
38407998b61Skettenis uint32_t
exclock_get_pll_clk(struct exclock_softc * sc,enum clocks pll)38507998b61Skettenis exclock_get_pll_clk(struct exclock_softc *sc, enum clocks pll)
38607829fe8Sbmercer {
38707829fe8Sbmercer uint32_t freq;
38807829fe8Sbmercer
38907829fe8Sbmercer switch (pll) {
39007829fe8Sbmercer case APLL:
39107829fe8Sbmercer freq = exclock_decode_pll_clk(pll,
39207998b61Skettenis HREAD4(sc, CLOCK_APLL_CON0), 0);
39307829fe8Sbmercer break;
39407829fe8Sbmercer case MPLL:
39507829fe8Sbmercer freq = exclock_decode_pll_clk(pll,
39607998b61Skettenis HREAD4(sc, CLOCK_MPLL_CON0), 0);
39707829fe8Sbmercer break;
39807829fe8Sbmercer case BPLL:
39907829fe8Sbmercer freq = exclock_decode_pll_clk(pll,
40007998b61Skettenis HREAD4(sc, CLOCK_BPLL_CON0), 0);
40107829fe8Sbmercer break;
40207829fe8Sbmercer case EPLL:
40307829fe8Sbmercer freq = exclock_decode_pll_clk(pll,
40407829fe8Sbmercer HREAD4(sc, CLOCK_EPLL_CON0),
40507829fe8Sbmercer HREAD4(sc, CLOCK_EPLL_CON1));
40607829fe8Sbmercer break;
40707829fe8Sbmercer case VPLL:
40807829fe8Sbmercer freq = exclock_decode_pll_clk(pll,
40907829fe8Sbmercer HREAD4(sc, CLOCK_VPLL_CON0),
41007829fe8Sbmercer HREAD4(sc, CLOCK_VPLL_CON1));
41107829fe8Sbmercer break;
41207998b61Skettenis case KPLL:
41307998b61Skettenis freq = exclock_decode_pll_clk(pll,
41407998b61Skettenis HREAD4(sc, EXYNOS5420_KPLL_CON0), 0);
41507998b61Skettenis break;
41607829fe8Sbmercer default:
41707829fe8Sbmercer return 0;
41807829fe8Sbmercer }
41907829fe8Sbmercer
42007829fe8Sbmercer /*
42107829fe8Sbmercer * According to the user manual, in EVT1 MPLL and BPLL always gives
42207829fe8Sbmercer * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.
42307829fe8Sbmercer */
42407829fe8Sbmercer if (pll == MPLL || pll == BPLL) {
42507829fe8Sbmercer uint32_t freq_sel;
42607829fe8Sbmercer uint32_t pll_div2_sel = HREAD4(sc, CLOCK_PLL_DIV2_SEL);
42707829fe8Sbmercer
42807829fe8Sbmercer switch (pll) {
42907829fe8Sbmercer case MPLL:
43007829fe8Sbmercer freq_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
43107829fe8Sbmercer & MPLL_FOUT_SEL_MASK;
43207829fe8Sbmercer break;
43307829fe8Sbmercer case BPLL:
43407829fe8Sbmercer freq_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
43507829fe8Sbmercer & BPLL_FOUT_SEL_MASK;
43607829fe8Sbmercer break;
43707829fe8Sbmercer default:
43807829fe8Sbmercer freq_sel = -1;
43907829fe8Sbmercer break;
44007829fe8Sbmercer }
44107829fe8Sbmercer
44207829fe8Sbmercer if (freq_sel == 0)
44307829fe8Sbmercer freq /= 2;
44407829fe8Sbmercer }
44507829fe8Sbmercer
44607829fe8Sbmercer return freq;
44707829fe8Sbmercer }
44807829fe8Sbmercer
44907998b61Skettenis uint32_t
exclock_get_armclk(struct exclock_softc * sc)45007998b61Skettenis exclock_get_armclk(struct exclock_softc *sc)
45107829fe8Sbmercer {
45207829fe8Sbmercer uint32_t div, armclk, arm_ratio, arm2_ratio;
45307829fe8Sbmercer
45407829fe8Sbmercer div = HREAD4(sc, CLOCK_CLK_DIV_CPU0);
45507829fe8Sbmercer
45607829fe8Sbmercer /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
45707829fe8Sbmercer arm_ratio = (div >> 0) & 0x7;
45807829fe8Sbmercer arm2_ratio = (div >> 28) & 0x7;
45907829fe8Sbmercer
46007998b61Skettenis armclk = exclock_get_pll_clk(sc, APLL) / (arm_ratio + 1);
46107829fe8Sbmercer armclk /= (arm2_ratio + 1);
46207829fe8Sbmercer
46307829fe8Sbmercer return armclk;
46407829fe8Sbmercer }
46507829fe8Sbmercer
46607998b61Skettenis uint32_t
exclock_get_kfcclk(struct exclock_softc * sc)46707998b61Skettenis exclock_get_kfcclk(struct exclock_softc *sc)
46807998b61Skettenis {
46907998b61Skettenis uint32_t div, kfc_ratio;
47007998b61Skettenis
47107998b61Skettenis div = HREAD4(sc, EXYNOS5420_DIV_KFC0);
47207998b61Skettenis
47307998b61Skettenis /* KFC_RATIO: [2:0] */
47407998b61Skettenis kfc_ratio = (div >> 0) & 0x7;
47507998b61Skettenis
47607998b61Skettenis return exclock_get_pll_clk(sc, KPLL) / (kfc_ratio + 1);
47707998b61Skettenis }
47807998b61Skettenis
47907829fe8Sbmercer unsigned int
exclock_get_i2cclk(void)480fe1242bbSkettenis exclock_get_i2cclk(void)
48107829fe8Sbmercer {
48207829fe8Sbmercer struct exclock_softc *sc = exclock_sc;
48307829fe8Sbmercer uint32_t aclk_66, aclk_66_pre, div, ratio;
48407829fe8Sbmercer
48507829fe8Sbmercer div = HREAD4(sc, CLOCK_CLK_DIV_TOP1);
48607829fe8Sbmercer ratio = (div >> 24) & 0x7;
48707998b61Skettenis aclk_66_pre = exclock_get_pll_clk(sc, MPLL) / (ratio + 1);
48807829fe8Sbmercer div = HREAD4(sc, CLOCK_CLK_DIV_TOP0);
48907829fe8Sbmercer ratio = (div >> 0) & 0x7;
49007829fe8Sbmercer aclk_66 = aclk_66_pre / (ratio + 1);
49107829fe8Sbmercer
49207998b61Skettenis return aclk_66 / 1000;
49307829fe8Sbmercer }
494