- Update SiFive Unleashed clock driver.
- Enables SiFive SPI driver and MMC SPI driver for SiFive Unleashed
  board
This commit is contained in:
Tom Rini 2019-07-19 10:11:45 -04:00
commit cfe987ea84
16 changed files with 487 additions and 490 deletions

View File

@ -28,7 +28,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply CMD_PING
imply CLK_SIFIVE
imply CLK_SIFIVE_FU540_PRCI
imply CLK_SIFIVE_GEMGXL_MGMT
imply DOS_PARTITION
imply EFI_PARTITION
imply IP_DYN
@ -39,6 +38,12 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply PHY_LIB
imply PHY_MSCC
imply SIFIVE_SERIAL
imply SPI
imply SPI_SIFIVE
imply MMC
imply MMC_SPI
imply MMC_BROKEN_CD
imply CMD_MMC
imply SMP
endif

View File

@ -8,6 +8,128 @@
#include <common.h>
#include <dm.h>
#include <linux/delay.h>
#include <linux/io.h>
#ifdef CONFIG_MISC_INIT_R
#define FU540_OTP_BASE_ADDR 0x10070000
struct fu540_otp_regs {
u32 pa; /* Address input */
u32 paio; /* Program address input */
u32 pas; /* Program redundancy cell selection input */
u32 pce; /* OTP Macro enable input */
u32 pclk; /* Clock input */
u32 pdin; /* Write data input */
u32 pdout; /* Read data output */
u32 pdstb; /* Deep standby mode enable input (active low) */
u32 pprog; /* Program mode enable input */
u32 ptc; /* Test column enable input */
u32 ptm; /* Test mode enable input */
u32 ptm_rep;/* Repair function test mode enable input */
u32 ptr; /* Test row enable input */
u32 ptrim; /* Repair function enable input */
u32 pwe; /* Write enable input (defines program cycle) */
} __packed;
#define BYTES_PER_FUSE 4
#define NUM_FUSES 0x1000
static int fu540_otp_read(int offset, void *buf, int size)
{
struct fu540_otp_regs *regs = (void __iomem *)FU540_OTP_BASE_ADDR;
unsigned int i;
int fuseidx = offset / BYTES_PER_FUSE;
int fusecount = size / BYTES_PER_FUSE;
u32 fusebuf[fusecount];
/* check bounds */
if (offset < 0 || size < 0)
return -EINVAL;
if (fuseidx >= NUM_FUSES)
return -EINVAL;
if ((fuseidx + fusecount) > NUM_FUSES)
return -EINVAL;
/* init OTP */
writel(0x01, &regs->pdstb); /* wake up from stand-by */
writel(0x01, &regs->ptrim); /* enable repair function */
writel(0x01, &regs->pce); /* enable input */
/* read all requested fuses */
for (i = 0; i < fusecount; i++, fuseidx++) {
writel(fuseidx, &regs->pa);
/* cycle clock to read */
writel(0x01, &regs->pclk);
mdelay(1);
writel(0x00, &regs->pclk);
mdelay(1);
/* read the value */
fusebuf[i] = readl(&regs->pdout);
}
/* shut down */
writel(0, &regs->pce);
writel(0, &regs->ptrim);
writel(0, &regs->pdstb);
/* copy out */
memcpy(buf, fusebuf, size);
return 0;
}
static u32 fu540_read_serialnum(void)
{
int ret;
u32 serial[2] = {0};
for (int i = 0xfe * 4; i > 0; i -= 8) {
ret = fu540_otp_read(i, serial, sizeof(serial));
if (ret) {
printf("%s: error reading from OTP\n", __func__);
break;
}
if (serial[0] == ~serial[1])
return serial[0];
}
return 0;
}
static void fu540_setup_macaddr(u32 serialnum)
{
/* Default MAC address */
unsigned char mac[6] = { 0x70, 0xb3, 0xd5, 0x92, 0xf0, 0x00 };
/*
* We derive our board MAC address by ORing last three bytes
* of board serial number to above default MAC address.
*
* This logic of deriving board MAC address is taken from
* SiFive FSBL and is kept unchanged.
*/
mac[5] |= (serialnum >> 0) & 0xff;
mac[4] |= (serialnum >> 8) & 0xff;
mac[3] |= (serialnum >> 16) & 0xff;
/* Update environment variable */
eth_env_set_enetaddr("ethaddr", mac);
}
int misc_init_r(void)
{
/* Set ethaddr environment variable if not set */
if (!env_get("ethaddr"))
fu540_setup_macaddr(fu540_read_serialnum());
return 0;
}
#endif
int board_init(void)
{

View File

@ -7,4 +7,5 @@ CONFIG_DISTRO_DEFAULTS=y
CONFIG_FIT=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_MISC_INIT_R=y
CONFIG_OF_PRIOR_STAGE=y

View File

@ -13,8 +13,7 @@ The support for following drivers are already enabled:
3. Cadence MACB ethernet driver for networking support.
TODO:
1. SPI driver is still missing. So MMC card can't be used in U-Boot as of now.
2. U-Boot expects the serial console device entry to be present under /chosen
1. U-Boot expects the serial console device entry to be present under /chosen
DT node. Example:
chosen {
stdout-path = "/soc/serial@10010000:115200";
@ -33,16 +32,21 @@ Building
Flashing
========
The current U-Boot port is supported in S-mode only and loaded from DRAM.
The current U-Boot port is supported in S-mode only and loaded directly
into DRAM.
A prior stage (M-mode) firmware/bootloader (e.g OpenSBI or BBL) is required to
load the u-boot.bin into memory and provide runtime services. The u-boot.bin
can be given as a payload to the prior stage (M-mode) firmware/bootloader.
A prior stage (M-mode) firmware/bootloader (e.g OpenSBI) is required to
boot the u-boot.bin in S-mode and provide M-mode runtime services.
The description of steps required to build the firmware is beyond the scope of
this document. Please refer OpenSBI or BBL documenation.
Currently, the u-boot.bin is used as a payload of the OpenSBI FW_PAYLOAD
firmware. We need to compile OpenSBI with below command:
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<path to u-boot.bin> FW_PAYLOAD_FDT_PATH=<path to hifive-unleashed-a00.dtb from Linux>
(Note: Prefer hifive-unleashed-a00.dtb from Linux-5.3 or higher)
(Note: Linux-5.2 is also fine but it does not have ethernet DT node)
More detailed description of steps required to build FW_PAYLOAD firmware
is beyond the scope of this document. Please refer OpenSBI documenation.
(Note: OpenSBI git repo is at https://github.com/riscv/opensbi.git)
(Note: BBL git repo is at https://github.com/riscv/riscv-pk.git)
Once the prior stage firmware/bootloader binary is generated, it should be
copied to the first partition of the sdcard.
@ -55,20 +59,18 @@ Once you plugin the sdcard and power up, you should see the U-Boot prompt.
Sample boot log from HiFive Unleashed board
===========================================
U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800)
U-Boot 2019.07-rc4-00013-g1837f893b0 (Jun 20 2019 - 11:08:48 +0530)
CPU: rv64imafdc
Model: sifive,hifive-unleashed-a00
Model: SiFive HiFive Unleashed A00
DRAM: 8 GiB
In: serial@10010000
Out: serial@10010000
Err: serial@10010000
Net:
Warning: ethernet@10090000 (eth0) using random MAC address - b6:75:4d:48:50:94
eth0: ethernet@10090000
Net: eth0: ethernet@10090000
Hit any key to stop autoboot: 0
=> version
U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800)
U-Boot 2019.07-rc4-00013-g1837f893b0 (Jun 20 2019 - 11:08:48 +0530)
riscv64-linux-gcc.br_real (Buildroot 2018.11-rc2-00003-ga0787e9) 8.2.0
GNU ld (GNU Binutils) 2.31.1
@ -79,30 +81,19 @@ Now you can configure your networking, tftp server and use tftp boot method to
load uImage.
==========================================================================
=> setenv ethaddr 70:B3:D5:92:F0:C2
=> setenv ipaddr 10.196.157.189
=> setenv serverip 10.11.143.218
=> setenv gatewayip 10.196.156.1
=> setenv ipaddr 10.206.5.241
=> setenv netmask 255.255.252.0
=> bdinfo
boot_params = 0x0000000000000000
DRAM bank = 0x0000000000000000
-> start = 0x0000000080000000
-> size = 0x0000000200000000
relocaddr = 0x00000000fff90000
reloc off = 0x000000007fd90000
ethaddr = 70:B3:D5:92:F0:C2
IP addr = 10.196.157.189
baudrate = 115200 bps
=> tftpboot uImage
=> setenv serverip 10.206.4.143
=> setenv gateway 10.206.4.1
=> tftpboot ${kernel_addr_r} /sifive/fu540/uImage
ethernet@10090000: PHY present at 0
ethernet@10090000: Starting autonegotiation...
ethernet@10090000: Autonegotiation complete
ethernet@10090000: link up, 1000Mbps full-duplex (lpa: 0x3800)
ethernet@10090000: link up, 1000Mbps full-duplex (lpa: 0x7c00)
Using ethernet@10090000 device
TFTP from server 10.11.143.218; our IP address is 10.196.157.189; sending through gateway 10.196.156.1
Filename 'uImage'.
Load address: 0x80200000
TFTP from server 10.206.4.143; our IP address is 10.206.5.241
Filename '/sifive/fu540/uImage'.
Load address: 0x80600000
Loading: #################################################################
#################################################################
#################################################################
@ -112,192 +103,171 @@ Loading: #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
##########################################################
2.5 MiB/s
########################################
1.5 MiB/s
done
Bytes transferred = 14939132 (e3f3fc hex)
=> bootm 0x80200000 - 0x82200000
## Booting kernel from Legacy Image at 80200000 ...
Bytes transferred = 9162364 (8bce7c hex)
=> tftpboot ${ramdisk_addr_r} /sifive/fu540/uRamdisk
ethernet@10090000: PHY present at 0
ethernet@10090000: Starting autonegotiation...
ethernet@10090000: Autonegotiation complete
ethernet@10090000: link up, 1000Mbps full-duplex (lpa: 0x7c00)
Using ethernet@10090000 device
TFTP from server 10.206.4.143; our IP address is 10.206.5.241
Filename '/sifive/fu540/uRamdisk'.
Load address: 0x82500000
Loading: #################################################################
#################################################################
##################################
448.2 KiB/s
done
Bytes transferred = 2398272 (249840 hex)
=> setenv bootargs "root=/dev/ram rw console=ttySIF0 earlycon=sbi"
=> bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr}
## Booting kernel from Legacy Image at 80600000 ...
Image Name: Linux
Image Type: RISC-V Linux Kernel Image (uncompressed)
Data Size: 14939068 Bytes = 14.2 MiB
Data Size: 9162300 Bytes = 8.7 MiB
Load Address: 80200000
Entry Point: 80200000
Verifying Checksum ... OK
## Flattened Device Tree blob at 82200000
Booting using the fdt blob at 0x82200000
## Loading init Ramdisk from Legacy Image at 82500000 ...
Image Name: Linux RootFS
Image Type: RISC-V Linux RAMDisk Image (uncompressed)
Data Size: 2398208 Bytes = 2.3 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at ff795730
Booting using the fdt blob at 0xff795730
Loading Kernel Image ... OK
Using Device Tree in place at 0000000082200000, end 0000000082205c69
Using Device Tree in place at 00000000ff795730, end 00000000ff799dac
Starting kernel ...
[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[ 0.000000] Linux version 5.0.0-rc1-00020-g4b51f736 (atish@jedi-01) (gcc version 7.2.0 (GCC)) #262 SMP Mon Jan 21 17:39:27 PST 2019
[ 0.000000] initrd not found or empty - disabling initrd
[ 0.000000] Linux version 5.2.0-rc1-00003-gb9543e66e700 (anup@anup-lab-machine) (gcc version 8.2.0 (Buildroot 2018.11-rc2-00003-ga0787e9)) #1 SMP Thu Jun 20 11:41:26 IST 2019
[ 0.000000] earlycon: sbi0 at I/O port 0x0 (options '')
[ 0.000000] printk: bootconsole [sbi0] enabled
[ 0.000000] Initial ramdisk at: 0x(____ptrval____) (2398208 bytes)
[ 0.000000] Zone ranges:
[ 0.000000] DMA32 [mem 0x0000000080200000-0x00000000ffffffff]
[ 0.000000] Normal [mem 0x0000000100000000-0x000027ffffffffff]
[ 0.000000] Normal [mem 0x0000000100000000-0x000000027fffffff]
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000080200000-0x000000027fffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x000000027fffffff]
[ 0.000000] software IO TLB: mapped [mem 0xfbfff000-0xfffff000] (64MB)
[ 0.000000] CPU with hartid=0 has a non-okay status of "masked"
[ 0.000000] CPU with hartid=0 has a non-okay status of "masked"
[ 0.000000] software IO TLB: mapped [mem 0xfb795000-0xff795000] (64MB)
[ 0.000000] CPU with hartid=0 is not available
[ 0.000000] CPU with hartid=0 is not available
[ 0.000000] elf_hwcap is 0x112d
[ 0.000000] percpu: Embedded 15 pages/cpu @(____ptrval____) s29720 r0 d31720 u61440
[ 0.000000] percpu: Embedded 17 pages/cpu s29592 r8192 d31848 u69632
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 2067975
[ 0.000000] Kernel command line: earlyprintk
[ 0.000000] Kernel command line: root=/dev/ram rw console=ttySIF0 earlycon=sbi
[ 0.000000] Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes)
[ 0.000000] Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes)
[ 0.000000] Sorting __ex_table...
[ 0.000000] Memory: 8178760K/8386560K available (3309K kernel code, 248K rwdata, 872K rodata, 9381K init, 763K bss, 207800K reserved, 0K cma-reserved)
[ 0.000000] Memory: 8182056K/8386560K available (5753K kernel code, 357K rwdata, 1804K rodata, 204K init, 808K bss, 204504K reserved, 0K cma-reserved)
[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
[ 0.000000] rcu: Hierarchical RCU implementation.
[ 0.000000] rcu: RCU event tracing is enabled.
[ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
[ 0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
[ 0.000000] plic: mapped 53 interrupts to 4 (out of 9) handlers.
[ 0.000000] riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [1]
[ 0.000000] plic: mapped 53 interrupts with 4 handlers for 9 contexts.
[ 0.000000] riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [2]
[ 0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns
[ 0.000008] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns
[ 0.000221] Console: colour dummy device 80x25
[ 0.000902] printk: console [tty0] enabled
[ 0.000963] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=10000)
[ 0.001034] pid_max: default: 32768 minimum: 301
[ 0.001541] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes)
[ 0.001912] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes)
[ 0.003542] rcu: Hierarchical SRCU implementation.
[ 0.004347] smp: Bringing up secondary CPUs ...
[ 1.040259] CPU1: failed to come online
[ 2.080483] CPU2: failed to come online
[ 3.120699] CPU3: failed to come online
[ 3.120765] smp: Brought up 1 node, 1 CPU
[ 3.121923] devtmpfs: initialized
[ 3.124649] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[ 3.124727] futex hash table entries: 1024 (order: 4, 65536 bytes)
[ 3.125346] random: get_random_u32 called from bucket_table_alloc+0x72/0x172 with crng_init=0
[ 3.125578] NET: Registered protocol family 16
[ 3.126400] sifive-u54-prci 10000000.prci: Registered U54 core clocks
[ 3.126649] sifive-gemgxl-mgmt 100a0000.cadence-gemgxl-mgmt: Registered clock switch 'cadence-gemgxl-mgmt'
[ 3.135572] vgaarb: loaded
[ 3.135858] SCSI subsystem initialized
[ 3.136193] usbcore: registered new interface driver usbfs
[ 3.136266] usbcore: registered new interface driver hub
[ 3.136348] usbcore: registered new device driver usb
[ 3.136446] pps_core: LinuxPPS API ver. 1 registered
[ 3.136484] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 3.136575] PTP clock support registered
[ 3.137256] clocksource: Switched to clocksource riscv_clocksource
[ 3.142711] NET: Registered protocol family 2
[ 3.143322] tcp_listen_portaddr_hash hash table entries: 4096 (order: 4, 65536 bytes)
[ 3.143634] TCP established hash table entries: 65536 (order: 7, 524288 bytes)
[ 3.145799] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes)
[ 3.149121] TCP: Hash tables configured (established 65536 bind 65536)
[ 3.149591] UDP hash table entries: 4096 (order: 5, 131072 bytes)
[ 3.150094] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes)
[ 3.150781] NET: Registered protocol family 1
[ 3.230693] workingset: timestamp_bits=62 max_order=21 bucket_order=0
[ 3.241224] io scheduler mq-deadline registered
[ 3.241269] io scheduler kyber registered
[ 3.242143] sifive_gpio 10060000.gpio: SiFive GPIO chip registered 16 GPIOs
[ 3.242357] pwm-sifivem 10020000.pwm: Unable to find controller clock
[ 3.242439] pwm-sifivem 10021000.pwm: Unable to find controller clock
[ 3.243228] xilinx-pcie 2000000000.pci: PCIe Link is DOWN
[ 3.243289] xilinx-pcie 2000000000.pci: host bridge /soc/pci@2000000000 ranges:
[ 3.243360] xilinx-pcie 2000000000.pci: No bus range found for /soc/pci@2000000000, using [bus 00-ff]
[ 3.243447] xilinx-pcie 2000000000.pci: MEM 0x40000000..0x5fffffff -> 0x40000000
[ 3.243591] xilinx-pcie 2000000000.pci: PCI host bridge to bus 0000:00
[ 3.243636] pci_bus 0000:00: root bus resource [bus 00-ff]
[ 3.243676] pci_bus 0000:00: root bus resource [mem 0x40000000-0x5fffffff]
[ 3.276547] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ 3.277689] 10010000.serial: ttySIF0 at MMIO 0x10010000 (irq = 39, base_baud = 0) is a SiFive UART v0
[ 3.786963] printk: console [ttySIF0] enabled
[ 3.791504] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 40, base_baud = 0) is a SiFive UART v0
[ 3.801251] sifive_spi 10040000.spi: mapped; irq=41, cs=1
[ 3.806362] m25p80 spi0.0: unrecognized JEDEC id bytes: 9d, 70, 19
[ 3.812084] m25p80: probe of spi0.0 failed with error -2
[ 3.817453] sifive_spi 10041000.spi: mapped; irq=42, cs=4
[ 3.823027] sifive_spi 10050000.spi: mapped; irq=43, cs=1
[ 3.828604] libphy: Fixed MDIO Bus: probed
[ 3.832623] macb: GEM doesn't support hardware ptp.
[ 3.837196] libphy: MACB_mii_bus: probed
[ 4.041156] Microsemi VSC8541 SyncE 10090000.ethernet-ffffffff:00: attached PHY driver [Microsemi VSC8541 SyncE] (mii_bus:phy_addr=10090000.ethernet-ffffffff:00, irq=POLL)
[ 4.055779] macb 10090000.ethernet eth0: Cadence GEM rev 0x10070109 at 0x10090000 irq 12 (70:b3:d5:92:f0:c2)
[ 4.065780] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 4.072033] ehci-pci: EHCI PCI platform driver
[ 4.076521] usbcore: registered new interface driver usb-storage
[ 4.082843] softdog: initialized. soft_noboot=0 soft_margin=60 sec soft_panic=0 (nowayout=0)
[ 4.127465] mmc_spi spi2.0: SD/MMC host mmc0, no DMA, no WP, no poweroff
[ 4.133645] usbcore: registered new interface driver usbhid
[ 4.138980] usbhid: USB HID core driver
[ 4.143017] NET: Registered protocol family 17
[ 4.147885] pwm-sifivem 10020000.pwm: SiFive PWM chip registered 4 PWMs
[ 4.153945] pwm-sifivem 10021000.pwm: SiFive PWM chip registered 4 PWMs
[ 4.186407] Freeing unused kernel memory: 9380K
[ 4.190224] This architecture does not have kernel memory protection.
[ 4.196609] Run /init as init process
Starting logging: OK
Starting mdev...
[ 4.303785] mmc0: host does not support reading read-only switch, assuming write-enable
[ 4.311109] mmc0: new SDHC card on SPI
[ 4.317103] mmcblk0: mmc0:0000 SS08G 7.40 GiB
[ 4.386471] mmcblk0: p1 p2
sort: /sys/devices/platform/Fixed: No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
Initializing random[ 4.759075] random: dd: uninitialized urandom read (512 bytes read)
number generator... done.
Starting network...
udhcpc (v1.24.2) started
Sending discover...
Sending discover...
[ 7.927510] macb 10090000.ethernet eth0: link up (1000/Full)
Sending discover...
Sending select for 10.196.157.190...
Lease of 10.196.157.190 obtained, lease time 499743
deleting routers
adding dns 10.86.1.1
adding dns 10.86.2.1
/etc/init.d/S50dropbear
Starting dropbear sshd: [ 12.772393] random: dropbear: uninitialized urandom read (32 bytes read)
OK
[ 0.000007] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns
[ 0.008553] Console: colour dummy device 80x25
[ 0.012990] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=4000)
[ 0.023103] pid_max: default: 32768 minimum: 301
[ 0.028269] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes)
[ 0.035068] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes)
[ 0.042770] *** VALIDATE proc ***
[ 0.045610] *** VALIDATE cgroup1 ***
[ 0.049157] *** VALIDATE cgroup2 ***
[ 0.053743] rcu: Hierarchical SRCU implementation.
[ 0.058297] smp: Bringing up secondary CPUs ...
[ 0.064134] smp: Brought up 1 node, 4 CPUs
[ 0.069114] devtmpfs: initialized
[ 0.073281] random: get_random_u32 called from bucket_table_alloc.isra.10+0x4e/0x160 with crng_init=0
[ 0.082157] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[ 0.091634] futex hash table entries: 1024 (order: 4, 65536 bytes)
[ 0.098480] NET: Registered protocol family 16
[ 0.114101] vgaarb: loaded
[ 0.116397] SCSI subsystem initialized
[ 0.120358] usbcore: registered new interface driver usbfs
[ 0.125541] usbcore: registered new interface driver hub
[ 0.130936] usbcore: registered new device driver usb
[ 0.136618] clocksource: Switched to clocksource riscv_clocksource
[ 0.148108] NET: Registered protocol family 2
[ 0.152358] tcp_listen_portaddr_hash hash table entries: 4096 (order: 4, 65536 bytes)
[ 0.159928] TCP established hash table entries: 65536 (order: 7, 524288 bytes)
[ 0.169027] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes)
[ 0.178360] TCP: Hash tables configured (established 65536 bind 65536)
[ 0.184653] UDP hash table entries: 4096 (order: 5, 131072 bytes)
[ 0.190819] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes)
[ 0.197618] NET: Registered protocol family 1
[ 0.201892] RPC: Registered named UNIX socket transport module.
[ 0.207395] RPC: Registered udp transport module.
[ 0.212159] RPC: Registered tcp transport module.
[ 0.216940] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 0.223445] PCI: CLS 0 bytes, default 64
[ 0.227726] Unpacking initramfs...
[ 0.260556] Freeing initrd memory: 2336K
[ 0.264652] workingset: timestamp_bits=62 max_order=21 bucket_order=0
[ 0.278452] NFS: Registering the id_resolver key type
[ 0.282841] Key type id_resolver registered
[ 0.287067] Key type id_legacy registered
[ 0.291155] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[ 0.298299] NET: Registered protocol family 38
[ 0.302470] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
[ 0.309906] io scheduler mq-deadline registered
[ 0.314501] io scheduler kyber registered
[ 0.354134] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ 0.360725] 10010000.serial: ttySIF0 at MMIO 0x10010000 (irq = 4, base_baud = 0) is a SiFive UART v0
[ 0.369191] printk: console [ttySIF0] enabled
[ 0.369191] printk: console [ttySIF0] enabled
[ 0.377938] printk: bootconsole [sbi0] disabled
[ 0.377938] printk: bootconsole [sbi0] disabled
[ 0.387298] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 1, base_baud = 0) is a SiFive UART v0
[ 0.396411] [drm] radeon kernel modesetting enabled.
[ 0.409818] loop: module loaded
[ 0.412606] libphy: Fixed MDIO Bus: probed
[ 0.416870] macb 10090000.ethernet: Registered clk switch 'sifive-gemgxl-mgmt'
[ 0.423570] macb: GEM doesn't support hardware ptp.
[ 0.428469] libphy: MACB_mii_bus: probed
[ 1.053009] Microsemi VSC8541 SyncE 10090000.ethernet-ffffffff:00: attached PHY driver [Microsemi VSC8541 SyncE] (mii_bus:phy_addr=10090000.ethernet-ffffffff:00, irq=POLL)
[ 1.067548] macb 10090000.ethernet eth0: Cadence GEM rev 0x10070109 at 0x10090000 irq 7 (70:b3:d5:92:f2:f3)
[ 1.077330] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
[ 1.083069] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
[ 1.089061] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 1.095485] ehci-pci: EHCI PCI platform driver
[ 1.099947] ehci-platform: EHCI generic platform driver
[ 1.105196] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[ 1.111286] ohci-pci: OHCI PCI platform driver
[ 1.115742] ohci-platform: OHCI generic platform driver
[ 1.121142] usbcore: registered new interface driver uas
[ 1.126269] usbcore: registered new interface driver usb-storage
[ 1.132331] mousedev: PS/2 mouse device common for all mice
[ 1.137978] usbcore: registered new interface driver usbhid
[ 1.143325] usbhid: USB HID core driver
[ 1.148022] NET: Registered protocol family 10
[ 1.152609] Segment Routing with IPv6
[ 1.155571] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[ 1.161927] NET: Registered protocol family 17
[ 1.165907] Key type dns_resolver registered
[ 1.171694] Freeing unused kernel memory: 204K
[ 1.175375] This architecture does not have kernel memory protection.
[ 1.181792] Run /init as init process
_ _
| ||_|
| | _ ____ _ _ _ _
| || | _ \| | | |\ \/ /
| || | | | | |_| |/ \
|_||_|_| |_|\____|\_/\_/
Welcome to Buildroot
buildroot login:
Busybox Rootfs
Please press Enter to activate this console.
/ #

