Add support for RK3288 SoC.

This commit is contained in:
Michal Meloun 2020-12-04 16:24:44 +00:00
parent a920b9817e
commit b0352107f1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=368340
14 changed files with 2038 additions and 1 deletions

View File

@ -0,0 +1,31 @@
# $FreeBSD$
kern/kern_clocksource.c standard
arm/rockchip/rk32xx_machdep.c standard
arm/rockchip/rk32xx_mp.c optional smp
arm64/rockchip/if_dwc_rk.c standard
arm64/rockchip/rk_i2c.c standard
arm64/rockchip/rk_iodomain.c standard
arm64/rockchip/rk_gpio.c standard
arm64/rockchip/rk_grf.c standard
arm64/rockchip/rk_pinctrl.c standard
arm64/rockchip/rk_pmu.c standard
arm64/rockchip/rk_pwm.c standard
arm64/rockchip/rk_tsadc.c standard
arm64/rockchip/rk_tsadc_if.m standard
arm64/rockchip/rk_usbphy.c standard
arm64/rockchip/clk/rk_clk_armclk.c standard
arm64/rockchip/clk/rk_clk_composite.c standard
arm64/rockchip/clk/rk_clk_fract.c standard
arm64/rockchip/clk/rk_clk_gate.c standard
arm64/rockchip/clk/rk_clk_mux.c standard
arm64/rockchip/clk/rk_clk_pll.c standard
arm64/rockchip/clk/rk_cru.c standard
arm64/rockchip/clk/rk3288_cru.c standard
dev/iicbus/pmic/act8846.c standard
dev/iicbus/pmic/act8846_regulator.c standard
dev/iicbus/pmic/fan53555.c standard
dev/iicbus/rtc/hym8563.c standard
dev/mmc/host/dwmmc.c optional dwmmc
dev/mmc/host/dwmmc_rockchip.c optional dwmmc

View File

