xref: /openbsd/sys/arch/armv7/marvell/mvacc.c (revision a78270f8)
1 /* $OpenBSD: mvacc.c,v 1.6 2024/02/13 02:14:25 jsg Exp $ */
2 /*
3  * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <machine/bus.h>
22 #include <machine/fdt.h>
23 
24 #include <dev/ofw/openfirm.h>
25 #include <dev/ofw/ofw_clock.h>
26 #include <dev/ofw/fdt.h>
27 
28 #define SAR				0x00
29 #define  SAR_CPU_DDR_FREQ_OPT		10
30 #define  SAR_CPU_DDR_FREQ_OPT_MASK	0x1f
31 #define  SAR_TCLK_FREQ_OPT		15
32 #define  SAR_TCLK_FREQ_OPT_MASK		0x1
33 
34 #define HREAD4(sc, reg)							\
35 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
36 #define HWRITE4(sc, reg, val)						\
37 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
38 #define HSET4(sc, reg, bits)						\
39 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
40 #define HCLR4(sc, reg, bits)						\
41 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
42 
43 static const uint32_t mvacc_cpu_freqs[] = {
44 	0, 0, 0, 0,
45 	1066000000, 0, 0, 0,
46 	1322000000, 0, 0, 0,
47 	1600000000,
48 };
49 
50 static const int mvacc_l2clk_ratios[32][2] = {
51 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
52 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
53 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
54 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
55 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
56 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
57 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
58 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
59 };
60 
61 static const int mvacc_ddrclk_ratios[32][2] = {
62 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
63 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
64 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
65 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
66 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
67 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
68 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
69 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
70 };
71 
72 struct mvacc_softc {
73 	struct device		 sc_dev;
74 	bus_space_tag_t		 sc_iot;
75 	bus_space_handle_t	 sc_ioh;
76 	int			 sc_node;
77 	struct clock_device	 sc_cd;
78 };
79 
80 int	 mvacc_match(struct device *, void *, void *);
81 void	 mvacc_attach(struct device *, struct device *, void *);
82 
83 uint32_t mvacc_get_frequency(void *, uint32_t *);
84 
85 const struct cfattach	mvacc_ca = {
86 	sizeof (struct mvacc_softc), mvacc_match, mvacc_attach
87 };
88 
89 struct cfdriver mvacc_cd = {
90 	NULL, "mvacc", DV_DULL
91 };
92 
93 int
mvacc_match(struct device * parent,void * cfdata,void * aux)94 mvacc_match(struct device *parent, void *cfdata, void *aux)
95 {
96 	struct fdt_attach_args *faa = aux;
97 
98 	return OF_is_compatible(faa->fa_node, "marvell,armada-380-core-clock");
99 }
100 
101 void amptimer_set_clockrate(int32_t new_frequency); /* XXX */
102 
103 void
mvacc_attach(struct device * parent,struct device * self,void * args)104 mvacc_attach(struct device *parent, struct device *self, void *args)
105 {
106 	struct mvacc_softc *sc = (struct mvacc_softc *)self;
107 	struct fdt_attach_args *faa = args;
108 	int idx = 2;
109 
110 	sc->sc_node = faa->fa_node;
111 	sc->sc_iot = faa->fa_iot;
112 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
113 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
114 		panic("%s: bus_space_map failed!", __func__);
115 
116 	printf("\n");
117 
118 	amptimer_set_clockrate(mvacc_get_frequency(sc, &idx));
119 
120 	sc->sc_cd.cd_node = sc->sc_node;
121 	sc->sc_cd.cd_cookie = sc;
122 	sc->sc_cd.cd_get_frequency = mvacc_get_frequency;
123 	clock_register(&sc->sc_cd);
124 }
125 
126 uint32_t
mvacc_get_frequency(void * cookie,uint32_t * cells)127 mvacc_get_frequency(void *cookie, uint32_t *cells)
128 {
129 	struct mvacc_softc *sc = cookie;
130 	uint32_t sar, cpu, tclk;
131 
132 	sar = HREAD4(sc, SAR);
133 	cpu = (sar >> SAR_CPU_DDR_FREQ_OPT) & SAR_CPU_DDR_FREQ_OPT_MASK;
134 	tclk = (sar >> SAR_TCLK_FREQ_OPT) & SAR_TCLK_FREQ_OPT_MASK;
135 
136 	if (cpu >= nitems(mvacc_cpu_freqs)) {
137 		printf("%s: invalid cpu frequency", sc->sc_dev.dv_xname);
138 		return 0;
139 	}
140 
141 	switch (cells[0])
142 	{
143 	case 0: /* TCLK */
144 		return tclk ? 200000000 : 250000000;
145 	case 1: /* CPUCLK */
146 		return mvacc_cpu_freqs[cpu];
147 	case 2: /* L2CLK */
148 		return (mvacc_cpu_freqs[cpu] * mvacc_l2clk_ratios[cpu][0])
149 		    / mvacc_l2clk_ratios[cpu][1];
150 	case 3: /* DDRCLK */
151 		return (mvacc_cpu_freqs[cpu] * mvacc_ddrclk_ratios[cpu][0])
152 		    / mvacc_ddrclk_ratios[cpu][1];
153 	default:
154 		return 0;
155 	}
156 }
157