View File

@ -98,6 +98,7 @@ config CLK_STM32MP1
Enable the STM32 clock (RCC) driver. Enable support for
manipulating STM32MP1's on-SoC clocks.
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/at91/Kconfig"
source "drivers/clk/exynos/Kconfig"
source "drivers/clk/imx/Kconfig"

View File

@ -8,6 +8,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o
obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o
obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o
obj-y += analogbits/
obj-y += imx/
obj-y += tegra/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/

View File

@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
config CLK_ANALOGBITS_WRPLL_CLN28HPC
bool

View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o

View File

@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Copyright (C) 2018 SiFive, Inc.
* Copyright (C) 2018-2019 SiFive, Inc.
* Wesley Terpstra
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This library supports configuration parsing and reprogramming of
* the CLN28HPC variant of the Analog Bits Wide Range PLL. The
* intention is for this library to be reusable for any device that
@ -29,14 +18,14 @@
* References:
* - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01
* - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset"
* https://static.dev.sifive.com/FU540-C000-v1.0.pdf
*/
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/log2.h>
#include <linux/math64.h>
#include "analogbits-wrpll-cln28hpc.h"
#include <linux/clk/analogbits-wrpll-cln28hpc.h>
/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
#define MIN_INPUT_FREQ 7000000
@ -85,40 +74,38 @@
* range selection.
*
* Return: The RANGE value to be presented to the PLL configuration inputs,
* or -1 upon error.
* or a negative return code upon error.
*/
static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
{
u8 range;
if (post_divr_freq < MIN_POST_DIVR_FREQ ||
post_divr_freq > MAX_POST_DIVR_FREQ) {
WARN(1, "%s: post-divider reference freq out of range: %lu",
__func__, post_divr_freq);
return -1;
return -ERANGE;
}
if (post_divr_freq < 11000000)
range = 1;
else if (post_divr_freq < 18000000)
range = 2;
else if (post_divr_freq < 30000000)
range = 3;
else if (post_divr_freq < 50000000)
range = 4;
else if (post_divr_freq < 80000000)
range = 5;
else if (post_divr_freq < 130000000)
range = 6;
else
range = 7;
switch (post_divr_freq) {
case 0 ... 10999999:
return 1;
case 11000000 ... 17999999:
return 2;
case 18000000 ... 29999999:
return 3;
case 30000000 ... 49999999:
return 4;
case 50000000 ... 79999999:
return 5;
case 80000000 ... 129999999:
return 6;
}
return range;
return 7;
}
/**
* __wrpll_calc_fbdiv() - return feedback fixed divide value
* @c: ptr to a struct analogbits_wrpll_cfg record to read from
* @c: ptr to a struct wrpll_cfg record to read from
*
* The internal feedback path includes a fixed by-two divider; the
* external feedback path does not. Return the appropriate divider
@ -133,7 +120,7 @@ static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
* Return: 2 if internal feedback is enabled or 1 if external feedback
* is enabled.
*/
static u8 __wrpll_calc_fbdiv(struct analogbits_wrpll_cfg *c)
static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c)
{
return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1;
}
@ -173,7 +160,7 @@ static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate)
*vco_rate = MIN_VCO_FREQ;
} else {
divq = ilog2(s);
*vco_rate = target_rate << divq;
*vco_rate = (u64)target_rate << divq;
}
wcd_out:
@ -182,7 +169,7 @@ wcd_out:
/**
* __wrpll_update_parent_rate() - update PLL data when parent rate changes
* @c: ptr to a struct analogbits_wrpll_cfg record to write PLL data to
* @c: ptr to a struct wrpll_cfg record to write PLL data to
* @parent_rate: PLL input refclk rate (pre-R-divider)
*
* Pre-compute some data used by the PLL configuration algorithm when
@ -190,46 +177,40 @@ wcd_out:
* computation when the parent rate remains constant - expected to be
* the common case.
*
* Returns: 0 upon success or -1 if the reference clock rate is out of range.
* Returns: 0 upon success or -ERANGE if the reference clock rate is
* out of range.
*/
static int __wrpll_update_parent_rate(struct analogbits_wrpll_cfg *c,
static int __wrpll_update_parent_rate(struct wrpll_cfg *c,
unsigned long parent_rate)
{
u8 max_r_for_parent;
if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ)
return -1;
return -ERANGE;
c->_parent_rate = parent_rate;
c->parent_rate = parent_rate;
max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ);
c->_max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
/* Round up */
c->_init_r = div_u64(parent_rate + MAX_POST_DIVR_FREQ - 1,
MAX_POST_DIVR_FREQ);
c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ);
return 0;
}
/*
* Public functions
*/
/**
* analogbits_wrpll_configure() - compute PLL configuration for a target rate
* @c: ptr to a struct analogbits_wrpll_cfg record to write into
* wrpll_configure() - compute PLL configuration for a target rate
* @c: ptr to a struct wrpll_cfg record to write into
* @target_rate: target PLL output clock rate (post-Q-divider)
* @parent_rate: PLL input refclk rate (pre-R-divider)
*
* Given a pointer to a PLL context @c, a desired PLL target output
* rate @target_rate, and a reference clock input rate @parent_rate,
* compute the appropriate PLL signal configuration values. PLL
* reprogramming is not glitchless, so the caller should switch any
* downstream logic to a different clock source or clock-gate it
* before presenting these values to the PLL configuration signals.
* Compute the appropriate PLL signal configuration values and store
* in PLL context @c. PLL reprogramming is not glitchless, so the
* caller should switch any downstream logic to a different clock
* source or clock-gate it before presenting these values to the PLL
* configuration signals.
*
* The caller must pass this function a pre-initialized struct
* analogbits_wrpll_cfg record: either initialized to zero (with the
* wrpll_cfg record: either initialized to zero (with the
* exception of the .name and .flags fields) or read from the PLL.
*
* Context: Any context. Caller must protect the memory pointed to by @c
@ -237,41 +218,26 @@ static int __wrpll_update_parent_rate(struct analogbits_wrpll_cfg *c,
*
* Return: 0 upon success; anything else upon failure.
*/
int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
u32 target_rate,
unsigned long parent_rate)
int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
unsigned long parent_rate)
{
unsigned long ratio;
u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre;
u32 best_f, f, post_divr_freq, fbcfg;
u32 best_f, f, post_divr_freq;
u8 fbdiv, divq, best_r, r;
if (!c)
return -1;
int range;
if (c->flags == 0) {
WARN(1, "%s called with uninitialized PLL config", __func__);
return -1;
}
fbcfg = WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK;
if ((c->flags & fbcfg) == fbcfg) {
WARN(1, "%s called with invalid PLL config", __func__);
return -1;
}
if (c->flags == WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
WARN(1, "%s: external feedback mode not currently supported",
__func__);
return -1;
return -EINVAL;
}
/* Initialize rounding data if it hasn't been initialized already */
if (parent_rate != c->_parent_rate) {
if (parent_rate != c->parent_rate) {
if (__wrpll_update_parent_rate(c, parent_rate)) {
pr_err("%s: PLL input rate is out of range\n",
__func__);
return -1;
return -ERANGE;
}
}
@ -282,11 +248,12 @@ int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
c->flags |= WRPLL_FLAGS_BYPASS_MASK;
return 0;
}
c->flags &= ~WRPLL_FLAGS_BYPASS_MASK;
/* Calculate the Q shift and target VCO rate */
divq = __wrpll_calc_divq(target_rate, &target_vco_rate);
if (divq == 0)
if (!divq)
return -1;
c->divq = divq;
@ -302,8 +269,7 @@ int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
* Consider all values for R which land within
* [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R
*/
for (r = c->_init_r; r <= c->_max_r; ++r) {
/* What is the best F we can pick in this case? */
for (r = c->init_r; r <= c->max_r; ++r) {
f_pre_div = ratio * r;
f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT;
f >>= (fbdiv - 1);
@ -335,46 +301,54 @@ int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
post_divr_freq = div_u64(parent_rate, best_r);
/* Pick the best PLL jitter filter */
c->range = __wrpll_calc_filter_range(post_divr_freq);
range = __wrpll_calc_filter_range(post_divr_freq);
if (range < 0)
return range;
c->range = range;
return 0;
}
/**
* analogbits_wrpll_calc_output_rate() - calculate the PLL's target output rate
* @c: ptr to a struct analogbits_wrpll_cfg record to read from
* wrpll_calc_output_rate() - calculate the PLL's target output rate
* @c: ptr to a struct wrpll_cfg record to read from
* @parent_rate: PLL refclk rate
*
* Given a pointer to the PLL's current input configuration @c and the
* PLL's input reference clock rate @parent_rate (before the R
* pre-divider), calculate the PLL's output clock rate (after the Q
* post-divider)
* post-divider).
*
* Context: Any context. Caller must protect the memory pointed to by @c
* from simultaneous modification.
*
* Return: the PLL's output clock rate, in Hz.
* Return: the PLL's output clock rate, in Hz. The return value from
* this function is intended to be convenient to pass directly
* to the Linux clock framework; thus there is no explicit
* error return value.
*/
unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
unsigned long parent_rate)
unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
unsigned long parent_rate)
{
u8 fbdiv;
u64 n;
WARN(c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK,
"external feedback mode not yet supported");
if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
WARN(1, "external feedback mode not yet supported");
return ULONG_MAX;
}
fbdiv = __wrpll_calc_fbdiv(c);
n = parent_rate * fbdiv * (c->divf + 1);
n = div_u64(n, (c->divr + 1));
n = div_u64(n, c->divr + 1);
n >>= c->divq;
return n;
}
/**
* analogbits_wrpll_calc_max_lock_us() - return the time for the PLL to lock
* @c: ptr to a struct analogbits_wrpll_cfg record to read from
* wrpll_calc_max_lock_us() - return the time for the PLL to lock
* @c: ptr to a struct wrpll_cfg record to read from
*
* Return the minimum amount of time (in microseconds) that the caller
* must wait after reprogramming the PLL to ensure that it is locked
@ -384,7 +358,7 @@ unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
* Return: the minimum amount of time the caller must wait for the PLL
* to lock (in microseconds)
*/
unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c)
unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
{
return MAX_LOCK_US;
}