@ -0,0 +1,126 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "opt_platform.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/devmap.h>
#include <sys/lock.h>
#include <sys/reboot.h>
#include <vm/vm.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/intr.h>
#include <machine/machdep.h>
#include <machine/platformvar.h>
#include <dev/ofw/openfirm.h>
#include <arm/rockchip/rk32xx_mp.h>
#include "platform_if.h"
#define CRU_PHYSBASE 0xFF760000
#define CRU_SIZE 0x00010000
#define CRU_GLB_SRST_FST_VALUE 0x1B0
static platform_def_t rk3288w_platform;
static void
rk32xx_late_init(platform_t plat)
{
}
/*
* Set up static device mappings.
*/
static int
rk32xx_devmap_init(platform_t plat)
{
devmap_add_entry(0xFF000000, 0x00E00000);
return (0);
}
static void
rk32xx_cpu_reset(platform_t plat)
{
bus_space_handle_t cru;
printf("Resetting...\n");
bus_space_map(fdtbus_bs_tag, CRU_PHYSBASE, CRU_SIZE, 0, &cru);
spinlock_enter();
dsb();
/* Generate 'first global software reset' */
bus_space_write_4(fdtbus_bs_tag, cru, CRU_GLB_SRST_FST_VALUE, 0xfdb9);
while(1)
;
}
/*
* Early putc routine for EARLY_PRINTF support. To use, add to kernel config:
* option SOCDEV_PA=0xFF600000
* option SOCDEV_VA=0x70000000
* option EARLY_PRINTF
*/
#if 0
#ifdef EARLY_PRINTF
static void
rk32xx_early_putc(int c)
{
volatile uint32_t * UART_STAT_REG = (uint32_t *)(0x7009007C);
volatile uint32_t * UART_TX_REG = (uint32_t *)(0x70090000);
const uint32_t UART_TXRDY = (1 << 2);
while ((*UART_STAT_REG & UART_TXRDY) == 0)
continue;
*UART_TX_REG = c;
}
early_putc_t *early_putc = rk32xx_early_putc;
#endif
#endif
static platform_method_t rk32xx_methods[] = {
PLATFORMMETHOD(platform_devmap_init, rk32xx_devmap_init),
PLATFORMMETHOD(platform_late_init, rk32xx_late_init),
PLATFORMMETHOD(platform_cpu_reset, rk32xx_cpu_reset),
#ifdef SMP
PLATFORMMETHOD(platform_mp_start_ap, rk32xx_mp_start_ap),
PLATFORMMETHOD(platform_mp_setmaxid, rk32xx_mp_setmaxid),
#endif
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF2(rk32xx, rk3288, "RK3288", 0, "rockchip,rk3288", 200);
FDT_PLATFORM_DEF2(rk32xx, rk3288w, "RK3288W", 0, "rockchip,rk3288w", 200);

View File

@ -0,0 +1,174 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/smp.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/cpu.h>
#include <machine/fdt.h>
#include <machine/smp.h>
#include <machine/platformvar.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_cpu.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/psci/psci.h>
#include <arm/rockchip/rk32xx_mp.h>
#define IMEM_PHYSBASE 0xFF700000
#define IMEM_SIZE 0x00018000
#define PMU_PHYSBASE 0xFF730000
#define PMU_SIZE 0x00010000
#define PMU_PWRDN_CON 0x08
static int running_cpus;
static uint32_t psci_mask, pmu_mask;
void
rk32xx_mp_setmaxid(platform_t plat)
{
int ncpu;
/* If we've already set the global vars don't bother to do it again. */
if (mp_ncpus != 0)
return;
/* Read current CP15 Cache Size ID Register */
ncpu = cp15_l2ctlr_get();
ncpu = CPUV7_L2CTLR_NPROC(ncpu);
mp_ncpus = ncpu;
mp_maxid = ncpu - 1;
}
static void
rk32xx_mp_start_pmu(uint32_t mask)
{
bus_space_handle_t imem;
bus_space_handle_t pmu;
uint32_t val;
int i, rv;
rv = bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE, IMEM_SIZE, 0, &imem);
if (rv != 0)
panic("Couldn't map the IMEM\n");
rv = bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu);
if (rv != 0)
panic("Couldn't map the PMU\n");
/* Power off all secondary cores first */
val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
for (i = 1; i < mp_ncpus; i++)
val |= 1 << i;
bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
DELAY(5000);
/* Power up all secondary cores */
val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
for (i = 1; i < mp_ncpus; i++)
val &= ~(1 << i);
bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
DELAY(5000);
/* Copy mpentry address then magic to sram */
val = pmap_kextract((vm_offset_t)mpentry);
bus_space_write_4(fdtbus_bs_tag, imem, 8, val);
dsb();
bus_space_write_4(fdtbus_bs_tag, imem, 4, 0xDEADBEAF);
dsb();
sev();
bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE);
bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE);
}
static boolean_t
rk32xx_start_ap(u_int id, phandle_t node, u_int addr_cells, pcell_t *reg)
{
int rv;
char method[16];
uint32_t mask;
if (!ofw_bus_node_status_okay(node))
return(false);
/* Skip boot CPU. */
if (id == 0)
return (true);
if (running_cpus >= mp_ncpus)
return (false);
running_cpus++;
mask = 1 << (*reg & 0x0f);
#ifdef INVARIANTS
if ((mask & pmu_mask) || (mask & psci_mask))
printf("CPU: Duplicated register value: 0x%X for CPU(%d)\n",
*reg, id);
#endif
rv = OF_getprop(node, "enable-method", method, sizeof(method));
if (rv > 0 && strcmp(method, "psci") == 0) {
psci_mask |= mask;
rv = psci_cpu_on(*reg, pmap_kextract((vm_offset_t)mpentry), id);
if (rv != PSCI_RETVAL_SUCCESS) {
printf("Failed to start CPU(%d)\n", id);
return (false);
}
return (true);
}
pmu_mask |= mask;
return (true);
}
void
rk32xx_mp_start_ap(platform_t plat)
{
ofw_cpu_early_foreach(rk32xx_start_ap, true);
if (pmu_mask != 0 && psci_mask != 0) {
printf("Inconsistent CPUs startup methods detected.\n");
printf("Only PSCI enabled cores will be started.\n");
return;
}
if (pmu_mask != 0)
rk32xx_mp_start_pmu(pmu_mask);
}

View File

@ -0,0 +1,36 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _RK32XX_MP_H_
#define _RK32XX_MP_H_
void rk32xx_mp_setmaxid(platform_t plat);
void rk32xx_mp_start_ap(platform_t plat);
#endif /* _RK32XX_MP_H_ */

View File

@ -0,0 +1,8 @@
# Rockchip rk32xx common options
#$FreeBSD$
cpu CPU_CORTEXA
machine arm armv7
makeoptions CONF_CFLAGS="-mcpu=cortex-a17"
files "../rockchip/files.rk32xx"

File diff suppressed because it is too large Load Diff

View File

@ -97,6 +97,249 @@ rk_clk_pll_set_gate(struct clknode *clk, bool enable)
return (0);
}
/* CON0 */
#define RK3066_CLK_PLL_REFDIV_SHIFT 8
#define RK3066_CLK_PLL_REFDIV_MASK 0x3F00
#define RK3066_CLK_PLL_POSTDIV_SHIFT 0
#define RK3066_CLK_PLL_POSTDIV_MASK 0x000F
/* CON1 */
#define RK3066_CLK_PLL_LOCK_MASK (1U << 31)
#define RK3066_CLK_PLL_FBDIV_SHIFT 0
#define RK3066_CLK_PLL_FBDIV_MASK 0x0FFF
/* CON2 */
/* CON3 */
#define RK3066_CLK_PLL_RESET (1 << 5)
#define RK3066_CLK_PLL_TEST (1 << 4)
#define RK3066_CLK_PLL_ENSAT (1 << 3)
#define RK3066_CLK_PLL_FASTEN (1 << 2)
#define RK3066_CLK_PLL_POWER_DOWN (1 << 1)
#define RK3066_CLK_PLL_BYPASS (1 << 0)
#define RK3066_CLK_PLL_MODE_SLOW 0
#define RK3066_CLK_PLL_MODE_NORMAL 1
#define RK3066_CLK_PLL_MODE_DEEP_SLOW 2
#define RK3066_CLK_PLL_MODE_MASK 0x3
static int
rk3066_clk_pll_init(struct clknode *clk, device_t dev)
{
struct rk_clk_pll_sc *sc;
uint32_t reg;
sc = clknode_get_softc(clk);
DEVICE_LOCK(clk);
READ4(clk, sc->mode_reg, &reg);
DEVICE_UNLOCK(clk);
reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
clknode_init_parent_idx(clk, reg);
return (0);
}
static int
rk3066_clk_pll_set_mux(struct clknode *clk, int idx)
{
uint32_t reg;
struct rk_clk_pll_sc *sc;
sc = clknode_get_softc(clk);
reg = (idx & RK3066_CLK_PLL_MODE_MASK) << sc->mode_shift;
reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
RK_CLK_PLL_MASK_SHIFT;
DEVICE_LOCK(clk);
WRITE4(clk, sc->mode_reg, reg);
DEVICE_UNLOCK(clk);
return(0);
}
static int
rk3066_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
{
struct rk_clk_pll_sc *sc;
uint64_t rate;
uint32_t refdiv, fbdiv, postdiv;
uint32_t raw0, raw1, raw2, reg;
sc = clknode_get_softc(clk);
DEVICE_LOCK(clk);
READ4(clk, sc->base_offset, &raw0);
READ4(clk, sc->base_offset + 4, &raw1);
READ4(clk, sc->base_offset + 8, &raw2);
READ4(clk, sc->mode_reg, &reg);
DEVICE_UNLOCK(clk);
reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
if (reg != RK3066_CLK_PLL_MODE_NORMAL)
return (0);
if (!(raw1 & RK3066_CLK_PLL_LOCK_MASK)) {
*freq = 0;
return (0);
}
/* TODO MUX */
refdiv = (raw0 & RK3066_CLK_PLL_REFDIV_MASK) >>
RK3066_CLK_PLL_REFDIV_SHIFT;
refdiv += 1;
postdiv = (raw0 & RK3066_CLK_PLL_POSTDIV_MASK) >>
RK3066_CLK_PLL_POSTDIV_SHIFT;
postdiv += 1;
fbdiv = (raw1 & RK3066_CLK_PLL_FBDIV_MASK) >>
RK3066_CLK_PLL_FBDIV_SHIFT;
fbdiv += 1;
rate = *freq * fbdiv;
rate /= refdiv;
*freq = rate / postdiv;
return (0);
}
static int
rk3066_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
int flags, int *stop)
{
struct rk_clk_pll_rate *rates;
struct rk_clk_pll_sc *sc;
uint32_t reg;
int rv, timeout;
sc = clknode_get_softc(clk);
if (sc->rates == NULL)
return (EINVAL);
for (rates = sc->rates; rates->freq; rates++) {
if (rates->freq == *fout)
break;
}
if (rates->freq == 0) {
*stop = 1;
return (EINVAL);
}
DEVICE_LOCK(clk);
/* Setting to slow mode during frequency change */
reg = (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
RK_CLK_PLL_MASK_SHIFT;
dprintf("Set PLL_MODEREG to %x\n", reg);
WRITE4(clk, sc->mode_reg, reg);
/* Reset PLL */
WRITE4(clk, sc->base_offset + 12, RK3066_CLK_PLL_RESET |
RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
/* Setting postdiv and refdiv */
reg = 0;
reg |= RK3066_CLK_PLL_POSTDIV_MASK << 16;
reg |= (rates->postdiv1 - 1) << RK3066_CLK_PLL_POSTDIV_SHIFT;
reg |= RK3066_CLK_PLL_REFDIV_MASK << 16;
reg |= (rates->refdiv - 1)<< RK3066_CLK_PLL_REFDIV_SHIFT;
dprintf("Set PLL_CON0 to %x\n", reg);
WRITE4(clk, sc->base_offset, reg);
/* Setting fbdiv (no write mask)*/
READ4(clk, sc->base_offset + 4, &reg);
reg &= ~RK3066_CLK_PLL_FBDIV_MASK;
reg |= RK3066_CLK_PLL_FBDIV_MASK << 16;
reg = (rates->fbdiv - 1) << RK3066_CLK_PLL_FBDIV_SHIFT;
dprintf("Set PLL_CON1 to %x\n", reg);
WRITE4(clk, sc->base_offset + 0x4, reg);
/* PLL loop bandwidth adjust */
reg = rates->bwadj - 1;
dprintf("Set PLL_CON2 to %x (%x)\n", reg, rates->bwadj);
WRITE4(clk, sc->base_offset + 0x8, reg);
/* Clear reset */
WRITE4(clk, sc->base_offset + 12,
RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
DELAY(100000);
/* Reading lock */
for (timeout = 1000; timeout >= 0; timeout--) {
READ4(clk, sc->base_offset + 0x4, &reg);
if ((reg & RK3066_CLK_PLL_LOCK_MASK) != 0)
break;
DELAY(1);
}
rv = 0;
if (timeout < 0) {
device_printf(clknode_get_device(clk),
"%s - Timedout while waiting for lock.\n",
clknode_get_name(clk));
dprintf("PLL_CON1: %x\n", reg);
rv = ETIMEDOUT;
}
/* Set back to normal mode */
reg = (RK3066_CLK_PLL_MODE_NORMAL << sc->mode_shift);
reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
RK_CLK_PLL_MASK_SHIFT;
dprintf("Set PLL_MODEREG to %x\n", reg);
WRITE4(clk, sc->mode_reg, reg);
DEVICE_UNLOCK(clk);
*stop = 1;
rv = clknode_set_parent_by_idx(clk, 1);
return (rv);
}
static clknode_method_t rk3066_clk_pll_clknode_methods[] = {
/* Device interface */
CLKNODEMETHOD(clknode_init, rk3066_clk_pll_init),
CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
CLKNODEMETHOD(clknode_recalc_freq, rk3066_clk_pll_recalc),
CLKNODEMETHOD(clknode_set_freq, rk3066_clk_pll_set_freq),
CLKNODEMETHOD(clknode_set_mux, rk3066_clk_pll_set_mux),
CLKNODEMETHOD_END
};
DEFINE_CLASS_1(rk3066_clk_pll_clknode, rk3066_clk_pll_clknode_class,
rk3066_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
int
rk3066_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
{
struct clknode *clk;
struct rk_clk_pll_sc *sc;
clk = clknode_create(clkdom, &rk3066_clk_pll_clknode_class,
&clkdef->clkdef);
if (clk == NULL)
return (1);
sc = clknode_get_softc(clk);
sc->base_offset = clkdef->base_offset;
sc->gate_offset = clkdef->gate_offset;
sc->gate_shift = clkdef->gate_shift;
sc->mode_reg = clkdef->mode_reg;
sc->mode_shift = clkdef->mode_shift;
sc->flags = clkdef->flags;
sc->rates = clkdef->rates;
sc->frac_rates = clkdef->frac_rates;
clknode_register(clkdom, clk);
return (0);
}
#define RK3328_CLK_PLL_FBDIV_OFFSET 0
#define RK3328_CLK_PLL_FBDIV_SHIFT 0
#define RK3328_CLK_PLL_FBDIV_MASK 0xFFF

View File

@ -40,6 +40,7 @@ struct rk_clk_pll_rate {
uint32_t postdiv2;
uint32_t dsmpd;
uint32_t frac;
uint32_t bwadj;
};
struct rk_clk_pll_def {
@ -60,6 +61,7 @@ struct rk_clk_pll_def {
#define RK_CLK_PLL_HAVE_GATE 0x1
int rk3066_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef);
int rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef);
int rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef);

View File

@ -233,6 +233,10 @@ rk_cru_attach(device_t dev)
switch (sc->clks[i].type) {
case RK_CLK_UNDEFINED:
break;
case RK3066_CLK_PLL:
rk3066_clk_pll_register(sc->clkdom,
sc->clks[i].clk.pll);
break;
case RK3328_CLK_PLL:
rk3328_clk_pll_register(sc->clkdom,
sc->clks[i].clk.pll);

View File

@ -205,6 +205,7 @@ struct rk_cru_gate {
enum rk_clk_type {
RK_CLK_UNDEFINED = 0,
RK3066_CLK_PLL,
RK3328_CLK_PLL,
RK3399_CLK_PLL,
RK_CLK_COMPOSITE,

View File

@ -0,0 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/extres/syscon/syscon.h>
#include <dev/fdt/simple_mfd.h>
static struct ofw_compat_data compat_data[] = {
{"rockchip,rk3288-pmu", 1},
{NULL, 0}
};
static int
rk_pmu_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
return (ENXIO);
device_set_desc(dev, "RockChip Power Management Unit");
return (BUS_PROBE_DEFAULT);
}
static device_method_t rk_pmu_methods[] = {
DEVMETHOD(device_probe, rk_pmu_probe),
DEVMETHOD_END
};
DEFINE_CLASS_1(rk_pmu, rk_pmu_driver, rk_pmu_methods,
sizeof(struct simple_mfd_softc), simple_mfd_driver);
static devclass_t rk_pmu_devclass;
EARLY_DRIVER_MODULE(rk_pmu, simplebus, rk_pmu_driver, rk_pmu_devclass,
0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
MODULE_VERSION(rk_pmu, 1);

View File

@ -99,6 +99,7 @@ __FBSDID("$FreeBSD$");
#define NS_PER_SEC 1000000000
static struct ofw_compat_data compat_data[] = {
{ "rockchip,rk3288-pwm", 1 },
{ "rockchip,rk3399-pwm", 1 },
{ NULL, 0 }
};

View File

@ -692,7 +692,8 @@ tsadc_attach(device_t dev)
}
/* Set the assigned clocks parent and freq */
if (clk_set_assigned(sc->dev, node) != 0) {
rv = clk_set_assigned(sc->dev, node);
if (rv != 0 && rv != ENOENT) {
device_printf(dev, "clk_set_assigned failed\n");
goto fail;
}

View File

@ -0,0 +1,307 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/gpio.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <dev/extres/clk/clk.h>
#include <dev/extres/hwreset/hwreset.h>
#include <dev/extres/phy/phy_usb.h>
#include <dev/extres/regulator/regulator.h>
#include <dev/extres/syscon/syscon.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/extres/syscon/syscon.h>
#include <dev/fdt/simple_mfd.h>
#include "phynode_if.h"
#include "phynode_usb_if.h"
#include "syscon_if.h"
/* Phy registers */
#define UOC_CON0 0x00
#define UOC_CON0_SIDDQ (1 << 13)
#define UOC_CON0_DISABLE (1 << 4)
#define UOC_CON0_COMMON_ON_N (1 << 0)
#define UOC_CON2 0x08
#define UOC_CON2_SOFT_CON_SEL (1 << 2)
#define UOC_CON3 0x0c
#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
static struct ofw_compat_data compat_data[] = {
{"rockchip,rk3288-usb-phy", 1},
{NULL, 0},
};
struct rk_usbphy_softc {
device_t dev;
};
struct rk_phynode_sc {
struct phynode_usb_sc usb_sc;
uint32_t base;
int mode;
clk_t clk;
hwreset_t hwreset;
regulator_t supply_vbus;
struct syscon *syscon;
};
static int
rk_phynode_phy_enable(struct phynode *phy, bool enable)
{
struct rk_phynode_sc *sc;
int rv;
sc = phynode_get_softc(phy);
rv = SYSCON_MODIFY_4(sc->syscon,
sc->base + UOC_CON0,
UOC_CON0_SIDDQ << 16 | UOC_CON0_SIDDQ,
enable ? 0 : UOC_CON0_SIDDQ);
return (rv);
}
static int
rk_phynode_get_mode(struct phynode *phynode, int *mode)
{
struct rk_phynode_sc *sc;
sc = phynode_get_softc(phynode);
*mode = sc->mode;
return (0);
}
static int
rk_phynode_set_mode(struct phynode *phynode, int mode)
{
struct rk_phynode_sc *sc;
sc = phynode_get_softc(phynode);
sc->mode = mode;
return (0);
}
/* Phy controller class and methods. */
static phynode_method_t rk_phynode_methods[] = {
PHYNODEUSBMETHOD(phynode_enable, rk_phynode_phy_enable),
PHYNODEMETHOD(phynode_usb_get_mode, rk_phynode_get_mode),
PHYNODEMETHOD(phynode_usb_set_mode, rk_phynode_set_mode),
PHYNODEUSBMETHOD_END
};
DEFINE_CLASS_1(rk_phynode, rk_phynode_class, rk_phynode_methods,
sizeof(struct rk_phynode_sc), phynode_usb_class);
static int
rk_usbphy_init_phy(struct rk_usbphy_softc *sc, phandle_t node)
{
struct phynode *phynode;
struct phynode_init_def phy_init;
struct rk_phynode_sc *phy_sc;
int rv;
uint32_t base;
clk_t clk;
hwreset_t hwreset;
regulator_t supply_vbus;
struct syscon *syscon;
clk = NULL;
hwreset = NULL;
supply_vbus = NULL;
rv = OF_getencprop(node, "reg", &base, sizeof(base));
if (rv <= 0) {
device_printf(sc->dev, "cannot get 'reg' property.\n");
goto fail;
}
/* FDT resources. All are optional. */
rv = clk_get_by_ofw_name(sc->dev, node, "phyclk", &clk);
if (rv != 0 && rv != ENOENT) {
device_printf(sc->dev, "cannot get 'phyclk' clock.\n");
goto fail;
}
rv = hwreset_get_by_ofw_name(sc->dev, node, "phy-reset", &hwreset);
if (rv != 0 && rv != ENOENT) {
device_printf(sc->dev, "Cannot get 'phy-reset' reset\n");
goto fail;
}
rv = regulator_get_by_ofw_property(sc->dev, node, "vbus-supply",
&supply_vbus);
if (rv != 0 && rv != ENOENT) {
device_printf(sc->dev, "Cannot get 'vbus' regulator.\n");
goto fail;
}
rv = SYSCON_GET_HANDLE(sc->dev, &syscon);
if (rv != 0) {
device_printf(sc->dev, "Cannot get parent syscon\n");
goto fail;
}
/* Init HW resources */
if (hwreset != NULL) {
rv = hwreset_assert(hwreset);
if (rv != 0) {
device_printf(sc->dev, "Cannot assert reset\n");
goto fail;
}
}
if (clk != NULL) {
rv = clk_enable(clk);
if (rv != 0) {
device_printf(sc->dev,
"Cannot enable 'phyclk' clock.\n");
goto fail;
}
}
if (hwreset != NULL) {
rv = hwreset_deassert(hwreset);
if (rv != 0) {
device_printf(sc->dev, "Cannot deassert reset\n");
goto fail;
}
}
/* Create and register phy. */
bzero(&phy_init, sizeof(phy_init));
phy_init.id = 1;
phy_init.ofw_node = node;
phynode = phynode_create(sc->dev, &rk_phynode_class, &phy_init);
if (phynode == NULL) {
device_printf(sc->dev, "Cannot create phy.\n");
return (ENXIO);
}
phy_sc = phynode_get_softc(phynode);
phy_sc->base = base;
phy_sc->clk = clk;
phy_sc->hwreset = hwreset;
phy_sc->supply_vbus = supply_vbus;
phy_sc->syscon = syscon;
if (phynode_register(phynode) == NULL) {
device_printf(sc->dev, "Cannot register phy.\n");
return (ENXIO);
}
/* XXX It breaks boot */
/* rk_phynode_phy_enable(phynode, 1); */
return (0);
fail:
if (supply_vbus != NULL)
regulator_release(supply_vbus);
if (clk != NULL)
clk_release(clk);
if (hwreset != NULL)
hwreset_release(hwreset);
return (ENXIO);
}
static int
rk_usbphy_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
return (ENXIO);
device_set_desc(dev, "RockChip USB Phy");
return (BUS_PROBE_DEFAULT);
}
static int
rk_usbphy_attach(device_t dev)
{
struct rk_usbphy_softc *sc;
phandle_t node, child;
int rv;
sc = device_get_softc(dev);
sc->dev = dev;
node = ofw_bus_get_node(sc->dev);
/* Attach child devices */
for (child = OF_child(node); child > 0; child = OF_peer(child)) {
rv = rk_usbphy_init_phy(sc, child);
if (rv != 0)
goto fail;
}
return (bus_generic_attach(dev));
fail:
return (ENXIO);
}
static int
rk_usbphy_detach(device_t dev)
{
struct rk_usbphy_softc *sc;
sc = device_get_softc(dev);
return (0);
}
static device_method_t rk_usbphy_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, rk_usbphy_probe),
DEVMETHOD(device_attach, rk_usbphy_attach),
DEVMETHOD(device_detach, rk_usbphy_detach),
DEVMETHOD_END
};
static devclass_t rk_usbphy_devclass;
static DEFINE_CLASS_0(rk_usbphy, rk_usbphy_driver, rk_usbphy_methods,
sizeof(struct rk_usbphy_softc));
EARLY_DRIVER_MODULE(rk_usbphy, simplebus, rk_usbphy_driver,
rk_usbphy_devclass, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_LAST);