#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_clock.h>
#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/fdt.h>
#define JH7100_CLK_CPUNDBUS_ROOT 0
#define JH7100_CLK_GMACUSB_ROOT 3
#define JH7100_CLK_PERH0_ROOT 4
#define JH7100_CLK_PERH1_ROOT 5
#define JH7100_CLK_CPUNBUS_ROOT_DIV 12
#define JH7100_CLK_PERH0_SRC 14
#define JH7100_CLK_PERH1_SRC 15
#define JH7100_CLK_PLL2_REF 19
#define JH7100_CLK_AHB_BUS 22
#define JH7100_CLK_SDIO0_AHB 114
#define JH7100_CLK_SDIO0_CCLKINT 115
#define JH7100_CLK_SDIO0_CCLKINT_INV 116
#define JH7100_CLK_SDIO1_AHB 117
#define JH7100_CLK_SDIO1_CCLKINT 118
#define JH7100_CLK_SDIO1_CCLKINT_INV 119
#define JH7100_CLK_GMAC_AHB 120
#define JH7100_CLK_GMAC_ROOT_DIV 121
#define JH7100_CLK_GMAC_GTX 123
#define JH7100_CLK_UART0_CORE 147
#define JH7100_CLK_I2C0_CORE 155
#define JH7100_CLK_I2C1_CORE 157
#define JH7100_CLK_UART3_CORE 162
#define JH7100_CLK_I2C2_CORE 168
#define JH7100_CLK_TEMP_APB 183
#define JH7100_CLK_TEMP_SENSE 184
#define JH7100_CLK_PLL0_OUT 186
#define JH7100_CLK_PLL1_OUT 187
#define JH7100_CLK_PLL2_OUT 188
#define JH7100_CLK_OSC_SYS 255
#define JH7100_CLK_OSC_AUD 254
#define JH7110_AONCLK_GMAC0_AHB 2
#define JH7110_AONCLK_GMAC0_AXI 3
#define JH7110_AONCLK_GMAC0_RMII_RTX 4
#define JH7110_AONCLK_GMAC0_TX 5
#define JH7110_AONCLK_GMAC0_TX_INV 6
#define JH7110_AONCLK_OSC 14
#define JH7110_AONCLK_GMAC0_RMII_REFIN 15
#define JH7110_AONCLK_STG_AXIAHB 17
#define JH7110_AONCLK_GMAC0_GTXCLK 19
#define JH7110_AONCLK_ASSERT_OFFSET 0x38
#define JH7110_AONCLK_STATUS_OFFSET 0x3c
#define JH7110_CLK_PLL0_OUT 0
#define JH7110_CLK_PLL1_OUT 1
#define JH7110_CLK_PLL2_OUT 2
#define JH7110_STGCLK_PCIE0_AXI_MST0 8
#define JH7110_STGCLK_PCIE0_APB 9
#define JH7110_STGCLK_PCIE0_TL 10
#define JH7110_STGCLK_PCIE1_AXI_MST0 11
#define JH7110_STGCLK_PCIE1_APB 12
#define JH7110_STGCLK_PCIE1_TL 13
#define JH7110_STGCLK_SEC_AHB 15
#define JH7110_STGCLK_SEC_MISC_AHB 16
#define JH7110_STGCLK_ASSERT_OFFSET 0x74
#define JH7110_STGCLK_STATUS_OFFSET 0x78
#define JH7110_SYSCLK_CPU_ROOT 0
#define JH7110_SYSCLK_CPU_CORE 1
#define JH7110_SYSCLK_CPU_BUS 2
#define JH7110_SYSCLK_BUS_ROOT 5
#define JH7110_SYSCLK_AXI_CFG0 7
#define JH7110_SYSCLK_STG_AXIAHB 8
#define JH7110_SYSCLK_AHB0 9
#define JH7110_SYSCLK_AHB1 10
#define JH7110_SYSCLK_APB_BUS 11
#define JH7110_SYSCLK_APB0 12
#define JH7110_SYSCLK_SDIO0_AHB 91
#define JH7110_SYSCLK_SDIO1_AHB 92
#define JH7110_SYSCLK_SDIO0_SDCARD 93
#define JH7110_SYSCLK_SDIO1_SDCARD 94
#define JH7110_SYSCLK_NOC_BUS_STG_AXI 96
#define JH7110_SYSCLK_GMAC1_AHB 97
#define JH7110_SYSCLK_GMAC1_AXI 98
#define JH7110_SYSCLK_GMAC1_GTXCLK 100
#define JH7110_SYSCLK_GMAC1_RMII_RTX 101
#define JH7110_SYSCLK_GMAC1_PTP 102
#define JH7110_SYSCLK_GMAC1_TX 105
#define JH7110_SYSCLK_GMAC1_TX_INV 106
#define JH7110_SYSCLK_GMAC1_GTXC 107
#define JH7110_SYSCLK_GMAC0_GTXCLK 108
#define JH7110_SYSCLK_GMAC0_PTP 109
#define JH7110_SYSCLK_GMAC0_GTXC 111
#define JH7110_SYSCLK_IOMUX_APB 112
#define JH7110_SYSCLK_TEMP_APB 129
#define JH7110_SYSCLK_TEMP_CORE 130
#define JH7110_SYSCLK_I2C0_APB 138
#define JH7110_SYSCLK_I2C1_APB 139
#define JH7110_SYSCLK_I2C2_APB 140
#define JH7110_SYSCLK_I2C3_APB 141
#define JH7110_SYSCLK_I2C4_APB 142
#define JH7110_SYSCLK_I2C5_APB 143
#define JH7110_SYSCLK_I2C6_APB 144
#define JH7110_SYSCLK_UART0_CORE 146
#define JH7110_SYSCLK_OSC 190
#define JH7110_SYSCLK_GMAC1_RMII_REFIN 191
#define JH7110_SYSCLK_PLL0_OUT 199
#define JH7110_SYSCLK_PLL1_OUT 200
#define JH7110_SYSCLK_PLL2_OUT 201
#define JH7110_SYSCLK_ASSERT_OFFSET 0x2f8
#define JH7110_SYSCLK_STATUS_OFFSET 0x308
#define CLKMUX_MASK 0x03000000
#define CLKMUX_SHIFT 24
#define CLKDIV_MASK 0x00ffffff
#define CLKDIV_SHIFT 0
#define PLL0DACPD_MASK 0x01000000
#define PLL0DACPD_SHIFT 24
#define PLL0DSMPD_MASK 0x02000000
#define PLL0DSMPD_SHIFT 25
#define PLL0FBDIV_MASK 0x00000fff
#define PLL0FBDIV_SHIFT 0
#define PLLDACPD_MASK 0x00008000
#define PLLDACPD_SHIFT 15
#define PLLDSMPD_MASK 0x00010000
#define PLLDSMPD_SHIFT 16
#define PLLFBDIV_MASK 0x1ffe0000
#define PLLFBDIV_SHIFT 17
#define PLLFRAC_MASK 0x00ffffff
#define PLLFRAC_SHIFT 0
#define PLLPOSTDIV1_MASK 0x30000000
#define PLLPOSTDIV1_SHIFT 28
#define PLLPREDIV_MASK 0x0000003f
#define PLLPREDIV_SHIFT 0
#define JH7110_PLL0_BASE 0x0018
#define JH7110_PLL1_BASE 0x0024
#define JH7110_PLL2_BASE 0x002c
#define JH7110_PLL0_PD_OFF 0x0000
#define JH7110_PLL0_FBDIV_OFF 0x0004
#define JH7110_PLL0_FRAC_OFF 0x0008
#define JH7110_PLL0_PREDIV_OFF 0x000c
#define JH7110_PLL_PD_OFF 0x0000
#define JH7110_PLL_FRAC_OFF 0x0004
#define JH7110_PLL_PREDIV_OFF 0x0008
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET4(sc, reg, bits) \
HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
#define HCLR4(sc, reg, bits) \
HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
struct stfclock_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
struct regmap *sc_rm;
int sc_node;
struct clock_device sc_cd;
struct reset_device sc_rd;
};
int stfclock_match(struct device *, void *, void *);
void stfclock_attach(struct device *, struct device *, void *);
const struct cfattach stfclock_ca = {
sizeof (struct stfclock_softc), stfclock_match, stfclock_attach
};
struct cfdriver stfclock_cd = {
NULL, "stfclock", DV_DULL
};
uint32_t stfclock_get_frequency_jh7100(void *, uint32_t *);
int stfclock_set_frequency_jh7100(void *, uint32_t *, uint32_t);
void stfclock_enable_jh7100(void *, uint32_t *, int);
uint32_t stfclock_get_frequency_jh7110_aon(void *, uint32_t *);
int stfclock_set_frequency_jh7110_aon(void *, uint32_t *, uint32_t);
void stfclock_enable_jh7110_aon(void *, uint32_t *, int);
void stfclock_reset_jh7110_aon(void *, uint32_t *, int);
uint32_t stfclock_get_frequency_jh7110_pll(void *, uint32_t *);
int stfclock_set_frequency_jh7110_pll(void *, uint32_t *, uint32_t);
void stfclock_enable_jh7110_pll(void *, uint32_t *, int);
uint32_t stfclock_get_frequency_jh7110_stg(void *, uint32_t *);
int stfclock_set_frequency_jh7110_stg(void *, uint32_t *, uint32_t);
void stfclock_enable_jh7110_stg(void *, uint32_t *, int);
void stfclock_reset_jh7110_stg(void *, uint32_t *, int);
uint32_t stfclock_get_frequency_jh7110_sys(void *, uint32_t *);
int stfclock_set_frequency_jh7110_sys(void *, uint32_t *, uint32_t);
void stfclock_enable_jh7110_sys(void *, uint32_t *, int);
void stfclock_reset_jh7110_sys(void *, uint32_t *, int);
int
stfclock_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
return OF_is_compatible(faa->fa_node, "starfive,jh7100-clkgen") ||
OF_is_compatible(faa->fa_node, "starfive,jh7110-aoncrg") ||
OF_is_compatible(faa->fa_node, "starfive,jh7110-pll") ||
OF_is_compatible(faa->fa_node, "starfive,jh7110-stgcrg") ||
OF_is_compatible(faa->fa_node, "starfive,jh7110-syscrg");
}
void
stfclock_attach(struct device *parent, struct device *self, void *aux)
{
struct stfclock_softc *sc = (struct stfclock_softc *)self;
struct fdt_attach_args *faa = aux;
if (OF_is_compatible(faa->fa_node, "starfive,jh7110-pll")) {
sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
if (sc->sc_rm == NULL) {
printf(": can't get regmap\n");
return;
}
} else {
if (faa->fa_nreg < 1) {
printf(": no registers\n");
return;
}
sc->sc_iot = faa->fa_iot;
if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
printf(": can't map registers\n");
return;
}
}
sc->sc_node = faa->fa_node;
sc->sc_cd.cd_node = faa->fa_node;
sc->sc_cd.cd_cookie = sc;
if (OF_is_compatible(faa->fa_node, "starfive,jh7100-clkgen")) {
sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7100;
sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7100;
sc->sc_cd.cd_enable = stfclock_enable_jh7100;
printf("\n");
} else if (OF_is_compatible(faa->fa_node, "starfive,jh7110-aoncrg")) {
sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7110_aon;
sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7110_aon;
sc->sc_cd.cd_enable = stfclock_enable_jh7110_aon;
sc->sc_rd.rd_node = sc->sc_node;
sc->sc_rd.rd_cookie = sc;
sc->sc_rd.rd_reset = stfclock_reset_jh7110_aon;
reset_register(&sc->sc_rd);
printf(": aoncrg\n");
} else if (OF_is_compatible(faa->fa_node, "starfive,jh7110-pll")) {
sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7110_pll;
sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7110_pll;
sc->sc_cd.cd_enable = stfclock_enable_jh7110_pll;
printf(": pll\n");
} else if (OF_is_compatible(faa->fa_node, "starfive,jh7110-stgcrg")) {
sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7110_stg;
sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7110_stg;
sc->sc_cd.cd_enable = stfclock_enable_jh7110_stg;
sc->sc_rd.rd_node = sc->sc_node;
sc->sc_rd.rd_cookie = sc;
sc->sc_rd.rd_reset = stfclock_reset_jh7110_stg;
reset_register(&sc->sc_rd);
printf(": stgcrg\n");
} else if (OF_is_compatible(faa->fa_node, "starfive,jh7110-syscrg")) {
sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7110_sys;
sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7110_sys;
sc->sc_cd.cd_enable = stfclock_enable_jh7110_sys;
sc->sc_rd.rd_node = sc->sc_node;
sc->sc_rd.rd_cookie = sc;
sc->sc_rd.rd_reset = stfclock_reset_jh7110_sys;
reset_register(&sc->sc_rd);
printf(": syscrg\n");
}
KASSERT(sc->sc_cd.cd_get_frequency);
clock_register(&sc->sc_cd);
}
uint32_t
stfclock_get_frequency_jh7100(void *cookie, uint32_t *cells)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t parent, freq;
uint32_t reg, div, mux;
switch (idx) {
case JH7100_CLK_OSC_SYS:
return clock_get_frequency(sc->sc_node, "osc_sys");
case JH7100_CLK_OSC_AUD:
return clock_get_frequency(sc->sc_node, "osc_aud");
case JH7100_CLK_PLL0_OUT:
parent = JH7100_CLK_OSC_SYS;
return 40 * stfclock_get_frequency_jh7100(sc, &parent);
case JH7100_CLK_PLL1_OUT:
parent = JH7100_CLK_OSC_SYS;
return 64 * stfclock_get_frequency_jh7100(sc, &parent);
case JH7100_CLK_PLL2_OUT:
parent = JH7100_CLK_PLL2_REF;
return 55 * stfclock_get_frequency_jh7100(sc, &parent);
}
reg = HREAD4(sc, idx * 4);
mux = (reg & CLKMUX_MASK) >> CLKMUX_SHIFT;
div = (reg & CLKDIV_MASK) >> CLKDIV_SHIFT;
switch (idx) {
case JH7100_CLK_CPUNDBUS_ROOT:
switch (mux) {
default:
parent = JH7100_CLK_OSC_SYS;
break;
case 1:
parent = JH7100_CLK_PLL0_OUT;
break;
case 2:
parent = JH7100_CLK_PLL1_OUT;
break;
case 3:
parent = JH7100_CLK_PLL2_OUT;
break;
}
return stfclock_get_frequency_jh7100(sc, &parent);
case JH7100_CLK_GMACUSB_ROOT:
switch (mux) {
default:
parent = JH7100_CLK_OSC_SYS;
break;
case 1:
parent = JH7100_CLK_PLL0_OUT;
break;
case 2:
parent = JH7100_CLK_PLL2_OUT;
break;
}
return stfclock_get_frequency_jh7100(sc, &parent);
case JH7100_CLK_PERH0_ROOT:
mux = (reg >> 24) & 1;
parent = mux ? JH7100_CLK_PLL0_OUT : JH7100_CLK_OSC_SYS;
return stfclock_get_frequency_jh7100(sc, &parent);
case JH7100_CLK_PERH1_ROOT:
mux = (reg >> 24) & 1;
parent = mux ? JH7100_CLK_PLL2_OUT : JH7100_CLK_OSC_SYS;
return stfclock_get_frequency_jh7100(sc, &parent);
case JH7100_CLK_PLL2_REF:
parent = mux ? JH7100_CLK_OSC_AUD : JH7100_CLK_OSC_SYS;
return stfclock_get_frequency_jh7100(sc, &parent);
}
switch (idx) {
case JH7100_CLK_PERH0_SRC:
parent = JH7100_CLK_PERH0_ROOT;
break;
case JH7100_CLK_PERH1_SRC:
parent = JH7100_CLK_PERH1_ROOT;
break;
case JH7100_CLK_CPUNBUS_ROOT_DIV:
parent = JH7100_CLK_CPUNDBUS_ROOT;
break;
case JH7100_CLK_AHB_BUS:
parent = JH7100_CLK_CPUNBUS_ROOT_DIV;
break;
case JH7100_CLK_SDIO0_CCLKINT:
case JH7100_CLK_UART3_CORE:
case JH7100_CLK_I2C2_CORE:
parent = JH7100_CLK_PERH0_SRC;
break;
case JH7100_CLK_SDIO1_CCLKINT:
case JH7100_CLK_I2C0_CORE:
case JH7100_CLK_I2C1_CORE:
case JH7100_CLK_UART0_CORE:
parent = JH7100_CLK_PERH1_SRC;
break;
case JH7100_CLK_SDIO0_AHB:
case JH7100_CLK_SDIO1_AHB:
case JH7100_CLK_GMAC_AHB:
parent = JH7100_CLK_AHB_BUS;
div = 1;
break;
case JH7100_CLK_SDIO0_CCLKINT_INV:
parent = JH7100_CLK_SDIO0_CCLKINT;
div = 1;
break;
case JH7100_CLK_SDIO1_CCLKINT_INV:
parent = JH7100_CLK_SDIO1_CCLKINT;
div = 1;
break;
case JH7100_CLK_GMAC_ROOT_DIV:
parent = JH7100_CLK_GMACUSB_ROOT;
break;
case JH7100_CLK_GMAC_GTX:
parent = JH7100_CLK_GMAC_ROOT_DIV;
break;
default:
printf("%s: unknown clock 0x%08x\n", __func__, idx);
return 0;
}
freq = stfclock_get_frequency_jh7100(sc, &parent);
return freq / div;
}
int
stfclock_set_frequency_jh7100(void *cookie, uint32_t *cells, uint32_t freq)
{
uint32_t idx = cells[0];
printf("%s: not handled 0x%08x (freq=0x%08x)\n", __func__, idx, freq);
return -1;
}
void
stfclock_enable_jh7100(void *cookie, uint32_t *cells, int on)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
switch (idx) {
case JH7100_CLK_SDIO0_CCLKINT:
case JH7100_CLK_SDIO0_CCLKINT_INV:
case JH7100_CLK_SDIO1_CCLKINT:
case JH7100_CLK_SDIO1_CCLKINT_INV:
case JH7100_CLK_SDIO0_AHB:
case JH7100_CLK_SDIO1_AHB:
case JH7100_CLK_GMAC_AHB:
case JH7100_CLK_GMAC_GTX:
case JH7100_CLK_I2C0_CORE:
case JH7100_CLK_I2C1_CORE:
case JH7100_CLK_UART0_CORE:
case JH7100_CLK_UART3_CORE:
case JH7100_CLK_I2C2_CORE:
case JH7100_CLK_TEMP_APB:
case JH7100_CLK_TEMP_SENSE:
if (on)
HSET4(sc, idx * 4, 1U << 31);
else
HCLR4(sc, idx * 4, 1U << 31);
return;
case JH7100_CLK_GMAC_ROOT_DIV:
return;
}
printf("%s: unknown clock 0x%08x\n", __func__, idx);
}
uint32_t
stfclock_get_frequency_jh7110_aon(void *cookie, uint32_t *cells)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t parent, freq;
uint32_t reg, div, mux;
switch (idx) {
case JH7110_AONCLK_OSC:
return clock_get_frequency(sc->sc_node, "osc");
case JH7110_AONCLK_STG_AXIAHB:
return clock_get_frequency(sc->sc_node, "stg_axiahb");
case JH7110_AONCLK_GMAC0_RMII_REFIN:
return clock_get_frequency(sc->sc_node, "gmac0_rmii_refin");
case JH7110_AONCLK_GMAC0_GTXCLK:
return clock_get_frequency(sc->sc_node, "gmac0_gtxclk");
}
reg = HREAD4(sc, idx * 4);
mux = (reg & CLKMUX_MASK) >> CLKMUX_SHIFT;
div = (reg & CLKDIV_MASK) >> CLKDIV_SHIFT;
switch (idx) {
case JH7110_AONCLK_GMAC0_TX:
parent = mux ? JH7110_AONCLK_GMAC0_RMII_RTX :
JH7110_AONCLK_GMAC0_GTXCLK;
return stfclock_get_frequency_jh7110_aon(sc, &parent);
}
switch (idx) {
case JH7110_AONCLK_GMAC0_AXI:
parent = JH7110_AONCLK_STG_AXIAHB;
div = 1;
break;
case JH7110_AONCLK_GMAC0_RMII_RTX:
parent = JH7110_AONCLK_GMAC0_RMII_REFIN;
break;
case JH7110_AONCLK_GMAC0_TX_INV:
parent = JH7110_AONCLK_GMAC0_TX;
div = 1;
break;
default:
printf("%s: unknown clock 0x%08x\n", __func__, idx);
return 0;
}
if (div == 0) {
printf("%s: zero divisor for clock 0x%08x\n", __func__, idx);
return 0;
}
freq = stfclock_get_frequency_jh7110_aon(sc, &parent);
return freq / div;
}
int
stfclock_set_frequency_jh7110_aon(void *cookie, uint32_t *cells, uint32_t freq)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t parent, parent_freq;
uint32_t reg, div, mux;
switch (idx) {
case JH7110_AONCLK_GMAC0_RMII_REFIN:
return clock_set_frequency(sc->sc_node, "gmac0_rmii_refin", freq);
case JH7110_AONCLK_GMAC0_GTXCLK:
return clock_set_frequency(sc->sc_node, "gmac0_gtxclk", freq);
}
reg = HREAD4(sc, idx * 4);
mux = (reg & CLKMUX_MASK) >> CLKMUX_SHIFT;
switch (idx) {
case JH7110_AONCLK_GMAC0_TX:
parent = mux ? JH7110_AONCLK_GMAC0_RMII_RTX :
JH7110_AONCLK_GMAC0_GTXCLK;
return stfclock_set_frequency_jh7110_aon(sc, &parent, freq);
case JH7110_AONCLK_GMAC0_TX_INV:
parent = JH7110_AONCLK_GMAC0_TX;
return stfclock_set_frequency_jh7110_aon(sc, &parent, freq);
}
switch (idx) {
case JH7110_AONCLK_GMAC0_RMII_RTX:
parent = JH7110_AONCLK_GMAC0_RMII_REFIN;
break;
default:
printf("%s: not handled 0x%08x (freq=0x%08x)\n",
__func__, idx, freq);
return -1;
}
parent_freq = stfclock_get_frequency_jh7110_sys(sc, &parent);
div = (parent_freq + freq / 2) / freq;
if (div == 0)
div = 1;
reg &= ~CLKDIV_MASK;
reg |= (div << CLKDIV_SHIFT);
HWRITE4(sc, idx * 4, reg);
return 0;
}
void
stfclock_enable_jh7110_aon(void *cookie, uint32_t *cells, int on)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
switch (idx) {
case JH7110_AONCLK_GMAC0_TX_INV:
idx = JH7110_AONCLK_GMAC0_TX;
break;
}
switch (idx) {
case JH7110_AONCLK_GMAC0_AHB:
case JH7110_AONCLK_GMAC0_AXI:
case JH7110_AONCLK_GMAC0_TX:
if (on)
HSET4(sc, idx * 4, 1U << 31);
else
HCLR4(sc, idx * 4, 1U << 31);
return;
}
printf("%s: unknown clock 0x%08x\n", __func__, idx);
}
void
stfclock_reset_jh7110_aon(void *cookie, uint32_t *cells, int assert)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t bits, offset;
offset = JH7110_AONCLK_ASSERT_OFFSET + (idx / 32) * 4;
bits = 1U << (idx % 32);
if (assert)
HSET4(sc, offset, bits);
else
HCLR4(sc, offset, bits);
}
uint32_t
stfclock_get_frequency_jh7110_pll(void *cookie, uint32_t *cells)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t dacpd, dsmpd, fbdiv, frac, prediv, postdiv, reg;
uint64_t frac_val, parent_freq;
bus_size_t base;
parent_freq = clock_get_frequency_idx(sc->sc_node, 0);
if (parent_freq == 0) {
printf("%s: failed to get parent frequency\n", __func__);
return 0;
}
switch (idx) {
case JH7110_CLK_PLL0_OUT:
base = JH7110_PLL0_BASE;
break;
case JH7110_CLK_PLL1_OUT:
base = JH7110_PLL1_BASE;
break;
case JH7110_CLK_PLL2_OUT:
base = JH7110_PLL2_BASE;
break;
default:
printf("%s: unknown clock 0x08%x\n", __func__, idx);
return 0;
}
switch (idx) {
case JH7110_CLK_PLL0_OUT:
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_PD_OFF);
dacpd = (reg & PLL0DACPD_MASK) >> PLL0DACPD_SHIFT;
dsmpd = (reg & PLL0DSMPD_MASK) >> PLL0DSMPD_SHIFT;
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_FBDIV_OFF);
fbdiv = (reg & PLL0FBDIV_MASK) >> PLL0FBDIV_SHIFT;
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_FRAC_OFF);
frac = (reg & PLLFRAC_MASK) >> PLLFRAC_SHIFT;
postdiv = 1 << ((reg & PLLPOSTDIV1_MASK) >> PLLPOSTDIV1_SHIFT);
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_PREDIV_OFF);
prediv = (reg & PLLPREDIV_MASK) >> PLLPREDIV_SHIFT;
break;
case JH7110_CLK_PLL1_OUT:
case JH7110_CLK_PLL2_OUT:
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL_PD_OFF);
dacpd = (reg & PLLDACPD_MASK) >> PLLDACPD_SHIFT;
dsmpd = (reg & PLLDSMPD_MASK) >> PLLDSMPD_SHIFT;
fbdiv = (reg & PLLFBDIV_MASK) >> PLLFBDIV_SHIFT;
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL_FRAC_OFF);
frac = (reg & PLLFRAC_MASK) >> PLLFRAC_SHIFT;
postdiv = 1 << ((reg & PLLPOSTDIV1_MASK) >> PLLPOSTDIV1_SHIFT);
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL_PREDIV_OFF);
prediv = (reg & PLLPREDIV_MASK) >> PLLPREDIV_SHIFT;
break;
}
if (fbdiv == 0 || prediv == 0 || postdiv == 0) {
printf("%s: zero divisor\n", __func__);
return 0;
}
if (dacpd != dsmpd)
return 0;
frac_val = 0;
if (dacpd == 0 && dsmpd == 0)
frac_val = ((uint64_t)frac * 1000) / (1 << 24);
return parent_freq / 1000 * (fbdiv * 1000 + frac_val) / prediv / postdiv;
}
int
stfclock_set_frequency_jh7110_pll(void *cookie, uint32_t *cells, uint32_t freq)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t dacpd, dsmpd, fbdiv, prediv, postdiv1, reg;
bus_size_t base = JH7110_PLL0_BASE;
switch (idx) {
case JH7110_CLK_PLL0_OUT:
switch (freq) {
case 375000000:
prediv = 8;
break;
case 500000000:
prediv = 6;
break;
case 750000000:
prediv = 4;
break;
case 1000000000:
prediv = 3;
break;
case 1500000000:
prediv = 2;
break;
default:
return -1;
}
dacpd = dsmpd = 1;
fbdiv = 125;
postdiv1 = 0;
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_PD_OFF);
reg &= ~(PLL0DACPD_MASK | PLL0DSMPD_MASK);
reg |= dacpd << PLL0DACPD_SHIFT;
reg |= dsmpd << PLL0DSMPD_SHIFT;
regmap_write_4(sc->sc_rm, base + JH7110_PLL0_PD_OFF, reg);
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_PREDIV_OFF);
reg &= ~PLLPREDIV_MASK;
reg |= (prediv << PLLPREDIV_SHIFT);
regmap_write_4(sc->sc_rm, base + JH7110_PLL0_PREDIV_OFF, reg);
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_FBDIV_OFF);
reg &= ~PLL0FBDIV_MASK;
reg |= fbdiv << PLL0FBDIV_SHIFT;
regmap_write_4(sc->sc_rm, base + JH7110_PLL0_FBDIV_OFF, reg);
reg = regmap_read_4(sc->sc_rm, base + JH7110_PLL0_FRAC_OFF);
reg &= ~PLLPOSTDIV1_MASK;
reg |= postdiv1 << PLLPOSTDIV1_SHIFT;
regmap_write_4(sc->sc_rm, base + JH7110_PLL0_FRAC_OFF, reg);
return 0;
}
printf("%s: not handled 0x%08x (freq=0x%08x)\n", __func__, idx, freq);
return -1;
}
void
stfclock_enable_jh7110_pll(void *cookie, uint32_t *cells, int on)
{
uint32_t idx = cells[0];
printf("%s: not handled 0x%08x\n", __func__, idx);
}
uint32_t
stfclock_get_frequency_jh7110_stg(void *cookie, uint32_t *cells)
{
uint32_t idx = cells[0];
printf("%s: unknown clock 0x%08x\n", __func__, idx);
return 0;
}
int
stfclock_set_frequency_jh7110_stg(void *cookie, uint32_t *cells, uint32_t freq)
{
uint32_t idx = cells[0];
printf("%s: not handled 0x%08x (freq=0x%08x)\n", __func__, idx, freq);
return -1;
}
void
stfclock_enable_jh7110_stg(void *cookie, uint32_t *cells, int on)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
switch (idx) {
case JH7110_STGCLK_PCIE0_AXI_MST0:
case JH7110_STGCLK_PCIE0_APB:
case JH7110_STGCLK_PCIE0_TL:
case JH7110_STGCLK_PCIE1_AXI_MST0:
case JH7110_STGCLK_PCIE1_APB:
case JH7110_STGCLK_PCIE1_TL:
case JH7110_STGCLK_SEC_AHB:
case JH7110_STGCLK_SEC_MISC_AHB:
if (on)
HSET4(sc, idx * 4, 1U << 31);
else
HCLR4(sc, idx * 4, 1U << 31);
return;
}
printf("%s: unknown clock 0x%08x\n", __func__, idx);
}
void
stfclock_reset_jh7110_stg(void *cookie, uint32_t *cells, int assert)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t bits, offset;
offset = JH7110_STGCLK_ASSERT_OFFSET + (idx / 32) * 4;
bits = 1U << (idx % 32);
if (assert)
HSET4(sc, offset, bits);
else
HCLR4(sc, offset, bits);
}
uint32_t
stfclock_get_frequency_jh7110_sys(void *cookie, uint32_t *cells)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t parent, freq;
uint32_t reg, div, mux;
switch (idx) {
case JH7110_SYSCLK_OSC:
return clock_get_frequency(sc->sc_node, "osc");
case JH7110_SYSCLK_GMAC1_RMII_REFIN:
return clock_get_frequency(sc->sc_node, "gmac1_rmii_refin");
case JH7110_SYSCLK_PLL0_OUT:
return clock_get_frequency(sc->sc_node, "pll0_out");
case JH7110_SYSCLK_PLL1_OUT:
return clock_get_frequency(sc->sc_node, "pll1_out");
case JH7110_SYSCLK_PLL2_OUT:
return clock_get_frequency(sc->sc_node, "pll2_out");
}
reg = HREAD4(sc, idx * 4);
mux = (reg & CLKMUX_MASK) >> CLKMUX_SHIFT;
div = (reg & CLKDIV_MASK) >> CLKDIV_SHIFT;
switch (idx) {
case JH7110_SYSCLK_CPU_ROOT:
mux = (reg >> 24) & 1;
parent = mux ? JH7110_SYSCLK_PLL0_OUT : JH7110_SYSCLK_OSC;
return stfclock_get_frequency_jh7110_sys(sc, &parent);
case JH7110_SYSCLK_BUS_ROOT:
mux = (reg >> 24) & 1;
parent = mux ? JH7110_SYSCLK_PLL2_OUT : JH7110_SYSCLK_OSC;
return stfclock_get_frequency_jh7110_sys(sc, &parent);
case JH7110_SYSCLK_GMAC1_TX:
parent = mux ? JH7110_SYSCLK_GMAC1_RMII_RTX :
JH7110_SYSCLK_GMAC1_GTXCLK;
return stfclock_get_frequency_jh7110_sys(sc, &parent);
}
switch (idx) {
case JH7110_SYSCLK_CPU_CORE:
parent = JH7110_SYSCLK_CPU_ROOT;
break;
case JH7110_SYSCLK_AXI_CFG0:
parent = JH7110_SYSCLK_BUS_ROOT;
break;
case JH7110_SYSCLK_STG_AXIAHB:
parent = JH7110_SYSCLK_AXI_CFG0;
break;
case JH7110_SYSCLK_AHB0:
case JH7110_SYSCLK_AHB1:
case JH7110_SYSCLK_APB_BUS:
parent = JH7110_SYSCLK_STG_AXIAHB;
break;
case JH7110_SYSCLK_APB0:
parent = JH7110_SYSCLK_APB_BUS;
div = 1;
break;
case JH7110_SYSCLK_SDIO0_AHB:
case JH7110_SYSCLK_SDIO1_AHB:
parent = JH7110_SYSCLK_AHB0;
break;
case JH7110_SYSCLK_SDIO0_SDCARD:
case JH7110_SYSCLK_SDIO1_SDCARD:
parent = JH7110_SYSCLK_AXI_CFG0;
break;
case JH7110_SYSCLK_GMAC1_AXI:
parent = JH7110_SYSCLK_STG_AXIAHB;
div = 1;
break;
case JH7110_SYSCLK_GMAC1_GTXCLK:
parent = JH7110_SYSCLK_PLL0_OUT;
break;
case JH7110_SYSCLK_GMAC1_RMII_RTX:
parent = JH7110_SYSCLK_GMAC1_RMII_REFIN;
break;
case JH7110_SYSCLK_GMAC1_TX_INV:
parent = JH7110_SYSCLK_GMAC1_TX;
div = 1;
break;
case JH7110_SYSCLK_GMAC0_GTXCLK:
parent = JH7110_SYSCLK_PLL0_OUT;
break;
case JH7110_SYSCLK_TEMP_APB:
parent = JH7110_SYSCLK_APB_BUS;
break;
case JH7110_SYSCLK_TEMP_CORE:
parent = JH7110_SYSCLK_OSC;
break;
case JH7110_SYSCLK_I2C0_APB:
case JH7110_SYSCLK_I2C1_APB:
case JH7110_SYSCLK_I2C2_APB:
parent = JH7110_SYSCLK_APB0;
div = 1;
break;
case JH7110_SYSCLK_I2C3_APB:
case JH7110_SYSCLK_I2C4_APB:
case JH7110_SYSCLK_I2C5_APB:
case JH7110_SYSCLK_I2C6_APB:
parent = JH7110_SYSCLK_APB_BUS;
div = 1;
break;
case JH7110_SYSCLK_UART0_CORE:
parent = JH7110_SYSCLK_OSC;
div = 1;
break;
default:
printf("%s: unknown clock 0x%08x\n", __func__, idx);
return 0;
}
if (div == 0) {
printf("%s: zero divisor for clock 0x%08x\n", __func__, idx);
return 0;
}
freq = stfclock_get_frequency_jh7110_sys(sc, &parent);
return freq / div;
}
int
stfclock_set_frequency_jh7110_sys(void *cookie, uint32_t *cells, uint32_t freq)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t parent, parent_freq;
uint32_t reg, div, mux;
switch (idx) {
case JH7110_SYSCLK_GMAC1_RMII_REFIN:
return clock_set_frequency(sc->sc_node, "gmac1_rmii_refin", freq);
}
if (idx == JH7110_SYSCLK_CPU_CORE &&
clock_get_frequency(sc->sc_node, "pll0_out") != 1500000000) {
reg = HREAD4(sc, idx * 4);
reg &= ~CLKDIV_MASK;
reg |= (2 << CLKDIV_SHIFT);
HWRITE4(sc, idx * 4, reg);
clock_set_frequency(sc->sc_node, "pll0_out", 1500000000);
}
reg = HREAD4(sc, idx * 4);
mux = (reg & CLKMUX_MASK) >> CLKMUX_SHIFT;
switch (idx) {
case JH7110_SYSCLK_GMAC1_TX:
parent = mux ? JH7110_SYSCLK_GMAC1_RMII_RTX :
JH7110_SYSCLK_GMAC1_GTXCLK;
return stfclock_set_frequency_jh7110_sys(sc, &parent, freq);
case JH7110_SYSCLK_GMAC1_TX_INV:
parent = JH7110_SYSCLK_GMAC1_TX;
return stfclock_set_frequency_jh7110_sys(sc, &parent, freq);
}
switch (idx) {
case JH7110_SYSCLK_CPU_CORE:
parent = JH7110_SYSCLK_CPU_ROOT;
break;
case JH7110_SYSCLK_SDIO0_SDCARD:
case JH7110_SYSCLK_SDIO1_SDCARD:
parent = JH7110_SYSCLK_AXI_CFG0;
break;
case JH7110_SYSCLK_GMAC1_GTXCLK:
parent = JH7110_SYSCLK_PLL0_OUT;
break;
case JH7110_SYSCLK_GMAC1_RMII_RTX:
parent = JH7110_SYSCLK_GMAC1_RMII_REFIN;
break;
case JH7110_SYSCLK_GMAC0_GTXCLK:
parent = JH7110_SYSCLK_PLL0_OUT;
break;
default:
printf("%s: not handled 0x%08x (freq=0x%08x)\n",
__func__, idx, freq);
return -1;
}
parent_freq = stfclock_get_frequency_jh7110_sys(sc, &parent);
div = (parent_freq + freq / 2) / freq;
if (div == 0)
div = 1;
reg &= ~CLKDIV_MASK;
reg |= (div << CLKDIV_SHIFT);
HWRITE4(sc, idx * 4, reg);
return 0;
}
void
stfclock_enable_jh7110_sys(void *cookie, uint32_t *cells, int on)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t parent;
switch (idx) {
case JH7110_SYSCLK_GMAC1_TX_INV:
idx = JH7110_SYSCLK_GMAC1_TX;
break;
case JH7110_SYSCLK_GMAC1_GTXC:
parent = JH7110_SYSCLK_GMAC1_GTXCLK;
stfclock_enable_jh7110_sys(sc, &parent, on);
break;
case JH7110_SYSCLK_GMAC0_GTXC:
parent = JH7110_SYSCLK_GMAC0_GTXCLK;
stfclock_enable_jh7110_sys(sc, &parent, on);
break;
}
switch (idx) {
case JH7110_SYSCLK_SDIO0_AHB:
case JH7110_SYSCLK_SDIO1_AHB:
case JH7110_SYSCLK_SDIO0_SDCARD:
case JH7110_SYSCLK_SDIO1_SDCARD:
case JH7110_SYSCLK_NOC_BUS_STG_AXI:
case JH7110_SYSCLK_GMAC1_AHB:
case JH7110_SYSCLK_GMAC1_AXI:
case JH7110_SYSCLK_GMAC1_GTXCLK:
case JH7110_SYSCLK_GMAC1_PTP:
case JH7110_SYSCLK_GMAC1_TX:
case JH7110_SYSCLK_GMAC1_GTXC:
case JH7110_SYSCLK_GMAC0_GTXCLK:
case JH7110_SYSCLK_GMAC0_PTP:
case JH7110_SYSCLK_GMAC0_GTXC:
case JH7110_SYSCLK_IOMUX_APB:
case JH7110_SYSCLK_TEMP_APB:
case JH7110_SYSCLK_TEMP_CORE:
case JH7110_SYSCLK_I2C0_APB:
case JH7110_SYSCLK_I2C1_APB:
case JH7110_SYSCLK_I2C2_APB:
case JH7110_SYSCLK_I2C3_APB:
case JH7110_SYSCLK_I2C4_APB:
case JH7110_SYSCLK_I2C5_APB:
case JH7110_SYSCLK_I2C6_APB:
case JH7110_SYSCLK_UART0_CORE:
if (on)
HSET4(sc, idx * 4, 1U << 31);
else
HCLR4(sc, idx * 4, 1U << 31);
return;
}
printf("%s: unknown clock 0x%08x\n", __func__, idx);
}
void
stfclock_reset_jh7110_sys(void *cookie, uint32_t *cells, int assert)
{
struct stfclock_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t bits, offset;
offset = JH7110_SYSCLK_ASSERT_OFFSET + (idx / 32) * 4;
bits = 1U << (idx % 32);
if (assert)
HSET4(sc, offset, bits);
else
HCLR4(sc, offset, bits);
}