View File

@ -1,8 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
config CLK_ANALOGBITS_WRPLL_CLN28HPC
bool
config CLK_SIFIVE
bool "SiFive SoC driver support"
depends on CLK
@ -17,10 +14,3 @@ config CLK_SIFIVE_FU540_PRCI
Supports the Power Reset Clock interface (PRCI) IP block found in
FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
enable this driver.
config CLK_SIFIVE_GEMGXL_MGMT
bool "GEMGXL management for SiFive FU540 SoCs"
depends on CLK_SIFIVE
help
Supports the GEMGXL management IP block found in FU540 SoCs to
control GEM TX clock operation mode for 10/100/1000 Mbps.

View File

@ -1,7 +1,3 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o
obj-$(CONFIG_CLK_SIFIVE_GEMGXL_MGMT) += gemgxl-mgmt.o

View File

@ -37,9 +37,8 @@
#include <errno.h>
#include <linux/math64.h>
#include <dt-bindings/clk/sifive-fu540-prci.h>
#include "analogbits-wrpll-cln28hpc.h"
#include <linux/clk/analogbits-wrpll-cln28hpc.h>
#include <dt-bindings/clock/sifive-fu540-prci.h>
/*
* EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
@ -159,30 +158,32 @@
* PRCI per-device instance data
*/
struct __prci_data {
void *base;
struct clk parent;
void *va;
struct clk parent_hfclk;
struct clk parent_rtcclk;
};
/**
* struct __prci_wrpll_data - WRPLL configuration and integration data
* @c: WRPLL current configuration record
* @bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
* @no_bypass: fn ptr to code to not bypass the WRPLL (if applicable; else NULL)
* @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
* @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
* @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
*
* @bypass and @no_bypass are used for WRPLL instances that contain a separate
* external glitchless clock mux downstream from the PLL. The WRPLL internal
* bypass mux is not glitchless.
* @enable_bypass and @disable_bypass are used for WRPLL instances
* that contain a separate external glitchless clock mux downstream
* from the PLL. The WRPLL internal bypass mux is not glitchless.
*/
struct __prci_wrpll_data {
struct analogbits_wrpll_cfg c;
void (*bypass)(struct __prci_data *pd);
void (*no_bypass)(struct __prci_data *pd);
struct wrpll_cfg c;
void (*enable_bypass)(struct __prci_data *pd);
void (*disable_bypass)(struct __prci_data *pd);
u8 cfg0_offs;
};
struct __prci_clock;
/* struct __prci_clock_ops - clock operations */
struct __prci_clock_ops {
int (*set_rate)(struct __prci_clock *pc,
unsigned long rate,
@ -198,8 +199,7 @@ struct __prci_clock_ops {
* struct __prci_clock - describes a clock device managed by PRCI
* @name: user-readable clock name string - should match the manual
* @parent_name: parent name for this clock
* @ops: struct clk_ops for the Linux clock framework to use for control
* @hw: Linux-private clock data
* @ops: struct __prci_clock_ops for control
* @pwd: WRPLL-specific data, associated with this clock (if not NULL)
* @pd: PRCI-specific data associated with this clock (if not NULL)
*
@ -233,19 +233,19 @@ struct __prci_clock {
*/
static u32 __prci_readl(struct __prci_data *pd, u32 offs)
{
return readl(pd->base + offs);
return readl(pd->va + offs);
}
static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
{
return writel(v, pd->base + offs);
writel(v, pd->va + offs);
}
/* WRPLL-related private functions */
/**
* __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
* @c: ptr to a struct analogbits_wrpll_cfg record to write config into
* @c: ptr to a struct wrpll_cfg record to write config into
* @r: value read from the PRCI PLL configuration register
*
* Given a value @r read from an FU540 PRCI PLL configuration register,
@ -257,7 +257,7 @@ static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
*
* Context: Any context.
*/
static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r)
static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
{
u32 v;
@ -280,15 +280,13 @@ static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r)
c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
WRPLL_FLAGS_EXT_FEEDBACK_MASK);
if (r & PRCI_COREPLLCFG0_FSE_MASK)
c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
else
c->flags |= WRPLL_FLAGS_EXT_FEEDBACK_MASK;
/* external feedback mode not supported */
c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
}
/**
* __prci_wrpll_pack() - pack PLL configuration parameters into a register value
* @c: pointer to a struct analogbits_wrpll_cfg record containing the PLL's cfg
* @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
*
* Using a set of WRPLL configuration values pointed to by @c,
* assemble a PRCI PLL configuration register value, and return it to
@ -301,7 +299,7 @@ static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r)
* Returns: a value suitable for writing into a PRCI PLL configuration
* register
*/
static u32 __prci_wrpll_pack(struct analogbits_wrpll_cfg *c)
static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
{
u32 r = 0;
@ -309,8 +307,9 @@ static u32 __prci_wrpll_pack(struct analogbits_wrpll_cfg *c)
r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
if (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK)
r |= PRCI_COREPLLCFG0_FSE_MASK;
/* external feedback mode not supported */
r |= PRCI_COREPLLCFG0_FSE_MASK;
return r;
}
@ -349,11 +348,11 @@ static void __prci_wrpll_read_cfg(struct __prci_data *pd,
*/
static void __prci_wrpll_write_cfg(struct __prci_data *pd,
struct __prci_wrpll_data *pwd,
struct analogbits_wrpll_cfg *c)
struct wrpll_cfg *c)
{
__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
memcpy(&pwd->c, c, sizeof(struct analogbits_wrpll_cfg));
memcpy(&pwd->c, c, sizeof(*c));
}
/* Core clock mux control */
@ -404,7 +403,7 @@ static unsigned long sifive_fu540_prci_wrpll_recalc_rate(
{
struct __prci_wrpll_data *pwd = pc->pwd;
return analogbits_wrpll_calc_output_rate(&pwd->c, parent_rate);
return wrpll_calc_output_rate(&pwd->c, parent_rate);
}
static unsigned long sifive_fu540_prci_wrpll_round_rate(
@ -413,13 +412,13 @@ static unsigned long sifive_fu540_prci_wrpll_round_rate(
unsigned long *parent_rate)
{
struct __prci_wrpll_data *pwd = pc->pwd;
struct analogbits_wrpll_cfg c;
struct wrpll_cfg c;
memcpy(&c, &pwd->c, sizeof(c));
analogbits_wrpll_configure_for_rate(&c, rate, *parent_rate);
wrpll_configure_for_rate(&c, rate, *parent_rate);
return analogbits_wrpll_calc_output_rate(&c, *parent_rate);
return wrpll_calc_output_rate(&c, *parent_rate);
}
static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
@ -430,19 +429,19 @@ static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
struct __prci_data *pd = pc->pd;
int r;
r = analogbits_wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
if (r)
return -ERANGE;
return r;
if (pwd->bypass)
pwd->bypass(pd);
if (pwd->enable_bypass)
pwd->enable_bypass(pd);
__prci_wrpll_write_cfg(pd, pwd, &pwd->c);
udelay(analogbits_wrpll_calc_max_lock_us(&pwd->c));
udelay(wrpll_calc_max_lock_us(&pwd->c));
if (pwd->no_bypass)
pwd->no_bypass(pd);
if (pwd->disable_bypass)
pwd->disable_bypass(pd);
return 0;
}
@ -484,8 +483,8 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = {
static struct __prci_wrpll_data __prci_corepll_data = {
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
.bypass = __prci_coreclksel_use_hfclk,
.no_bypass = __prci_coreclksel_use_corepll,
.enable_bypass = __prci_coreclksel_use_hfclk,
.disable_bypass = __prci_coreclksel_use_corepll,
};
static struct __prci_wrpll_data __prci_ddrpll_data = {
@ -526,6 +525,27 @@ static struct __prci_clock __prci_init_clocks[] = {
},
};
static ulong sifive_fu540_prci_parent_rate(struct __prci_clock *pc)
{
ulong parent_rate;
struct __prci_clock *p;
if (strcmp(pc->parent_name, "corepll") == 0) {
p = &__prci_init_clocks[PRCI_CLK_COREPLL];
if (!p->pd || !p->ops->recalc_rate)
return -ENXIO;
return p->ops->recalc_rate(p, sifive_fu540_prci_parent_rate(p));
}
if (strcmp(pc->parent_name, "rtcclk") == 0)
parent_rate = clk_get_rate(&pc->pd->parent_rtcclk);
else
parent_rate = clk_get_rate(&pc->pd->parent_hfclk);
return parent_rate;
}
static ulong sifive_fu540_prci_get_rate(struct clk *clk)
{
struct __prci_clock *pc;
@ -537,7 +557,7 @@ static ulong sifive_fu540_prci_get_rate(struct clk *clk)
if (!pc->pd || !pc->ops->recalc_rate)
return -ENXIO;
return pc->ops->recalc_rate(pc, clk_get_rate(&pc->pd->parent));
return pc->ops->recalc_rate(pc, sifive_fu540_prci_parent_rate(pc));
}
static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
@ -552,7 +572,7 @@ static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
if (!pc->pd || !pc->ops->set_rate)
return -ENXIO;
err = pc->ops->set_rate(pc, rate, clk_get_rate(&pc->pd->parent));
err = pc->ops->set_rate(pc, rate, sifive_fu540_prci_parent_rate(pc));
if (err)
return err;
@ -565,11 +585,15 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
struct __prci_clock *pc;
struct __prci_data *pd = dev_get_priv(dev);
pd->base = (void *)dev_read_addr(dev);
if (IS_ERR(pd->base))
return PTR_ERR(pd->base);
pd->va = (void *)dev_read_addr(dev);
if (IS_ERR(pd->va))
return PTR_ERR(pd->va);
err = clk_get_by_index(dev, 0, &pd->parent);
err = clk_get_by_index(dev, 0, &pd->parent_hfclk);
if (err)
return err;
err = clk_get_by_index(dev, 1, &pd->parent_rtcclk);
if (err)
return err;
@ -589,8 +613,7 @@ static struct clk_ops sifive_fu540_prci_ops = {
};
static const struct udevice_id sifive_fu540_prci_ids[] = {
{ .compatible = "sifive,fu540-c000-prci0" },
{ .compatible = "sifive,aloeprci0" },
{ .compatible = "sifive,fu540-c000-prci" },
{ }
};

View File

@ -1,60 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
#include <asm/io.h>
struct gemgxl_mgmt_regs {
__u32 tx_clk_sel;
};
struct gemgxl_mgmt_platdata {
struct gemgxl_mgmt_regs *regs;
};
static int gemgxl_mgmt_ofdata_to_platdata(struct udevice *dev)
{
struct gemgxl_mgmt_platdata *plat = dev_get_platdata(dev);
plat->regs = (struct gemgxl_mgmt_regs *)dev_read_addr(dev);
return 0;
}
static ulong gemgxl_mgmt_set_rate(struct clk *clk, ulong rate)
{
struct gemgxl_mgmt_platdata *plat = dev_get_platdata(clk->dev);
/*
* GEMGXL TX clock operation mode:
*
* 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic
* and output clock on GMII output signal GTX_CLK
* 1 = MII mode. Use MII input signal TX_CLK in TX logic
*/
writel(rate != 125000000, &plat->regs->tx_clk_sel);
return 0;
}
const struct clk_ops gemgxl_mgmt_ops = {
.set_rate = gemgxl_mgmt_set_rate,
};
static const struct udevice_id gemgxl_mgmt_match[] = {
{ .compatible = "sifive,cadencegemgxlmgmt0", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(sifive_gemgxl_mgmt) = {
.name = "sifive-gemgxl-mgmt",
.id = UCLASS_CLK,
.of_match = gemgxl_mgmt_match,
.ofdata_to_platdata = gemgxl_mgmt_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct gemgxl_mgmt_platdata),
.ops = &gemgxl_mgmt_ops,
};

View File

@ -1,29 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Copyright (C) 2018 SiFive, Inc.
* Wesley Terpstra
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LINUX_CLK_SIFIVE_FU540_PRCI_H
#define __LINUX_CLK_SIFIVE_FU540_PRCI_H
/* Clock indexes for use by Device Tree data */
#define PRCI_CLK_COREPLL 0
#define PRCI_CLK_DDRPLL 1
#define PRCI_CLK_GEMGXLPLL 2
#define PRCI_CLK_TLCLK 3
#endif

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018-2019 SiFive, Inc.
* Wesley Terpstra
* Paul Walmsley
*/
#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H
#define __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H
/* Clock indexes for use by Device Tree data and the PRCI driver */
#define PRCI_CLK_COREPLL 0
#define PRCI_CLK_DDRPLL 1
#define PRCI_CLK_GEMGXLPLL 2
#define PRCI_CLK_TLCLK 3
#endif

View File

@ -1,19 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Copyright (C) 2018 SiFive, Inc.
* Copyright (C) 2018-2019 SiFive, Inc.
* Wesley Terpstra
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
@ -25,7 +14,7 @@
#define DIVQ_VALUES 6
/*
* Bit definitions for struct analogbits_wrpll_cfg.flags
* Bit definitions for struct wrpll_cfg.flags
*
* WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be
* programmed to enter bypass
@ -34,10 +23,6 @@
* feedback mode
* WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external
* feedback mode (not yet supported by this driver)
*
* The flags WRPLL_FLAGS_INT_FEEDBACK_FLAG and WRPLL_FLAGS_EXT_FEEDBACK_FLAG are
* mutually exclusive. If both bits are set, or both are zero, the struct
* analogbits_wrpll_cfg record is uninitialized or corrupt.
*/
#define WRPLL_FLAGS_BYPASS_SHIFT 0
#define WRPLL_FLAGS_BYPASS_MASK BIT(WRPLL_FLAGS_BYPASS_SHIFT)
@ -49,53 +34,46 @@
#define WRPLL_FLAGS_EXT_FEEDBACK_MASK BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT)
/**
* struct analogbits_wrpll_cfg - WRPLL configuration values
* @divr: reference divider value (6 bits), as presented to the PLL signals.
* @divf: feedback divider value (9 bits), as presented to the PLL signals.
* @divq: output divider value (3 bits), as presented to the PLL signals.
* @flags: PLL configuration flags. See above for more information.
* @range: PLL loop filter range. See below for more information.
* @_output_rate_cache: cached output rates, swept across DIVQ.
* @_parent_rate: PLL refclk rate for which values are valid
* @_max_r: maximum possible R divider value, given @parent_rate
* @_init_r: initial R divider value to start the search from
* struct wrpll_cfg - WRPLL configuration values
* @divr: reference divider value (6 bits), as presented to the PLL signals
* @divf: feedback divider value (9 bits), as presented to the PLL signals
* @divq: output divider value (3 bits), as presented to the PLL signals
* @flags: PLL configuration flags. See above for more information
* @range: PLL loop filter range. See below for more information
* @output_rate_cache: cached output rates, swept across DIVQ
* @parent_rate: PLL refclk rate for which values are valid
* @max_r: maximum possible R divider value, given @parent_rate
* @init_r: initial R divider value to start the search from
*
* @divr, @divq, @divq, @range represent what the PLL expects to see
* on its input signals. Thus @divr and @divf are the actual divisors
* minus one. @divq is a power-of-two divider; for example, 1 =
* divide-by-2 and 6 = divide-by-64. 0 is an invalid @divq value.
*
* When initially passing a struct analogbits_wrpll_cfg record, the
* When initially passing a struct wrpll_cfg record, the
* record should be zero-initialized with the exception of the @flags
* field. The only flag bits that need to be set are either
* WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK.
*
* Field names beginning with an underscore should be considered
* private to the wrpll-cln28hpc.c code.
*/
struct analogbits_wrpll_cfg {
struct wrpll_cfg {
u8 divr;
u8 divq;
u8 range;
u8 flags;
u16 divf;
u32 _output_rate_cache[DIVQ_VALUES];
unsigned long _parent_rate;
u8 _max_r;
u8 _init_r;
/* private: */
u32 output_rate_cache[DIVQ_VALUES];
unsigned long parent_rate;
u8 max_r;
u8 init_r;
};
/*
* Function prototypes
*/
int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
unsigned long parent_rate);
int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
u32 target_rate,
unsigned long parent_rate);
unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c);
unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c);
unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
unsigned long parent_rate);
unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
unsigned long parent_rate);
#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */