- MPC83xx device tree additions (CPU and RAM) - Fix sandbox build error - Sync bitrev with Linux - Various ofnode/DT improvementslime2-spi
commit
4e710ebb44
@ -0,0 +1,23 @@ |
||||
MPC83xx system clock devices |
||||
|
||||
MPC83xx SoCs supply a variety of clocks to drive various components of a |
||||
system. |
||||
|
||||
Required properties: |
||||
- compatible: must be one of "fsl,mpc8308-clk", |
||||
"fsl,mpc8309-clk", |
||||
"fsl,mpc8313-clk", |
||||
"fsl,mpc8315-clk", |
||||
"fsl,mpc832x-clk", |
||||
"fsl,mpc8349-clk", |
||||
"fsl,mpc8360-clk", |
||||
"fsl,mpc8379-clk" |
||||
depending on which SoC is employed |
||||
- #clock-cells: Must be 1 |
||||
|
||||
Example: |
||||
|
||||
socclocks: clocks { |
||||
compatible = "fsl,mpc832x-clk"; |
||||
#clock-cells = <1>; |
||||
}; |
@ -0,0 +1,34 @@ |
||||
MPC83xx CPU devices |
||||
|
||||
MPC83xx SoCs contain a e300 core as their main processor. |
||||
|
||||
Required properties: |
||||
- compatible: must be one of "fsl,mpc83xx", |
||||
"fsl,mpc8308", |
||||
"fsl,mpc8309", |
||||
"fsl,mpc8313", |
||||
"fsl,mpc8315", |
||||
"fsl,mpc832x", |
||||
"fsl,mpc8349", |
||||
"fsl,mpc8360", |
||||
"fsl,mpc8379" |
||||
- clocks: has to have two entries, which must be the core clock at index 0 and |
||||
the CSB (Coherent System Bus) clock at index 1. Both are given by a suitable |
||||
"fsl,mpc83xx-clk" device |
||||
|
||||
Example: |
||||
|
||||
socclocks: clocks { |
||||
compatible = "fsl,mpc8315-clk"; |
||||
#clock-cells = <1>; |
||||
}; |
||||
|
||||
cpus { |
||||
compatible = "cpu_bus"; |
||||
|
||||
PowerPC,8315@0 { |
||||
compatible = "fsl,mpc8315"; |
||||
clocks = <&socclocks MPC83XX_CLK_CORE |
||||
&socclocks MPC83XX_CLK_CSB>; |
||||
}; |
||||
}; |
@ -0,0 +1,24 @@ |
||||
MPC83xx SerDes controller devices |
||||
|
||||
MPC83xx SoCs contain a built-in SerDes controller that determines which |
||||
protocols (SATA, PCI Express, SGMII, ...) are used on the system's serdes lines |
||||
and how the lines are configured. |
||||
|
||||
Required properties: |
||||
- compatible: must be "fsl,mpc83xx-serdes" |
||||
- reg: must point to the serdes controller's register map |
||||
- proto: selects for which protocol the serdes lines are configured. One of |
||||
"sata", "pex", "pex-x2", "sgmii" |
||||
- serdes-clk: determines the frequency the serdes lines are configured for. One |
||||
of 100, 125, 150. |
||||
- vdd: determines whether 1.0V core VDD is used or not |
||||
|
||||
Example: |
||||
|
||||
SERDES: serdes@e3000 { |
||||
reg = <0xe3000 0x200>; |
||||
compatible = "fsl,mpc83xx-serdes"; |
||||
proto = "pex"; |
||||
serdes-clk = <100>; |
||||
vdd; |
||||
}; |
@ -0,0 +1,314 @@ |
||||
MPC83xx RAM controller |
||||
|
||||
This driver supplies support for the embedded RAM controller on MCP83xx-series |
||||
SoCs. |
||||
|
||||
For static configuration mode, each controller node should have child nodes |
||||
describing the actual RAM modules installed. |
||||
|
||||
Controller node |
||||
=============== |
||||
|
||||
Required properties: |
||||
- compatible: Must be "fsl,mpc83xx-mem-controller" |
||||
- reg: The address of the RAM controller's register space |
||||
- #address-cells: Must be 2 |
||||
- #size-cells: Must be 1 |
||||
- driver_software_override: DDR driver software override is enabled (1) or |
||||
disabled (0) |
||||
- p_impedance_override: DDR driver software p-impedance override; possible |
||||
values: |
||||
* DSO_P_IMPEDANCE_HIGHEST_Z |
||||
* DSO_P_IMPEDANCE_MUCH_HIGHER_Z |
||||
* DSO_P_IMPEDANCE_HIGHER_Z |
||||
* DSO_P_IMPEDANCE_NOMINAL |
||||
* DSO_P_IMPEDANCE_LOWER_Z |
||||
- n_impedance_override: DDR driver software n-impedance override; possible |
||||
values: |
||||
* DSO_N_IMPEDANCE_HIGHEST_Z |
||||
* DSO_N_IMPEDANCE_MUCH_HIGHER_Z |
||||
* DSO_N_IMPEDANCE_HIGHER_Z |
||||
* DSO_N_IMPEDANCE_NOMINAL |
||||
* DSO_N_IMPEDANCE_LOWER_Z |
||||
- odt_termination_value: ODT termination value for I/Os; possible values: |
||||
* ODT_TERMINATION_75_OHM |
||||
* ODT_TERMINATION_150_OHM |
||||
- ddr_type: Selects voltage level for DDR pads; possible |
||||
values: |
||||
* DDR_TYPE_DDR2_1_8_VOLT |
||||
* DDR_TYPE_DDR1_2_5_VOLT |
||||
- mvref_sel: Determine where MVREF_SEL signal is generated; |
||||
possible values: |
||||
* MVREF_SEL_EXTERNAL |
||||
* MVREF_SEL_INTERNAL_GVDD |
||||
- m_odr: Disable memory transaction reordering; possible |
||||
values: |
||||
* M_ODR_ENABLE |
||||
* M_ODR_DISABLE |
||||
- clock_adjust: Clock adjust; possible values: |
||||
* CLOCK_ADJUST_025 |
||||
* CLOCK_ADJUST_05 |
||||
* CLOCK_ADJUST_075 |
||||
* CLOCK_ADJUST_1 |
||||
- ext_refresh_rec: Extended refresh recovery time; possible values: |
||||
0, 16, 32, 48, 64, 80, 96, 112 |
||||
- read_to_write: Read-to-write turnaround; possible values: |
||||
0, 1, 2, 3 |
||||
- write_to_read: Write-to-read turnaround; possible values: |
||||
0, 1, 2, 3 |
||||
- read_to_read: Read-to-read turnaround; possible values: |
||||
0, 1, 2, 3 |
||||
- write_to_write: Write-to-write turnaround; possible values: |
||||
0, 1, 2, 3 |
||||
- active_powerdown_exit: Active powerdown exit timing; possible values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- precharge_powerdown_exit: Precharge powerdown exit timing; possible values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- odt_powerdown_exit: ODT powerdown exit timing; possible values: |
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, |
||||
9, 10, 11, 12, 13, 14, 15 |
||||
- mode_reg_set_cycle: Mode register set cycle time; possible values: |
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 |
||||
- precharge_to_activate: Precharge-to-acitvate interval; possible values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- activate_to_precharge: Activate to precharge interval; possible values: |
||||
4, 5, 6, 7, 8, 9, 10, 11, 12, |
||||
13, 14, 15, 16, 17, 18, 19 |
||||
- activate_to_readwrite: Activate to read/write interval for SDRAM; |
||||
possible values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- mcas_latency: MCAS latency from READ command; possible values: |
||||
* CASLAT_20 |
||||
* CASLAT_25 |
||||
* CASLAT_30 |
||||
* CASLAT_35 |
||||
* CASLAT_40 |
||||
* CASLAT_45 |
||||
* CASLAT_50 |
||||
* CASLAT_55 |
||||
* CASLAT_60 |
||||
* CASLAT_65 |
||||
* CASLAT_70 |
||||
* CASLAT_75 |
||||
* CASLAT_80 |
||||
- refresh_recovery: Refresh recovery time; possible values: |
||||
8, 9, 10, 11, 12, 13, 14, 15, |
||||
16, 17, 18, 19, 20, 21, 22, 23 |
||||
- last_data_to_precharge: Last data to precharge minimum interval; possible |
||||
values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- activate_to_activate: Activate-to-activate interval; possible values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- last_write_data_to_read: Last write data pair to read command issue |
||||
interval; possible values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- additive_latency: Additive latency; possible values: |
||||
0, 1, 2, 3, 4, 5 |
||||
- mcas_to_preamble_override: MCAS-to-preamble-override; possible values: |
||||
* READ_LAT |
||||
* READ_LAT_PLUS_1_4 |
||||
* READ_LAT_PLUS_1_2 |
||||
* READ_LAT_PLUS_3_4 |
||||
* READ_LAT_PLUS_1 |
||||
* READ_LAT_PLUS_5_4 |
||||
* READ_LAT_PLUS_3_2 |
||||
* READ_LAT_PLUS_7_4 |
||||
* READ_LAT_PLUS_2 |
||||
* READ_LAT_PLUS_9_4 |
||||
* READ_LAT_PLUS_5_2 |
||||
* READ_LAT_PLUS_11_4 |
||||
* READ_LAT_PLUS_3 |
||||
* READ_LAT_PLUS_13_4 |
||||
* READ_LAT_PLUS_7_2 |
||||
* READ_LAT_PLUS_15_4 |
||||
* READ_LAT_PLUS_4 |
||||
* READ_LAT_PLUS_17_4 |
||||
* READ_LAT_PLUS_9_2 |
||||
* READ_LAT_PLUS_19_4 |
||||
- write_latency: Write latency; possible values: |
||||
1, 2, 3, 4, 5, 6, 7 |
||||
- read_to_precharge: Read to precharge; possible values: |
||||
1, 2, 3, 4 |
||||
- write_cmd_to_write_data: Write command to write data strobe timing |
||||
adjustment; possible values: |
||||
* CLOCK_DELAY_0 |
||||
* CLOCK_DELAY_1_4 |
||||
* CLOCK_DELAY_1_2 |
||||
* CLOCK_DELAY_3_4 |
||||
* CLOCK_DELAY_1 |
||||
* CLOCK_DELAY_5_4 |
||||
* CLOCK_DELAY_3_2 |
||||
- minimum_cke_pulse_width: Minimum CKE pulse width; possible values: |
||||
1, 2, 3, 4 |
||||
- four_activates_window: Window for four activates; possible values: |
||||
1, 2, 3, 4 8, 9, 10, 11, 12, |
||||
13, 14, 15, 16, 17, 18, 19 |
||||
- self_refresh: Self refresh (during sleep); possible values: |
||||
* SREN_DISABLE |
||||
* SREN_ENABLE |
||||
- ecc: Support for ECC; possible values: |
||||
* ECC_DISABLE |
||||
* ECC_ENABLE |
||||
- registered_dram: Support for registered DRAM; possible values: |
||||
* RD_DISABLE |
||||
* RD_ENABLE |
||||
- sdram_type: Type of SDRAM device to be used; possible values: |
||||
* TYPE_DDR1 |
||||
* TYPE_DDR2 |
||||
- dynamic_power_management: Dynamic power management mode; possible values: |
||||
* DYN_PWR_DISABLE |
||||
* DYN_PWR_ENABLE |
||||
- databus_width: DRAM data bus width; possible values |
||||
* DATA_BUS_WIDTH_16 |
||||
* DATA_BUS_WIDTH_32 |
||||
- nc_auto_precharge: Non-concurrent auto-precharge; possible values: |
||||
* NCAP_DISABLE |
||||
* NCAP_ENABLE |
||||
- timing_2t: 2T timing; possible values: |
||||
* TIMING_1T |
||||
* TIMING_2T |
||||
- bank_interleaving_ctrl: Bank (chip select) interleaving control; possible |
||||
values: |
||||
* INTERLEAVE_NONE |
||||
* INTERLEAVE_1_AND_2 |
||||
- precharge_bit_8: Precharge bin 8; possible values |
||||
* PRECHARGE_MA_10 |
||||
* PRECHARGE_MA_8 |
||||
- half_strength: Global half-strength override; possible values: |
||||
* STRENGTH_FULL |
||||
* STRENGTH_HALF |
||||
- bypass_initialization: Bypass initialization; possible values: |
||||
* INITIALIZATION_DONT_BYPASS |
||||
* INITIALIZATION_BYPASS |
||||
- force_self_refresh: Force self refresh; possible values: |
||||
* MODE_NORMAL |
||||
* MODE_REFRESH |
||||
- dll_reset: DLL reset; possible values: |
||||
* DLL_RESET_ENABLE |
||||
* DLL_RESET_DISABLE |
||||
- dqs_config: DQS configuration; possible values: |
||||
* DQS_TRUE |
||||
- odt_config: ODT configuration; possible values: |
||||
* ODT_ASSERT_NEVER |
||||
* ODT_ASSERT_WRITES |
||||
* ODT_ASSERT_READS |
||||
* ODT_ASSERT_ALWAYS |
||||
- posted_refreshes: Number of posted refreshes |
||||
1, 2, 3, 4, 5, 6, 7, 8 |
||||
- sdmode: Initial value loaded into the DDR SDRAM mode |
||||
register |
||||
- esdmode: Initial value loaded into the DDR SDRAM extended |
||||
mode register |
||||
- esdmode2: Initial value loaded into the DDR SDRAM extended |
||||
mode 2 register |
||||
- esdmode3: Initial value loaded into the DDR SDRAM extended |
||||
mode 3 register |
||||
- refresh_interval: Refresh interval; possible values: |
||||
0 - 65535 |
||||
- precharge_interval: Precharge interval; possible values: |
||||
0 - 16383 |
||||
|
||||
RAM module node: |
||||
================ |
||||
|
||||
Required properties: |
||||
- reg: A triple <cs addr size>, which consists of: |
||||
* cs - the chipselect used to drive this RAM module |
||||
* addr - the address where this RAM module's memory is map |
||||
to in the global memory space |
||||
* size - the size of the RAM module's memory in bytes |
||||
- auto_precharge: Chip select auto-precharge; possible values: |
||||
* AUTO_PRECHARGE_ENABLE |
||||
* AUTO_PRECHARGE_DISABLE |
||||
- odt_rd_cfg: ODT for reads configuration; possible values: |
||||
* ODT_RD_NEVER |
||||
* ODT_RD_ONLY_CURRENT |
||||
* ODT_RD_ONLY_OTHER_CS |
||||
* ODT_RD_ONLY_OTHER_DIMM |
||||
* ODT_RD_ALL |
||||
- odt_wr_cfg: ODT for writes configuration; possible values: |
||||
* ODT_WR_NEVER |
||||
* ODT_WR_ONLY_CURRENT |
||||
* ODT_WR_ONLY_OTHER_CS |
||||
* ODT_WR_ONLY_OTHER_DIMM |
||||
* ODT_WR_ALL |
||||
- bank_bits: Number of bank bits for SDRAM on chip select; possible |
||||
values: |
||||
2, 3 |
||||
- row_bits: Number of row bits for SDRAM on chip select; possible values: |
||||
12, 13, 14 |
||||
- col_bits: Number of column bits for SDRAM on chip select; possible |
||||
values: |
||||
8, 9, 10, 11 |
||||
|
||||
Example: |
||||
|
||||
memory@2000 { |
||||
#address-cells = <2>; |
||||
#size-cells = <1>; |
||||
compatible = "fsl,mpc83xx-mem-controller"; |
||||
reg = <0x2000 0x1000>; |
||||
device_type = "memory"; |
||||
u-boot,dm-pre-reloc; |
||||
|
||||
driver_software_override = <DSO_ENABLE>; |
||||
p_impedance_override = <DSO_P_IMPEDANCE_NOMINAL>; |
||||
n_impedance_override = <DSO_N_IMPEDANCE_NOMINAL>; |
||||
odt_termination_value = <ODT_TERMINATION_150_OHM>; |
||||
ddr_type = <DDR_TYPE_DDR2_1_8_VOLT>; |
||||
|
||||
clock_adjust = <CLOCK_ADJUST_05>; |
||||
|
||||
read_to_write = <0>; |
||||
write_to_read = <0>; |
||||
read_to_read = <0>; |
||||
write_to_write = <0>; |
||||
active_powerdown_exit = <2>; |
||||
precharge_powerdown_exit = <6>; |
||||
odt_powerdown_exit = <8>; |
||||
mode_reg_set_cycle = <2>; |
||||
|
||||
precharge_to_activate = <2>; |
||||
activate_to_precharge = <6>; |
||||
activate_to_readwrite = <2>; |
||||
mcas_latency = <CASLAT_40>; |
||||
refresh_recovery = <17>; |
||||
last_data_to_precharge = <2>; |
||||
activate_to_activate = <2>; |
||||
last_write_data_to_read = <2>; |
||||
|
||||
additive_latency = <0>; |
||||
mcas_to_preamble_override = <READ_LAT_PLUS_1_2>; |
||||
write_latency = <3>; |
||||
read_to_precharge = <2>; |
||||
write_cmd_to_write_data = <CLOCK_DELAY_1_2>; |
||||
minimum_cke_pulse_width = <3>; |
||||
four_activates_window = <5>; |
||||
|
||||
self_refresh = <SREN_ENABLE>; |
||||
sdram_type = <TYPE_DDR2>; |
||||
databus_width = <DATA_BUS_WIDTH_32>; |
||||
|
||||
force_self_refresh = <MODE_NORMAL>; |
||||
dll_reset = <DLL_RESET_ENABLE>; |
||||
dqs_config = <DQS_TRUE>; |
||||
odt_config = <ODT_ASSERT_READS>; |
||||
posted_refreshes = <1>; |
||||
|
||||
refresh_interval = <2084>; |
||||
precharge_interval = <256>; |
||||
|
||||
sdmode = <0x0242>; |
||||
esdmode = <0x0440>; |
||||
|
||||
ram@0 { |
||||
reg = <0x0 0x0 0x8000000>; |
||||
compatible = "nanya,nt5tu64m16hg"; |
||||
|
||||
odt_rd_cfg = <ODT_RD_NEVER>; |
||||
odt_wr_cfg = <ODT_WR_ONLY_CURRENT>; |
||||
bank_bits = <3>; |
||||
row_bits = <13>; |
||||
col_bits = <10>; |
||||
}; |
||||
}; |
@ -0,0 +1,21 @@ |
||||
MPC83xx timer devices |
||||
|
||||
MPC83xx SoCs offer a decrementer interrupt that can be used to implement delay |
||||
functionality, and periodically triggered actions. |
||||
|
||||
Required properties: |
||||
- compatible: must be "fsl,mpc83xx-timer" |
||||
- clocks: must be a reference to the system's CSB (coherent system bus) clock, |
||||
provided by one of the "fsl,mpc83xx-clk" devices |
||||
|
||||
Example: |
||||
|
||||
socclocks: clocks { |
||||
compatible = "fsl,mpc832x-clk"; |
||||
#clock-cells = <1>; |
||||
}; |
||||
|
||||
timer { |
||||
compatible = "fsl,mpc83xx-timer"; |
||||
clocks = <&socclocks MPC83XX_CLK_CSB>; |
||||
}; |
@ -0,0 +1,74 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#ifndef _MPC83XX_SOC_H_ |
||||
#define _MPC83XX_SOC_H_ |
||||
|
||||
enum soc_type { |
||||
SOC_MPC8308, |
||||
SOC_MPC8309, |
||||
SOC_MPC8313, |
||||
SOC_MPC8315, |
||||
SOC_MPC832X, |
||||
SOC_MPC8349, |
||||
SOC_MPC8360, |
||||
SOC_MPC8379, |
||||
}; |
||||
|
||||
bool mpc83xx_has_sdhc(int type) |
||||
{ |
||||
return (type == SOC_MPC8308) || |
||||
(type == SOC_MPC8309) || |
||||
(type == SOC_MPC8379); |
||||
} |
||||
|
||||
bool mpc83xx_has_tsec(int type) |
||||
{ |
||||
return (type == SOC_MPC8308) || |
||||
(type == SOC_MPC8313) || |
||||
(type == SOC_MPC8315) || |
||||
(type == SOC_MPC8349) || |
||||
(type == SOC_MPC8379); |
||||
} |
||||
|
||||
bool mpc83xx_has_pcie1(int type) |
||||
{ |
||||
return (type == SOC_MPC8308) || |
||||
(type == SOC_MPC8315) || |
||||
(type == SOC_MPC8379); |
||||
} |
||||
|
||||
bool mpc83xx_has_pcie2(int type) |
||||
{ |
||||
return (type == SOC_MPC8315) || |
||||
(type == SOC_MPC8379); |
||||
} |
||||
|
||||
bool mpc83xx_has_sata(int type) |
||||
{ |
||||
return (type == SOC_MPC8315) || |
||||
(type == SOC_MPC8379); |
||||
} |
||||
|
||||
bool mpc83xx_has_pci(int type) |
||||
{ |
||||
return type != SOC_MPC8308; |
||||
} |
||||
|
||||
bool mpc83xx_has_second_i2c(int type) |
||||
{ |
||||
return (type != SOC_MPC8315) && |
||||
(type != SOC_MPC832X); |
||||
} |
||||
|
||||
bool mpc83xx_has_quicc_engine(int type) |
||||
{ |
||||
return (type == SOC_MPC8309) || |
||||
(type == SOC_MPC832X) || |
||||
(type == SOC_MPC8360); |
||||
} |
||||
|
||||
#endif /* _MPC83XX_SOC_H_ */ |
@ -0,0 +1,410 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2017 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <clk-uclass.h> |
||||
#include <dm.h> |
||||
#include <dm/lists.h> |
||||
#include <dt-bindings/clk/mpc83xx-clk.h> |
||||
#include <asm/arch/soc.h> |
||||
|
||||
#include "mpc83xx_clk.h" |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
/**
|
||||
* struct mpc83xx_clk_priv - Private data structure for the MPC83xx clock |
||||
* driver |
||||
* @speed: Array containing the speed values of all system clocks (initialized |
||||
* once, then only read back) |
||||
*/ |
||||
struct mpc83xx_clk_priv { |
||||
u32 speed[MPC83XX_CLK_COUNT]; |
||||
}; |
||||
|
||||
/**
|
||||
* is_clk_valid() - Check if clock ID is valid for given clock device |
||||
* @clk: The clock device for which to check a clock ID |
||||
* @id: The clock ID to check |
||||
* |
||||
* Return: true if clock ID is valid for clock device, false if not |
||||
*/ |
||||
static inline bool is_clk_valid(struct udevice *clk, int id) |
||||
{ |
||||
ulong type = dev_get_driver_data(clk); |
||||
|
||||
switch (id) { |
||||
case MPC83XX_CLK_MEM: |
||||
return true; |
||||
case MPC83XX_CLK_MEM_SEC: |
||||
return type == SOC_MPC8360; |
||||
case MPC83XX_CLK_ENC: |
||||
return (type == SOC_MPC8308) || (type == SOC_MPC8309); |
||||
case MPC83XX_CLK_I2C1: |
||||
return true; |
||||
case MPC83XX_CLK_TDM: |
||||
return type == SOC_MPC8315; |
||||
case MPC83XX_CLK_SDHC: |
||||
return mpc83xx_has_sdhc(type); |
||||
case MPC83XX_CLK_TSEC1: |
||||
case MPC83XX_CLK_TSEC2: |
||||
return mpc83xx_has_tsec(type); |
||||
case MPC83XX_CLK_USBDR: |
||||
return type == SOC_MPC8360; |
||||
case MPC83XX_CLK_USBMPH: |
||||
return type == SOC_MPC8349; |
||||
case MPC83XX_CLK_PCIEXP1: |
||||
return mpc83xx_has_pcie1(type); |
||||
case MPC83XX_CLK_PCIEXP2: |
||||
return mpc83xx_has_pcie2(type); |
||||
case MPC83XX_CLK_SATA: |
||||
return mpc83xx_has_sata(type); |
||||
case MPC83XX_CLK_DMAC: |
||||
return (type == SOC_MPC8308) || (type == SOC_MPC8309); |
||||
case MPC83XX_CLK_PCI: |
||||
return mpc83xx_has_pci(type); |
||||
case MPC83XX_CLK_CSB: |
||||
return true; |
||||
case MPC83XX_CLK_I2C2: |
||||
return mpc83xx_has_second_i2c(type); |
||||
case MPC83XX_CLK_QE: |
||||
case MPC83XX_CLK_BRG: |
||||
return mpc83xx_has_quicc_engine(type) && (type != SOC_MPC8309); |
||||
case MPC83XX_CLK_LCLK: |
||||
case MPC83XX_CLK_LBIU: |
||||
case MPC83XX_CLK_CORE: |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/**
|
||||
* init_single_clk() - Initialize a clock with a given ID |
||||
* @dev: The clock device for which to initialize the clock |
||||
* @clk: The clock ID |
||||
* |
||||
* The clock speed is read from the hardware's registers, and stored in the |
||||
* private data structure of the driver. From there it is only retrieved, and |
||||
* not set. |
||||
* |
||||
* Return: 0 if OK, -ve on error |
||||
*/ |
||||
static int init_single_clk(struct udevice *dev, int clk) |
||||
{ |
||||
struct mpc83xx_clk_priv *priv = dev_get_priv(dev); |
||||
immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
||||
ulong type = dev_get_driver_data(dev); |
||||
struct clk_mode mode; |
||||
ulong mask; |
||||
u32 csb_clk = get_csb_clk(im); |
||||
int ret; |
||||
|
||||
ret = retrieve_mode(clk, type, &mode); |
||||
if (ret) { |
||||
debug("%s: Could not retrieve mode for clk %d (ret = %d)\n", |
||||
dev->name, clk, ret); |
||||
return ret; |
||||
} |
||||
|
||||
if (mode.type == TYPE_INVALID) { |
||||
debug("%s: clock %d invalid\n", dev->name, clk); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
if (mode.type == TYPE_SCCR_STANDARD) { |
||||
mask = GENMASK(31 - mode.low, 31 - mode.high); |
||||
|
||||
switch (sccr_field(im, mask)) { |
||||
case 0: |
||||
priv->speed[clk] = 0; |
||||
break; |
||||
case 1: |
||||
priv->speed[clk] = csb_clk; |
||||
break; |
||||
case 2: |
||||
priv->speed[clk] = csb_clk / 2; |
||||
break; |
||||
case 3: |
||||
priv->speed[clk] = csb_clk / 3; |
||||
break; |
||||
default: |
||||
priv->speed[clk] = 0; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
if (mode.type == TYPE_SPMR_DIRECT_MULTIPLY) { |
||||
mask = GENMASK(31 - mode.low, 31 - mode.high); |
||||
|
||||
priv->speed[clk] = csb_clk * (1 + sccr_field(im, mask)); |
||||
return 0; |
||||
} |
||||
|
||||
if (clk == MPC83XX_CLK_CSB || clk == MPC83XX_CLK_I2C2) { |
||||
priv->speed[clk] = csb_clk; /* i2c-2 clk is equal to csb clk */ |
||||
return 0; |
||||
} |
||||
|
||||
if (clk == MPC83XX_CLK_QE || clk == MPC83XX_CLK_BRG) { |
||||
u32 pci_sync_in = get_pci_sync_in(im); |
||||
u32 qepmf = spmr_field(im, SPMR_CEPMF); |
||||
u32 qepdf = spmr_field(im, SPMR_CEPDF); |
||||
u32 qe_clk = (pci_sync_in * qepmf) / (1 + qepdf); |
||||
|
||||
if (clk == MPC83XX_CLK_QE) |
||||
priv->speed[clk] = qe_clk; |
||||
else |
||||
priv->speed[clk] = qe_clk / 2; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
if (clk == MPC83XX_CLK_LCLK || clk == MPC83XX_CLK_LBIU) { |
||||
u32 lbiu_clk = csb_clk * |
||||
(1 + spmr_field(im, SPMR_LBIUCM)); |
||||
u32 clkdiv = lcrr_field(im, LCRR_CLKDIV); |
||||
|
||||
if (clk == MPC83XX_CLK_LBIU) |
||||
priv->speed[clk] = lbiu_clk; |
||||
|
||||
switch (clkdiv) { |
||||
case 2: |
||||
case 4: |
||||
case 8: |
||||
priv->speed[clk] = lbiu_clk / clkdiv; |
||||
break; |
||||
default: |
||||
/* unknown lcrr */ |
||||
priv->speed[clk] = 0; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
if (clk == MPC83XX_CLK_CORE) { |
||||
u8 corepll = spmr_field(im, SPMR_COREPLL); |
||||
u32 corecnf_tab_index = ((corepll & 0x1F) << 2) | |
||||
((corepll & 0x60) >> 5); |
||||
|
||||
if (corecnf_tab_index > (ARRAY_SIZE(corecnf_tab))) { |
||||
debug("%s: Core configuration index %02x too high; possible wrong value", |
||||
dev->name, corecnf_tab_index); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) { |
||||
case RAT_BYP: |
||||
case RAT_1_TO_1: |
||||
priv->speed[clk] = csb_clk; |
||||
break; |
||||
case RAT_1_5_TO_1: |
||||
priv->speed[clk] = (3 * csb_clk) / 2; |
||||
break; |
||||
case RAT_2_TO_1: |
||||
priv->speed[clk] = 2 * csb_clk; |
||||
break; |
||||
case RAT_2_5_TO_1: |
||||
priv->speed[clk] = (5 * csb_clk) / 2; |
||||
break; |
||||
case RAT_3_TO_1: |
||||
priv->speed[clk] = 3 * csb_clk; |
||||
break; |
||||
default: |
||||
/* unknown core to csb ratio */ |
||||
priv->speed[clk] = 0; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* Unknown clk value -> error */ |
||||
debug("%s: clock %d invalid\n", dev->name, clk); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
/**
|
||||
* init_all_clks() - Initialize all clocks of a clock device |
||||
* @dev: The clock device whose clocks should be initialized |
||||
* |
||||
* Return: 0 if OK, -ve on error |
||||
*/ |
||||
static inline int init_all_clks(struct udevice *dev) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < MPC83XX_CLK_COUNT; i++) { |
||||
int ret; |
||||
|
||||
if (!is_clk_valid(dev, i)) |
||||
continue; |
||||
|
||||
ret = init_single_clk(dev, i); |
||||
if (ret) { |
||||
debug("%s: Failed to initialize %s clock\n", |
||||
dev->name, names[i]); |
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mpc83xx_clk_request(struct clk *clock) |
||||
{ |
||||
/* Reject requests of clocks that are not available */ |
||||
if (is_clk_valid(clock->dev, clock->id)) |
||||
return 0; |
||||
else |
||||
return -ENODEV; |
||||
} |
||||
|
||||
static ulong mpc83xx_clk_get_rate(struct clk *clk) |
||||
{ |
||||
struct mpc83xx_clk_priv *priv = dev_get_priv(clk->dev); |
||||
|
||||
if (clk->id >= MPC83XX_CLK_COUNT) { |
||||
debug("%s: clock index %lu invalid\n", __func__, clk->id); |
||||
return 0; |
||||
} |
||||
|
||||
return priv->speed[clk->id]; |
||||
} |
||||
|
||||
int get_clocks(void) |
||||
{ |
||||
/* Empty implementation to keep the prototype in common.h happy */ |
||||
return 0; |
||||
} |
||||
|
||||
int get_serial_clock(void) |
||||
{ |
||||
struct mpc83xx_clk_priv *priv; |
||||
struct udevice *clk; |
||||
int ret; |
||||
|
||||
ret = uclass_first_device_err(UCLASS_CLK, &clk); |
||||
if (ret) { |
||||
debug("%s: Could not get clock device\n", __func__); |
||||
return ret; |
||||
} |
||||
|
||||
priv = dev_get_priv(clk); |
||||
|
||||
return priv->speed[MPC83XX_CLK_CSB]; |
||||
} |
||||
|
||||
const struct clk_ops mpc83xx_clk_ops = { |
||||
.request = mpc83xx_clk_request, |
||||
.get_rate = mpc83xx_clk_get_rate, |
||||
}; |
||||
|
||||
static const struct udevice_id mpc83xx_clk_match[] = { |
||||
{ .compatible = "fsl,mpc8308-clk", .data = SOC_MPC8308 }, |
||||
{ .compatible = "fsl,mpc8309-clk", .data = SOC_MPC8309 }, |
||||
{ .compatible = "fsl,mpc8313-clk", .data = SOC_MPC8313 }, |
||||
{ .compatible = "fsl,mpc8315-clk", .data = SOC_MPC8315 }, |
||||
{ .compatible = "fsl,mpc832x-clk", .data = SOC_MPC832X }, |
||||
{ .compatible = "fsl,mpc8349-clk", .data = SOC_MPC8349 }, |
||||
{ .compatible = "fsl,mpc8360-clk", .data = SOC_MPC8360 }, |
||||
{ .compatible = "fsl,mpc8379-clk", .data = SOC_MPC8379 }, |
||||
{ /* sentinel */ } |
||||
}; |
||||
|
||||
static int mpc83xx_clk_probe(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_clk_priv *priv = dev_get_priv(dev); |
||||
ulong type; |
||||
int ret; |
||||
|
||||
ret = init_all_clks(dev); |
||||
if (ret) { |
||||
debug("%s: Could not initialize all clocks (ret = %d)\n", |
||||
dev->name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
type = dev_get_driver_data(dev); |
||||
|
||||
if (mpc83xx_has_sdhc(type)) |
||||
gd->arch.sdhc_clk = priv->speed[MPC83XX_CLK_SDHC]; |
||||
|
||||
gd->arch.core_clk = priv->speed[MPC83XX_CLK_CORE]; |
||||
gd->arch.i2c1_clk = priv->speed[MPC83XX_CLK_I2C1]; |
||||
if (mpc83xx_has_second_i2c(type)) |
||||
gd->arch.i2c2_clk = priv->speed[MPC83XX_CLK_I2C2]; |
||||
|
||||
gd->mem_clk = priv->speed[MPC83XX_CLK_MEM]; |
||||
|
||||
if (mpc83xx_has_pci(type)) |
||||
gd->pci_clk = priv->speed[MPC83XX_CLK_PCI]; |
||||
|
||||
gd->cpu_clk = priv->speed[MPC83XX_CLK_CORE]; |
||||
gd->bus_clk = priv->speed[MPC83XX_CLK_CSB]; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mpc83xx_clk_bind(struct udevice *dev) |
||||
{ |
||||
int ret; |
||||
struct udevice *sys_child; |
||||
|
||||
/*
|
||||
* Since there is no corresponding device tree entry, and since the |
||||
* clock driver has to be present in either case, bind the sysreset |
||||
* driver here. |
||||
*/ |
||||
ret = device_bind_driver(dev, "mpc83xx_sysreset", "sysreset", |
||||
&sys_child); |
||||
if (ret) |
||||
debug("%s: No sysreset driver: ret=%d\n", |
||||
dev->name, ret); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_DRIVER(mpc83xx_clk) = { |
||||
.name = "mpc83xx_clk", |
||||
.id = UCLASS_CLK, |
||||
.of_match = mpc83xx_clk_match, |
||||
.ops = &mpc83xx_clk_ops, |
||||
.probe = mpc83xx_clk_probe, |
||||
.priv_auto_alloc_size = sizeof(struct mpc83xx_clk_priv), |
||||
.bind = mpc83xx_clk_bind, |
||||
}; |
||||
|
||||
static int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
int i; |
||||
char buf[32]; |
||||
struct udevice *clk; |
||||
int ret; |
||||
struct mpc83xx_clk_priv *priv; |
||||
|
||||
ret = uclass_first_device_err(UCLASS_CLK, &clk); |
||||
if (ret) { |
||||
debug("%s: Could not get clock device\n", __func__); |
||||
return ret; |
||||
} |
||||
|
||||
for (i = 0; i < MPC83XX_CLK_COUNT; i++) { |
||||
if (!is_clk_valid(clk, i)) |
||||
continue; |
||||
|
||||
priv = dev_get_priv(clk); |
||||
|
||||
printf("%s = %s MHz\n", names[i], strmhz(buf, priv->speed[i])); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_CMD(clocks, 1, 1, do_clocks, |
||||
"display values of SoC's clocks", |
||||
"" |
||||
); |
@ -0,0 +1,379 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
/**
|
||||
* enum ratio - Description of a core clock ratio |
||||
* @RAT_UNK: Unknown ratio |
||||
* @RAT_BYP: Bypass |
||||
* @RAT_1_TO_8: Ratio 1:8 |
||||
* @RAT_1_TO_4: Ratio 1:4 |
||||
* @RAT_1_TO_2: Ratio 1:2 |
||||
* @RAT_1_TO_1: Ratio 1:1 |
||||
* @RAT_1_5_TO_1: Ratio 1.5:1 |
||||
* @RAT_2_TO_1: Ratio 2:1 |
||||
* @RAT_2_5_TO_1: Ratio 2.5:1 |
||||
* @RAT_3_TO_1: Ratio 3:1 |
||||
*/ |
||||
enum ratio { |
||||
RAT_UNK, |
||||
RAT_BYP, |
||||
RAT_1_TO_8, |
||||
RAT_1_TO_4, |
||||
RAT_1_TO_2, |
||||
RAT_1_TO_1, |
||||
RAT_1_5_TO_1, |
||||
RAT_2_TO_1, |
||||
RAT_2_5_TO_1, |
||||
RAT_3_TO_1 |
||||
}; |
||||
|
||||
/**
|
||||
* struct corecnf - Description for a core clock configuration |
||||
* @core_csb_ratio: Core clock frequency to CSB clock frequency ratio |
||||
* @vco_divider: VCO divider (Core VCO frequency = Core frequency * VCO divider) |
||||
*/ |
||||
struct corecnf { |
||||
int core_csb_ratio; |
||||
int vco_divider; |
||||
}; |
||||
|
||||
/*
|
||||
* Table with all valid Core CSB frequency ratio / VCO divider combinations as |
||||
* indexed by the COREPLL field of the SPMR |
||||
*/ |
||||
static const struct corecnf corecnf_tab[] = { |
||||
{RAT_BYP, RAT_BYP}, /* 0x00 */ |
||||
{RAT_BYP, RAT_BYP}, /* 0x01 */ |
||||
{RAT_BYP, RAT_BYP}, /* 0x02 */ |
||||
{RAT_BYP, RAT_BYP}, /* 0x03 */ |
||||
{RAT_BYP, RAT_BYP}, /* 0x04 */ |
||||
{RAT_BYP, RAT_BYP}, /* 0x05 */ |
||||
{RAT_BYP, RAT_BYP}, /* 0x06 */ |
||||
{RAT_BYP, RAT_BYP}, /* 0x07 */ |
||||
{RAT_1_TO_1, RAT_1_TO_2}, /* 0x08 */ |
||||
{RAT_1_TO_1, RAT_1_TO_4}, /* 0x09 */ |
||||
{RAT_1_TO_1, RAT_1_TO_8}, /* 0x0A */ |
||||
{RAT_1_TO_1, RAT_1_TO_8}, /* 0x0B */ |
||||
{RAT_1_5_TO_1, RAT_1_TO_2}, /* 0x0C */ |
||||
{RAT_1_5_TO_1, RAT_1_TO_4}, /* 0x0D */ |
||||
{RAT_1_5_TO_1, RAT_1_TO_8}, /* 0x0E */ |
||||
{RAT_1_5_TO_1, RAT_1_TO_8}, /* 0x0F */ |
||||
{RAT_2_TO_1, RAT_1_TO_2}, /* 0x10 */ |
||||
{RAT_2_TO_1, RAT_1_TO_4}, /* 0x11 */ |
||||
{RAT_2_TO_1, RAT_1_TO_8}, /* 0x12 */ |
||||
{RAT_2_TO_1, RAT_1_TO_8}, /* 0x13 */ |
||||
{RAT_2_5_TO_1, RAT_1_TO_2}, /* 0x14 */ |
||||
{RAT_2_5_TO_1, RAT_1_TO_4}, /* 0x15 */ |
||||
{RAT_2_5_TO_1, RAT_1_TO_8}, /* 0x16 */ |
||||
{RAT_2_5_TO_1, RAT_1_TO_8}, /* 0x17 */ |
||||
{RAT_3_TO_1, RAT_1_TO_2}, /* 0x18 */ |
||||
{RAT_3_TO_1, RAT_1_TO_4}, /* 0x19 */ |
||||
{RAT_3_TO_1, RAT_1_TO_8}, /* 0x1A */ |
||||
{RAT_3_TO_1, RAT_1_TO_8}, /* 0x1B */ |
||||
}; |
||||
|
||||
/**
|
||||
* enum reg_type - Register to read a field from |
||||
* @REG_SCCR: Use the SCCR register |
||||
* @REG_SPMR: Use the SPMR register |
||||
*/ |
||||
enum reg_type { |
||||
REG_SCCR, |
||||
REG_SPMR, |
||||
}; |
||||
|
||||
/**
|
||||
* enum mode_type - Description of how to read a specific frequency value |
||||
* @TYPE_INVALID: Unknown type, will provoke error |
||||
* @TYPE_SCCR_STANDARD: Read a field from the SCCR register, and use it |
||||
* as a divider for the CSB clock to compute the |
||||
* frequency |
||||
* @TYPE_SCCR_ONOFF: The field describes a bit flag that can turn the |
||||
* clock on or off |
||||
* @TYPE_SPMR_DIRECT_MULTIPLY: Read a field from the SPMR register, and use it |
||||
* as a multiplier for the CSB clock to compute the |
||||
* frequency |
||||
* @TYPE_SPECIAL: The frequency is calculated in a non-standard way |
||||
*/ |
||||
enum mode_type { |
||||
TYPE_INVALID = 0, |
||||
TYPE_SCCR_STANDARD, |
||||
TYPE_SCCR_ONOFF, |
||||
TYPE_SPMR_DIRECT_MULTIPLY, |
||||
TYPE_SPECIAL, |
||||
}; |
||||
|
||||
/* Map of each clock index to its human-readable name */ |
||||
static const char * const names[] = { |
||||
[MPC83XX_CLK_CORE] = "Core", |
||||
[MPC83XX_CLK_CSB] = "Coherent System Bus", |
||||
[MPC83XX_CLK_QE] = "QE", |
||||
[MPC83XX_CLK_BRG] = "BRG", |
||||
[MPC83XX_CLK_LBIU] = "Local Bus Controller", |
||||
[MPC83XX_CLK_LCLK] = "Local Bus", |
||||
[MPC83XX_CLK_MEM] = "DDR", |
||||
[MPC83XX_CLK_MEM_SEC] = "DDR Secondary", |
||||
[MPC83XX_CLK_ENC] = "SEC", |
||||
[MPC83XX_CLK_I2C1] = "I2C1", |
||||
[MPC83XX_CLK_I2C2] = "I2C2", |
||||
[MPC83XX_CLK_TDM] = "TDM", |
||||
[MPC83XX_CLK_SDHC] = "SDHC", |
||||
[MPC83XX_CLK_TSEC1] = "TSEC1", |
||||
[MPC83XX_CLK_TSEC2] = "TSEC2", |
||||
[MPC83XX_CLK_USBDR] = "USB DR", |
||||
[MPC83XX_CLK_USBMPH] = "USB MPH", |
||||
[MPC83XX_CLK_PCIEXP1] = "PCIEXP1", |
||||
[MPC83XX_CLK_PCIEXP2] = "PCIEXP2", |
||||
[MPC83XX_CLK_SATA] = "SATA", |
||||
[MPC83XX_CLK_DMAC] = "DMAC", |
||||
[MPC83XX_CLK_PCI] = "PCI", |
||||
}; |
||||
|
||||
/**
|
||||
* struct clk_mode - Structure for clock mode descriiptions |
||||
* @low: The low bit of the data field to read for this mode (may not apply to |
||||
* some modes) |
||||
* @high: The high bit of the data field to read for this mode (may not apply to |
||||
* some modes) |
||||
* @type: The type of the mode description (one of enum mode_type) |
||||
*/ |
||||
struct clk_mode { |
||||
u8 low; |
||||
u8 high; |
||||
int type; |
||||
}; |
||||
|
||||
/**
|
||||
* set_mode() - Build a clock mode description from data |
||||
* @mode: The clock mode description to be filled out |
||||
* @low: The low bit of the data field to read for this mode (may not apply to |
||||
* some modes) |
||||
* @high: The high bit of the data field to read for this mode (may not apply to |
||||
* some modes) |
||||
* @type: The type of the mode description (one of enum mode_type) |
||||
* |
||||
* Clock mode descriptions are a succinct description of how to read a specific |
||||
* clock's rate from the hardware; usually by reading a specific field of a |
||||
* register, such a s the SCCR register, but some types use different methods |
||||
* for obtaining the clock rate. |
||||
*/ |
||||
static void set_mode(struct clk_mode *mode, u8 low, u8 high, int type) |
||||
{ |
||||
mode->low = low; |
||||
mode->high = high; |
||||
mode->type = type; |
||||
} |
||||
|
||||
/**
|
||||
* retrieve_mode() - Get the clock mode description for a specific clock |
||||
* @clk: The identifier of the clock for which the clock description should |
||||
* be retrieved |
||||
* @soc_type: The type of MPC83xx SoC for which the clock description should be |
||||
* retrieved |
||||
* @mode: Pointer to a clk_mode structure to be filled with data for the |
||||
* clock |
||||
* |
||||
* Since some clock rate are stored in different places on different MPC83xx |
||||
* SoCs, the SoC type has to be supplied along with the clock's identifier. |
||||
* |
||||
* Return: 0 if OK, -ve on error |
||||
*/ |
||||
static int retrieve_mode(int clk, int soc_type, struct clk_mode *mode) |
||||
{ |
||||
switch (clk) { |
||||
case MPC83XX_CLK_CORE: |
||||
case MPC83XX_CLK_CSB: |
||||
case MPC83XX_CLK_QE: |
||||
case MPC83XX_CLK_BRG: |
||||
case MPC83XX_CLK_LCLK: |
||||
case MPC83XX_CLK_I2C2: |
||||
set_mode(mode, 0, 0, TYPE_SPECIAL); |
||||
break; |
||||
case MPC83XX_CLK_MEM: |
||||
set_mode(mode, 1, 1, TYPE_SPMR_DIRECT_MULTIPLY); |
||||
break; |
||||
case MPC83XX_CLK_LBIU: |
||||
case MPC83XX_CLK_MEM_SEC: |
||||
set_mode(mode, 0, 0, TYPE_SPMR_DIRECT_MULTIPLY); |
||||
break; |
||||
case MPC83XX_CLK_TSEC1: |
||||
set_mode(mode, 0, 1, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_TSEC2: |
||||
if (soc_type == SOC_MPC8313) /* I2C and TSEC2 are the same register */ |
||||
set_mode(mode, 2, 3, TYPE_SCCR_STANDARD); |
||||
else /* FIXME(mario.six@gdsys.cc): This has separate enable/disable bit! */ |
||||
set_mode(mode, 0, 1, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_SDHC: |
||||
set_mode(mode, 4, 5, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_ENC: |
||||
set_mode(mode, 6, 7, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_I2C1: |
||||
if (soc_type == SOC_MPC8349) |
||||
set_mode(mode, 2, 3, TYPE_SCCR_STANDARD); |
||||
else /* I2C and ENC are the same register */ |
||||
set_mode(mode, 6, 7, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_PCIEXP1: |
||||
set_mode(mode, 10, 11, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_PCIEXP2: |
||||
set_mode(mode, 12, 13, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_USBDR: |
||||
if (soc_type == SOC_MPC8313 || soc_type == SOC_MPC8349) |
||||
set_mode(mode, 10, 11, TYPE_SCCR_STANDARD); |
||||
else |
||||
set_mode(mode, 8, 9, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_USBMPH: |
||||
set_mode(mode, 8, 9, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_PCI: |
||||
set_mode(mode, 15, 15, TYPE_SCCR_ONOFF); |
||||
break; |
||||
case MPC83XX_CLK_DMAC: |
||||
set_mode(mode, 26, 27, TYPE_SCCR_STANDARD); |
||||
break; |
||||
case MPC83XX_CLK_SATA: |
||||
/* FIXME(mario.six@gdsys.cc): All SATA controllers must have the same clock ratio */ |
||||
if (soc_type == SOC_MPC8379) { |
||||
set_mode(mode, 24, 25, TYPE_SCCR_STANDARD); |
||||
set_mode(mode, 26, 27, TYPE_SCCR_STANDARD); |
||||
set_mode(mode, 28, 29, TYPE_SCCR_STANDARD); |
||||
set_mode(mode, 30, 31, TYPE_SCCR_STANDARD); |
||||
} else { |
||||
set_mode(mode, 18, 19, TYPE_SCCR_STANDARD); |
||||
set_mode(mode, 20, 21, TYPE_SCCR_STANDARD); |
||||
} |
||||
break; |
||||
case MPC83XX_CLK_TDM: |
||||
set_mode(mode, 26, 27, TYPE_SCCR_STANDARD); |
||||
break; |
||||
default: |
||||
debug("%s: Unknown clock type %d on soc type %d\n", |
||||
__func__, clk, soc_type); |
||||
set_mode(mode, 0, 0, TYPE_INVALID); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* get_spmr() - Read the SPMR (System PLL Mode Register) |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* |
||||
* Return: The SPMR value as a 32-bit number. |
||||
*/ |
||||
static inline u32 get_spmr(immap_t *im) |
||||
{ |
||||
u32 res = in_be32(&im->clk.spmr); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
/**
|
||||
* get_sccr() - Read the SCCR (System Clock Control Register) |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* |
||||
* Return: The SCCR value as a 32-bit number. |
||||
*/ |
||||
static inline u32 get_sccr(immap_t *im) |
||||
{ |
||||
u32 res = in_be32(&im->clk.sccr); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
/**
|
||||
* get_lcrr() - Read the LCRR (Clock Ratio Register) |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* |
||||
* Return: The LCRR value as a 32-bit number. |
||||
*/ |
||||
static inline u32 get_lcrr(immap_t *im) |
||||
{ |
||||
u32 res = in_be32(&im->im_lbc.lcrr); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
/**
|
||||
* get_pci_sync_in() - Read the PCI synchronization clock speed |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* |
||||
* Return: The PCI synchronization clock speed value as a 32-bit number. |
||||
*/ |
||||
static inline u32 get_pci_sync_in(immap_t *im) |
||||
{ |
||||
u8 clkin_div; |
||||
|
||||
clkin_div = (get_spmr(im) & SPMR_CKID) >> SPMR_CKID_SHIFT; |
||||
return CONFIG_SYS_CLK_FREQ / (1 + clkin_div); |
||||
} |
||||
|
||||
/**
|
||||
* get_csb_clk() - Read the CSB (Coheren System Bus) clock speed |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* |
||||
* Return: The CSB clock speed value as a 32-bit number. |
||||
*/ |
||||
static inline u32 get_csb_clk(immap_t *im) |
||||
{ |
||||
u8 spmf; |
||||
|
||||
spmf = (get_spmr(im) & SPMR_SPMF) >> SPMR_SPMF_SHIFT; |
||||
return CONFIG_SYS_CLK_FREQ * spmf; |
||||
} |
||||
|
||||
/**
|
||||
* spmr_field() - Read a specific SPMR field |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* @mask: A bitmask that describes the bitfield to be read |
||||
* |
||||
* Return: The value of the bit field as a 32-bit number. |
||||
*/ |
||||
static inline uint spmr_field(immap_t *im, u32 mask) |
||||
{ |
||||
/* Extract shift from bitmask */ |
||||
uint shift = mask ? ffs(mask) - 1 : 0; |
||||
|
||||
return (get_spmr(im) & mask) >> shift; |
||||
} |
||||
|
||||
/**
|
||||
* sccr_field() - Read a specific SCCR field |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* @mask: A bitmask that describes the bitfield to be read |
||||
* |
||||
* Return: The value of the bit field as a 32-bit number. |
||||
*/ |
||||
static inline uint sccr_field(immap_t *im, u32 mask) |
||||
{ |
||||
/* Extract shift from bitmask */ |
||||
uint shift = mask ? ffs(mask) - 1 : 0; |
||||
|
||||
return (get_sccr(im) & mask) >> shift; |
||||
} |
||||
|
||||
/**
|
||||
* lcrr_field() - Read a specific LCRR field |
||||
* @im: Pointer to the MPC83xx main register map in question |
||||
* @mask: A bitmask that describes the bitfield to be read |
||||
* |
||||
* Return: The value of the bit field as a 32-bit number. |
||||
*/ |
||||
static inline uint lcrr_field(immap_t *im, u32 mask) |
||||
{ |
||||
/* Extract shift from bitmask */ |
||||
uint shift = mask ? ffs(mask) - 1 : 0; |
||||
|
||||
return (get_lcrr(im) & mask) >> shift; |
||||
} |
@ -0,0 +1,61 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <cpu.h> |
||||
|
||||
int cpu_sandbox_get_desc(struct udevice *dev, char *buf, int size) |
||||
{ |
||||
snprintf(buf, size, "LEG Inc. SuperMegaUltraTurbo CPU No. 1"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cpu_sandbox_get_info(struct udevice *dev, struct cpu_info *info) |
||||
{ |
||||
info->cpu_freq = 42 * 42 * 42 * 42 * 42; |
||||
info->features = 0x42424242; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cpu_sandbox_get_count(struct udevice *dev) |
||||
{ |
||||
return 42; |
||||
} |
||||
|
||||
int cpu_sandbox_get_vendor(struct udevice *dev, char *buf, int size) |
||||
{ |
||||
snprintf(buf, size, "Languid Example Garbage Inc."); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct cpu_ops cpu_sandbox_ops = { |
||||
.get_desc = cpu_sandbox_get_desc, |
||||
.get_info = cpu_sandbox_get_info, |
||||
.get_count = cpu_sandbox_get_count, |
||||
.get_vendor = cpu_sandbox_get_vendor, |
||||
}; |
||||
|
||||
int cpu_sandbox_probe(struct udevice *dev) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
static const struct udevice_id cpu_sandbox_ids[] = { |
||||
{ .compatible = "sandbox,cpu_sandbox" }, |
||||
{ } |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(cpu_sandbox) = { |
||||
.name = "cpu_sandbox", |
||||
.id = UCLASS_CPU, |
||||
.ops = &cpu_sandbox_ops, |
||||
.of_match = cpu_sandbox_ids, |
||||
.probe = cpu_sandbox_probe, |
||||
}; |
@ -0,0 +1,349 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <bitfield.h> |
||||
#include <clk.h> |
||||
#include <cpu.h> |
||||
#include <dm.h> |
||||
|
||||
#include "mpc83xx_cpu.h" |
||||
|
||||
/**
|
||||
* struct mpc83xx_cpu_priv - Private data for MPC83xx CPUs |
||||
* @e300_type: The e300 core type of the MPC83xx CPU |
||||
* @family: The MPC83xx family the CPU belongs to |
||||
* @type: The MPC83xx type of the CPU |
||||
* @is_e_processor: Flag indicating whether the CPU is a E processor or not |
||||
* @is_a_variant: Flag indicating whtther the CPU is a A variant or not |
||||
* @revid: The revision ID of the CPU |
||||
* @revid.major: The major part of the CPU's revision ID |
||||
* @revid.minor: The minor part of the CPU's revision ID |
||||
*/ |
||||
struct mpc83xx_cpu_priv { |
||||
enum e300_type e300_type; |
||||
enum mpc83xx_cpu_family family; |
||||
enum mpc83xx_cpu_type type; |
||||
bool is_e_processor; |
||||
bool is_a_variant; |
||||
struct { |
||||
uint major; |
||||
uint minor; |
||||
} revid; |
||||
}; |
||||
|
||||
int checkcpu(void) |
||||
{ |
||||
/* Activate all CPUs from board_f.c */ |
||||
return cpu_probe_all(); |
||||
} |
||||
|
||||
/**
|
||||
* get_spridr() - Read SPRIDR (System Part and Revision ID Register) of CPU |
||||
* |
||||
* Return: The SPRIDR value |
||||
*/ |
||||
static inline u32 get_spridr(void) |
||||
{ |
||||
immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; |
||||
|
||||
return in_be32(&immr->sysconf.spridr); |
||||
} |
||||
|
||||
/**
|
||||
* determine_type() - Determine CPU family of MPC83xx device |
||||
* @dev: CPU device from which to read CPU family from |
||||
*/ |
||||
static inline void determine_family(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); |
||||
/* Upper 12 bits of PARTID field (bits 0-23 in SPRIDR) */ |
||||
const u32 PARTID_FAMILY_MASK = 0xFFF00000; |
||||
|
||||
switch (bitfield_extract_by_mask(get_spridr(), PARTID_FAMILY_MASK)) { |
||||
case 0x810: |
||||
case 0x811: |
||||
priv->family = FAMILY_830X; |
||||
break; |
||||
case 0x80B: |
||||
priv->family = FAMILY_831X; |
||||
break; |
||||
case 0x806: |
||||
priv->family = FAMILY_832X; |
||||
break; |
||||
case 0x803: |
||||
priv->family = FAMILY_834X; |
||||
break; |
||||
case 0x804: |
||||
priv->family = FAMILY_836X; |
||||
break; |
||||
case 0x80C: |
||||
priv->family = FAMILY_837X; |
||||
break; |
||||
default: |
||||
priv->family = FAMILY_UNKNOWN; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* determine_type() - Determine CPU type of MPC83xx device |
||||
* @dev: CPU device from which to read CPU type from |
||||
*/ |
||||
static inline void determine_type(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); |
||||
/* Upper 16 bits of PVR (Processor Version Register) */ |
||||
const u32 PCR_UPPER_MASK = 0xFFFF0000; |
||||
u32 val; |
||||
|
||||
val = bitfield_extract_by_mask(get_spridr(), PCR_UPPER_MASK); |
||||
|
||||
/* Mask out E-variant bit */ |
||||
switch (val & 0xFFFE) { |
||||
case 0x8100: |
||||
priv->type = TYPE_8308; |
||||
break; |
||||
case 0x8110: |
||||
priv->type = TYPE_8309; |
||||
break; |
||||
case 0x80B2: |
||||
priv->type = TYPE_8311; |
||||
break; |
||||
case 0x80B0: |
||||
priv->type = TYPE_8313; |
||||
break; |
||||
case 0x80B6: |
||||
priv->type = TYPE_8314; |
||||
break; |
||||
case 0x80B4: |
||||
priv->type = TYPE_8315; |
||||
break; |
||||
case 0x8066: |
||||
priv->type = TYPE_8321; |
||||
break; |
||||
case 0x8062: |
||||
priv->type = TYPE_8323; |
||||
break; |
||||
case 0x8036: |
||||
priv->type = TYPE_8343; |
||||
break; |
||||
case 0x8032: |
||||
priv->type = TYPE_8347_TBGA; |
||||
break; |
||||
case 0x8034: |
||||
priv->type = TYPE_8347_PBGA; |
||||
break; |
||||
case 0x8030: |
||||
priv->type = TYPE_8349; |
||||
break; |
||||
case 0x804A: |
||||
priv->type = TYPE_8358_TBGA; |
||||
break; |
||||
case 0x804E: |
||||
priv->type = TYPE_8358_PBGA; |
||||
break; |
||||
case 0x8048: |
||||
priv->type = TYPE_8360; |
||||
break; |
||||
case 0x80C6: |
||||
priv->type = TYPE_8377; |
||||
break; |
||||
case 0x80C4: |
||||
priv->type = TYPE_8378; |
||||
break; |
||||
case 0x80C2: |
||||
priv->type = TYPE_8379; |
||||
break; |
||||
default: |
||||
priv->type = TYPE_UNKNOWN; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* determine_e300_type() - Determine e300 core type of MPC83xx device |
||||
* @dev: CPU device from which to read e300 core type from |
||||
*/ |
||||
static inline void determine_e300_type(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); |
||||
/* Upper 16 bits of PVR (Processor Version Register) */ |
||||
const u32 PCR_UPPER_MASK = 0xFFFF0000; |
||||
u32 pvr = get_pvr(); |
||||
|
||||
switch ((pvr & PCR_UPPER_MASK) >> 16) { |
||||
case 0x8083: |
||||
priv->e300_type = E300C1; |
||||
break; |
||||
case 0x8084: |
||||
priv->e300_type = E300C2; |
||||
break; |
||||
case 0x8085: |
||||
priv->e300_type = E300C3; |
||||
break; |
||||
case 0x8086: |
||||
priv->e300_type = E300C4; |
||||
break; |
||||
default: |
||||
priv->e300_type = E300_UNKNOWN; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* determine_revid() - Determine revision ID of CPU device |
||||
* @dev: CPU device from which to read revision ID |
||||
*/ |
||||
static inline void determine_revid(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); |
||||
u32 REVID_MAJOR_MASK; |
||||
u32 REVID_MINOR_MASK; |
||||
u32 spridr = get_spridr(); |
||||
|
||||
if (priv->family == FAMILY_834X) { |
||||
REVID_MAJOR_MASK = 0x0000FF00; |
||||
REVID_MINOR_MASK = 0x000000FF; |
||||
} else { |
||||
REVID_MAJOR_MASK = 0x000000F0; |
||||
REVID_MINOR_MASK = 0x0000000F; |
||||
} |
||||
|
||||
priv->revid.major = bitfield_extract_by_mask(spridr, REVID_MAJOR_MASK); |
||||
priv->revid.minor = bitfield_extract_by_mask(spridr, REVID_MINOR_MASK); |
||||
} |
||||
|
||||
/**
|
||||
* determine_cpu_data() - Determine CPU information from hardware |
||||
* @dev: CPU device from which to read information |
||||
*/ |
||||
static void determine_cpu_data(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); |
||||
const u32 E_FLAG_MASK = 0x00010000; |
||||
u32 spridr = get_spridr(); |
||||
|
||||
determine_family(dev); |
||||
determine_type(dev); |
||||
determine_e300_type(dev); |
||||
determine_revid(dev); |
||||
|
||||
if ((priv->family == FAMILY_834X || |
||||
priv->family == FAMILY_836X) && priv->revid.major >= 2) |
||||
priv->is_a_variant = true; |
||||
|
||||
priv->is_e_processor = !bitfield_extract_by_mask(spridr, E_FLAG_MASK); |
||||
} |
||||
|
||||
static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size) |
||||
{ |
||||
struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); |
||||
struct clk core_clk; |
||||
struct clk csb_clk; |
||||
char core_freq[32]; |
||||
char csb_freq[32]; |
||||
int ret; |
||||
|
||||
ret = clk_get_by_index(dev, 0, &core_clk); |
||||
if (ret) { |
||||
debug("%s: Failed to get core clock (err = %d)\n", |
||||
dev->name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
ret = clk_get_by_index(dev, 1, &csb_clk); |
||||
if (ret) { |
||||
debug("%s: Failed to get CSB clock (err = %d)\n", |
||||
dev->name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
determine_cpu_data(dev); |
||||
|
||||
snprintf(buf, size, |
||||
"CPU: %s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz\n", |
||||
e300_names[priv->e300_type], |
||||
cpu_type_names[priv->type], |
||||
priv->is_e_processor ? "E" : "", |
||||
priv->is_a_variant ? "A" : "", |
||||
priv->revid.major, |
||||
priv->revid.minor, |
||||
strmhz(core_freq, clk_get_rate(&core_clk)), |
||||
strmhz(csb_freq, clk_get_rate(&csb_clk))); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mpc83xx_cpu_get_info(struct udevice *dev, struct cpu_info *info) |
||||
{ |
||||
struct clk clock; |
||||
int ret; |
||||
ulong freq; |
||||
|
||||
ret = clk_get_by_index(dev, 0, &clock); |
||||
if (ret) { |
||||
debug("%s: Failed to get core clock (err = %d)\n", |
||||
dev->name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
freq = clk_get_rate(&clock); |
||||
if (!freq) { |
||||
debug("%s: Core clock speed is zero\n", dev->name); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
info->cpu_freq = freq; |
||||
info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mpc83xx_cpu_get_count(struct udevice *dev) |
||||
{ |
||||
/* We have one e300cX core */ |
||||
return 1; |
||||
} |
||||
|
||||
static int mpc83xx_cpu_get_vendor(struct udevice *dev, char *buf, int size) |
||||
{ |
||||
snprintf(buf, size, "NXP"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct cpu_ops mpc83xx_cpu_ops = { |
||||
.get_desc = mpc83xx_cpu_get_desc, |
||||
.get_info = mpc83xx_cpu_get_info, |
||||
.get_count = mpc83xx_cpu_get_count, |
||||
.get_vendor = mpc83xx_cpu_get_vendor, |
||||
}; |
||||
|
||||
static int mpc83xx_cpu_probe(struct udevice *dev) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
static const struct udevice_id mpc83xx_cpu_ids[] = { |
||||
{ .compatible = "fsl,mpc83xx", }, |
||||
{ .compatible = "fsl,mpc8308", }, |
||||
{ .compatible = "fsl,mpc8309", }, |
||||
{ .compatible = "fsl,mpc8313", }, |
||||
{ .compatible = "fsl,mpc8315", }, |
||||
{ .compatible = "fsl,mpc832x", }, |
||||
{ .compatible = "fsl,mpc8349", }, |
||||
{ .compatible = "fsl,mpc8360", }, |
||||
{ .compatible = "fsl,mpc8379", }, |
||||
{ /* sentinel */ } |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(mpc83xx_cpu) = { |
||||
.name = "mpc83xx_cpu", |
||||
.id = UCLASS_CPU, |
||||
.of_match = mpc83xx_cpu_ids, |
||||
.probe = mpc83xx_cpu_probe, |
||||
.priv_auto_alloc_size = sizeof(struct mpc83xx_cpu_priv), |
||||
.ops = &mpc83xx_cpu_ops, |
||||
.flags = DM_FLAG_PRE_RELOC, |
||||
}; |
@ -0,0 +1,126 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#ifndef _MPC83XX_CPU_H_ |
||||
#define _MPC83XX_CPU_H_ |
||||
|
||||
/**
|
||||
* enum e300_type - Identifiers for e300 cores |
||||
* @E300C1: Identifier for e300c1 cores |
||||
* @E300C2: Identifier for e300c2 cores |
||||
* @E300C3: Identifier for e300c3 cores |
||||
* @E300C4: Identifier for e300c4 cores |
||||
* @E300_UNKNOWN: Identifier for unknown e300 cores |
||||
*/ |
||||
enum e300_type { |
||||
E300C1, |
||||
E300C2, |
||||
E300C3, |
||||
E300C4, |
||||
E300_UNKNOWN, |
||||
}; |
||||
|
||||
/* Array mapping the e300 core types to their human-readable names */ |
||||
static const char * const e300_names[] = { |
||||
[E300C1] = "e300c1", |
||||
[E300C2] = "e300c2", |
||||
[E300C3] = "e300c3", |
||||
[E300C4] = "e300c4", |
||||
[E300_UNKNOWN] = "Unknown e300", |
||||
}; |
||||
|
||||
/**
|
||||
* enum mpc83xx_cpu_family - Identifiers for MPC83xx CPU families |
||||
* @FAMILY_830X: Identifier for the MPC830x CPU family |
||||
* @FAMILY_831X: Identifier for the MPC831x CPU family |
||||
* @FAMILY_832X: Identifier for the MPC832x CPU family |
||||
* @FAMILY_834X: Identifier for the MPC834x CPU family |
||||
* @FAMILY_836X: Identifier for the MPC836x CPU family |
||||
* @FAMILY_837X: Identifier for the MPC837x CPU family |
||||
* @FAMILY_UNKNOWN: Identifier for an unknown MPC83xx CPU family |
||||
*/ |
||||
enum mpc83xx_cpu_family { |
||||
FAMILY_830X, |
||||
FAMILY_831X, |
||||
FAMILY_832X, |
||||
FAMILY_834X, |
||||
FAMILY_836X, |
||||
FAMILY_837X, |
||||
FAMILY_UNKNOWN, |
||||
}; |
||||
|
||||
/**
|
||||
* enum mpc83xx_cpu_type - Identifiers for MPC83xx CPU types |
||||
* @TYPE_8308: Identifier for the MPC8308 CPU type |
||||
* @TYPE_8309: Identifier for the MPC8309 CPU type |
||||
* @TYPE_8311: Identifier for the MPC8311 CPU type |
||||
* @TYPE_8313: Identifier for the MPC8313 CPU type |
||||
* @TYPE_8314: Identifier for the MPC8314 CPU type |
||||
* @TYPE_8315: Identifier for the MPC8315 CPU type |
||||
* @TYPE_8321: Identifier for the MPC8321 CPU type |
||||
* @TYPE_8323: Identifier for the MPC8323 CPU type |
||||
* @TYPE_8343: Identifier for the MPC8343 CPU type |
||||
* @TYPE_8347_TBGA: Identifier for the MPC8347 CPU type (Tape Ball Grid Array |
||||
* version) |
||||
* @TYPE_8347_PBGA: Identifier for the MPC8347 CPU type (Plastic Ball Grid Array |
||||
* version) |
||||
* @TYPE_8349: Identifier for the MPC8349 CPU type |
||||
* @TYPE_8358_TBGA: Identifier for the MPC8358 CPU type (Tape Ball Grid Array |
||||
* version) |
||||
* @TYPE_8358_PBGA: Identifier for the MPC8358 CPU type (Plastic Ball Grid Array |
||||
* version) |
||||
* @TYPE_8360: Identifier for the MPC8360 CPU type |
||||
* @TYPE_8377: Identifier for the MPC8377 CPU type |
||||
* @TYPE_8378: Identifier for the MPC8378 CPU type |
||||
* @TYPE_8379: Identifier for the MPC8379 CPU type |
||||
* @TYPE_UNKNOWN: Identifier for an unknown MPC83xx CPU type |
||||
*/ |
||||
enum mpc83xx_cpu_type { |
||||
TYPE_8308, |
||||
TYPE_8309, |
||||
TYPE_8311, |
||||
TYPE_8313, |
||||
TYPE_8314, |
||||
TYPE_8315, |
||||
TYPE_8321, |
||||
TYPE_8323, |
||||
TYPE_8343, |
||||
TYPE_8347_TBGA, |
||||
TYPE_8347_PBGA, |
||||
TYPE_8349, |
||||
TYPE_8358_TBGA, |
||||
TYPE_8358_PBGA, |
||||
TYPE_8360, |
||||
TYPE_8377, |
||||
TYPE_8378, |
||||
TYPE_8379, |
||||
TYPE_UNKNOWN, |
||||
}; |
||||
|
||||
/* Array mapping the MCP83xx CPUs to their human-readable names */ |
||||
static const char * const cpu_type_names[] = { |
||||
[TYPE_8308] = "8308", |
||||
[TYPE_8309] = "8309", |
||||
[TYPE_8311] = "8311", |
||||
[TYPE_8313] = "8313", |
||||
[TYPE_8314] = "8314", |
||||
[TYPE_8315] = "8315", |
||||
[TYPE_8321] = "8321", |
||||
[TYPE_8323] = "8323", |
||||
[TYPE_8343] = "8343", |
||||
[TYPE_8347_TBGA] = "8347_TBGA", |
||||
[TYPE_8347_PBGA] = "8347_PBGA", |
||||
[TYPE_8349] = "8349", |
||||
[TYPE_8358_TBGA] = "8358_TBGA", |
||||
[TYPE_8358_PBGA] = "8358_PBGA", |
||||
[TYPE_8360] = "8360", |
||||
[TYPE_8377] = "8377", |
||||
[TYPE_8378] = "8378", |
||||
[TYPE_8379] = "8379", |
||||
[TYPE_UNKNOWN] = "Unknown CPU", |
||||
}; |
||||
|
||||
#endif /* !_MPC83XX_CPU_H_ */ |
@ -0,0 +1,185 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
* |
||||
* base on the MPC83xx serdes initialization, which is |
||||
* |
||||
* Copyright 2007,2011 Freescale Semiconductor, Inc. |
||||
* Copyright (C) 2008 MontaVista Software, Inc. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <mapmem.h> |
||||
#include <misc.h> |
||||
|
||||
#include "mpc83xx_serdes.h" |
||||
|
||||
/**
|
||||
* struct mpc83xx_serdes_priv - Private structure for MPC83xx serdes |
||||
* @regs: The device's register map |
||||
* @rfcks: Variable to keep the serdes reference clock selection set during |
||||
* initialization in (is or'd to every value written to SRDSCR4) |
||||
*/ |
||||
struct mpc83xx_serdes_priv { |
||||
struct mpc83xx_serdes_regs *regs; |
||||
u32 rfcks; |
||||
}; |
||||
|
||||
/**
|
||||
* setup_sata() - Configure the SerDes device to SATA mode |
||||
* @dev: The device to configure |
||||
*/ |
||||
static void setup_sata(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); |
||||
|
||||
/* Set and clear reset bits */ |
||||
setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET); |
||||
udelay(1000); |
||||
clrbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET); |
||||
|
||||
/* Configure SRDSCR0 */ |
||||
clrsetbits_be32(&priv->regs->srdscr0, |
||||
SRDSCR0_TXEQA_MASK | SRDSCR0_TXEQE_MASK, |
||||
SRDSCR0_TXEQA_SATA | SRDSCR0_TXEQE_SATA); |
||||
|
||||
/* Configure SRDSCR1 */ |
||||
clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW); |
||||
|
||||
/* Configure SRDSCR2 */ |
||||
clrsetbits_be32(&priv->regs->srdscr2, |
||||
SRDSCR2_SEIC_MASK, |
||||
SRDSCR2_SEIC_SATA); |
||||
|
||||
/* Configure SRDSCR3 */ |
||||
out_be32(&priv->regs->srdscr3, |
||||
SRDSCR3_KFR_SATA | SRDSCR3_KPH_SATA | |
||||
SRDSCR3_SDFM_SATA_PEX | SRDSCR3_SDTXL_SATA); |
||||
|
||||
/* Configure SRDSCR4 */ |
||||
out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SATA); |
||||
} |
||||
|
||||
/**
|
||||
* setup_pex() - Configure the SerDes device to PCI Express mode |
||||
* @dev: The device to configure |
||||
* @type: The PCI Express type to configure for (x1 or x2) |
||||
*/ |
||||
static void setup_pex(struct udevice *dev, enum pex_type type) |
||||
{ |
||||
struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); |
||||
|
||||
/* Configure SRDSCR1 */ |
||||
setbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW); |
||||
|
||||
/* Configure SRDSCR2 */ |
||||
clrsetbits_be32(&priv->regs->srdscr2, |
||||
SRDSCR2_SEIC_MASK, |
||||
SRDSCR2_SEIC_PEX); |
||||
|
||||
/* Configure SRDSCR3 */ |
||||
out_be32(&priv->regs->srdscr3, SRDSCR3_SDFM_SATA_PEX); |
||||
|
||||
/* Configure SRDSCR4 */ |
||||
if (type == PEX_X2) |
||||
out_be32(&priv->regs->srdscr4, |
||||
priv->rfcks | SRDSCR4_PROT_PEX | SRDSCR4_PLANE_X2); |
||||
else |
||||
out_be32(&priv->regs->srdscr4, |
||||
priv->rfcks | SRDSCR4_PROT_PEX); |
||||
} |
||||
|
||||
/**
|
||||
* setup_sgmii() - Configure the SerDes device to SGMII mode |
||||
* @dev: The device to configure |
||||
*/ |
||||
static void setup_sgmii(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); |
||||
|
||||
/* Configure SRDSCR1 */ |
||||
clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW); |
||||
|
||||
/* Configure SRDSCR2 */ |
||||
clrsetbits_be32(&priv->regs->srdscr2, |
||||
SRDSCR2_SEIC_MASK, |
||||
SRDSCR2_SEIC_SGMII); |
||||
|
||||
/* Configure SRDSCR3 */ |
||||
out_be32(&priv->regs->srdscr3, 0); |
||||
|
||||
/* Configure SRDSCR4 */ |
||||
out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SGMII); |
||||
} |
||||
|
||||
static int mpc83xx_serdes_probe(struct udevice *dev) |
||||
{ |
||||
struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); |
||||
bool vdd; |
||||
const char *proto; |
||||
|
||||
priv->regs = map_sysmem(dev_read_addr(dev), |
||||
sizeof(struct mpc83xx_serdes_regs)); |
||||
|
||||
switch (dev_read_u32_default(dev, "serdes-clk", -1)) { |
||||
case 100: |
||||
priv->rfcks = SRDSCR4_RFCKS_100; |
||||
break; |
||||
case 125: |
||||
priv->rfcks = SRDSCR4_RFCKS_125; |
||||
break; |
||||
case 150: |
||||
priv->rfcks = SRDSCR4_RFCKS_150; |
||||
break; |
||||
default: |
||||
debug("%s: Could not read serdes clock value\n", dev->name); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
vdd = dev_read_bool(dev, "vdd"); |
||||
|
||||
/* 1.0V corevdd */ |
||||
if (vdd) { |
||||
/* DPPE/DPPA = 0 */ |
||||
clrbits_be32(&priv->regs->srdscr0, SRDSCR0_DPP_1V2); |
||||
|
||||
/* VDD = 0 */ |
||||
clrbits_be32(&priv->regs->srdscr0, SRDSCR2_VDD_1V2); |
||||
} |
||||
|
||||
proto = dev_read_string(dev, "proto"); |
||||
|
||||
/* protocol specific configuration */ |
||||
if (!strcmp(proto, "sata")) { |
||||
setup_sata(dev); |
||||
} else if (!strcmp(proto, "pex")) { |
||||
setup_pex(dev, PEX_X1); |
||||
} else if (!strcmp(proto, "pex-x2")) { |
||||
setup_pex(dev, PEX_X2); |
||||
} else if (!strcmp(proto, "sgmii")) { |
||||
setup_sgmii(dev); |
||||
} else { |
||||
debug("%s: Invalid protocol value %s\n", dev->name, proto); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
/* Do a software reset */ |
||||
setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_RST); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct udevice_id mpc83xx_serdes_ids[] = { |
||||
{ .compatible = "fsl,mpc83xx-serdes" }, |
||||
{ } |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(mpc83xx_serdes) = { |
||||
.name = "mpc83xx_serdes", |
||||
.id = UCLASS_MISC, |
||||
.of_match = mpc83xx_serdes_ids, |
||||
.probe = mpc83xx_serdes_probe, |
||||
.priv_auto_alloc_size = sizeof(struct mpc83xx_serdes_priv), |
||||
}; |
@ -0,0 +1,232 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
/**
|
||||
* enum srdscr0_mask - Bit masks for SRDSCR0 (SerDes Control Register 0) |
||||
* @SRDSCR0_DPPA: Bitmask for the DPPA (diff pk-pk swing for lane A) |
||||
* field of the SRCSCR0 |
||||
* @SRDSCR0_DPPE: Bitmask for the DPPE (diff pk-pk swing for lane E) |
||||
* field of the SRCSCR0 |
||||
* @SRDSCR0_DPP_1V2: Combined bitmask to set diff pk-pk swing for both lanes |
||||
* @SRDSCR0_TXEQA_MASK: Bitmask for the TXEQA (transmit equalization for |
||||
* lane A) field of the SRCSCR0 |
||||
* @SRDSCR0_TXEQA_SATA: Bitmask to set the TXEQA to the value used for SATA |
||||
* @SRDSCR0_TXEQE_MASK: Bitmask for the TXEQE (transmit equalization for |
||||
* lane E) field of the SRCSCR0 |
||||
* @SRDSCR0_TXEQE_SATA: Bitmask to set the TXEQE to the value used for SATA |
||||
*/ |
||||
enum srdscr0_mask { |
||||
SRDSCR0_DPPA = BIT(31 - 16), |
||||
SRDSCR0_DPPE = BIT(31 - 20), |
||||
SRDSCR0_DPP_1V2 = SRDSCR0_DPPE | SRDSCR0_DPPA, |
||||
|
||||
SRDSCR0_TXEQA_MASK = 0x00007000, |
||||
SRDSCR0_TXEQA_SATA = 0x00001000, |
||||
SRDSCR0_TXEQE_MASK = 0x00000700, |
||||
SRDSCR0_TXEQE_SATA = 0x00000100, |
||||
}; |
||||
|
||||
/**
|
||||
* enum srdscr1_mask - Bit masks for SRDSCR1 (SerDes Control Register 1) |
||||
* @SRDSCR1_PLLBW: Bitmask for the PLLBW (PLL bandwidth) field of SRDSCR1 |
||||
*/ |
||||
enum srdscr1_mask { |
||||
SRDSCR1_PLLBW = BIT(31 - 25), |
||||
}; |
||||
|
||||
/**
|
||||
* enum srdscr2_mask - Bit masks for SRDSCR2 (SerDes Control Register 2) |
||||
* @SRDSCR2_VDD_1V2: Bit mask to to set the VDD field of the SCRSCR2 |
||||
* @SRDSCR2_SEICA_MASK: Bitmask for the SEICA (Receiver electrical idle |
||||
* detection control for lane A) field of the SRCSCR2 |
||||
* @SRDSCR2_SEICE_MASK: Bitmask for the SEICE (Receiver electrical idle |
||||
* detection control for lane E) field of the SRCSCR2 |
||||
* @SRDSCR2_SEIC_MASK: Combined bitmask to set the receiver electrical idle |
||||
* detection control for both lanes |
||||
* @SRDSCR2_SEICA_SATA: Bitmask to set the SEICA field to the value used for |
||||
* SATA |
||||
* @SRDSCR2_SEICE_SATA: Bitmask to set the SEICE field to the value used for |
||||
* SATA |
||||
* @SRDSCR2_SEIC_SATA: Combined bitmask to set the value of both SEIC fields |
||||
* to the value used for SATA |
||||
* @SRDSCR2_SEICA_PEX: Bitmask to set the SEICA field to the value used for |
||||
* PCI Express |
||||
* @SRDSCR2_SEICE_PEX: Bitmask to set the SEICE field to the value used for |
||||
* PCI Express |
||||
* @SRDSCR2_SEIC_PEX: Combined bitmask to set the value of both SEIC fields |
||||
* to the value used for PCI Express |
||||
* @SRDSCR2_SEICA_SGMII: Bitmask to set the SEICA field to the value used for |
||||
* SGMII |
||||
* @SRDSCR2_SEICE_SGMII: Bitmask to set the SEICE field to the value used for |
||||
* SGMII |
||||
* @SRDSCR2_SEIC_SGMII: Combined bitmask to set the value of both SEIC fields |
||||
* to the value used for SGMII |
||||
*/ |
||||
enum srdscr2_mask { |
||||
SRDSCR2_VDD_1V2 = 0x00800000, |
||||
|
||||
SRDSCR2_SEICA_MASK = 0x00001c00, |
||||
SRDSCR2_SEICE_MASK = 0x0000001c, |
||||
SRDSCR2_SEIC_MASK = SRDSCR2_SEICA_MASK | SRDSCR2_SEICE_MASK, |
||||
|
||||
SRDSCR2_SEICA_SATA = 0x00001400, |
||||
SRDSCR2_SEICE_SATA = 0x00000014, |
||||
SRDSCR2_SEIC_SATA = SRDSCR2_SEICA_SATA | SRDSCR2_SEICE_SATA, |
||||
|
||||
SRDSCR2_SEICA_PEX = 0x00001000, |
||||
SRDSCR2_SEICE_PEX = 0x00000010, |
||||
SRDSCR2_SEIC_PEX = SRDSCR2_SEICA_PEX | SRDSCR2_SEICE_PEX, |
||||
|
||||
SRDSCR2_SEICA_SGMII = 0x00000100, |
||||
SRDSCR2_SEICE_SGMII = 0x00000001, |
||||
SRDSCR2_SEIC_SGMII = SRDSCR2_SEICA_SGMII | SRDSCR2_SEICE_SGMII, |
||||
}; |
||||
|
||||
/**
|
||||
* enum srdscr3_mask - Bit masks for SRDSCR3 (SerDes Control Register 3) |
||||
* @SRDSCR3_KFRA_SATA: Bitmask to set the KFRA field of SRDSCR3 to the |
||||
* value used by SATA |
||||
* @SRDSCR3_KFRE_SATA: Bitmask to set the KFRE field of SRDSCR3 to the |
||||
* value used by SATA |
||||
* @SRDSCR3_KFR_SATA: Combined bitmask to set both KFR fields to the |
||||
* value used by SATA |
||||
* @SRDSCR3_KPHA_SATA: Bitmask to set the KPHA field of SRDSCR3 to the |
||||
* value used by SATA |
||||
* @SRDSCR3_KPHE_SATA: Bitmask to set the KPHE field of SRDSCR3 to the |
||||
* value used by SATA |
||||
* @SRDSCR3_KPH_SATA: Combined bitmask to set both KPH fields to the |
||||
* value used by SATA |
||||
* @SRDSCR3_SDFMA_SATA_PEX: Bitmask to set the SDFMA field of SRDSCR3 to the |
||||
* value used by SATA and PCI Express |
||||
* @SRDSCR3_SDFME_SATA_PEX: Bitmask to set the SDFME field of SRDSCR3 to the |
||||
* value used by SATA and PCI Express |
||||
* @SRDSCR3_SDFM_SATA_PEX: Combined bitmask to set both SDFM fields to the |
||||
* value used by SATA and PCI Express |
||||
* @SRDSCR3_SDTXLA_SATA: Bitmask to set the SDTXLA field of SRDSCR3 to the |
||||
* value used by SATA |
||||
* @SRDSCR3_SDTXLE_SATA: Bitmask to set the SDTXLE field of SRDSCR3 to the |
||||
* value used by SATA |
||||
* @SRDSCR3_SDTXL_SATA: Combined bitmask to set both SDTXL fields to the |
||||
* value used by SATA |
||||
* |
||||
* KFRA = 'Kfr' gain selection in the CDR for lane A |
||||
* KFRE = 'Kfr' gain selection in the CDR for lane E |
||||
* SDFMA = Bandwidth of digital filter for lane A |
||||
* SDFME = Bandwidth of digital filter for lane E |
||||
* SDTXLA = Lane A transmitter amplitude levels |
||||
* SDTXLE = Lane E transmitter amplitude levels |
||||
*/ |
||||
enum srdscr3_mask { |
||||
SRDSCR3_KFRA_SATA = 0x10000000, |
||||
SRDSCR3_KFRE_SATA = 0x00100000, |
||||
SRDSCR3_KFR_SATA = SRDSCR3_KFRA_SATA | SRDSCR3_KFRE_SATA, |
||||
|
||||
SRDSCR3_KPHA_SATA = 0x04000000, |
||||
SRDSCR3_KPHE_SATA = 0x00040000, |
||||
SRDSCR3_KPH_SATA = SRDSCR3_KPHA_SATA | SRDSCR3_KPHE_SATA, |
||||
|
||||
SRDSCR3_SDFMA_SATA_PEX = 0x01000000, |
||||
SRDSCR3_SDFME_SATA_PEX = 0x00010000, |
||||
SRDSCR3_SDFM_SATA_PEX = SRDSCR3_SDFMA_SATA_PEX | SRDSCR3_SDFME_SATA_PEX, |
||||
|
||||
SRDSCR3_SDTXLA_SATA = 0x00000500, |
||||
SRDSCR3_SDTXLE_SATA = 0x00000005, |
||||
SRDSCR3_SDTXL_SATA = SRDSCR3_SDTXLA_SATA | SRDSCR3_SDTXLE_SATA, |
||||
}; |
||||
|
||||
/**
|
||||
* enum srdscr4_mask - Bit masks for SRDSCR4 (SerDes Control Register 4) |
||||
* @SRDSCR4_PROTA_SATA: Bitmask to set the PROTA field of SRDSCR4 to the |
||||
* value used by SATA |
||||
* @SRDSCR4_PROTE_SATA: Bitmask to set the PROTE field of SRDSCR4 to the |
||||
* value used by SATA |
||||
* @SRDSCR4_PROT_SATA: Combined bitmask to set both PROT fields to the |
||||
* value used by SATA |
||||
* @SRDSCR4_PROTA_PEX: Bitmask to set the PROTA field of SRDSCR4 to the |
||||
* value used by PCI Express |
||||
* @SRDSCR4_PROTE_PEX: Bitmask to set the PROTE field of SRDSCR4 to the |
||||
* value used by PCI Express |
||||
* @SRDSCR4_PROT_PEX: Combined bitmask to set both PROT fields to the |
||||
* value used by PCI Express |
||||
* @SRDSCR4_PROTA_SGMII: Bitmask to set the PROTA field of SRDSCR4 to the |
||||
* value used by SGMII |
||||
* @SRDSCR4_PROTE_SGMII: Bitmask to set the PROTE field of SRDSCR4 to the |
||||
* value used by SGMII |
||||
* @SRDSCR4_PROT_SGMII: Combined bitmask to set both PROT fields to the |
||||
* value used by SGMII |
||||
* @SRDSCR4_PLANE_X2: Bitmask to set the PLANE field of SRDSCR4 |
||||
* @SRDSCR4_RFCKS_100: Bitmask to set the RFCKS field of SRDSCR4 to the |
||||
* value 100Mhz |
||||
* @SRDSCR4_RFCKS_125: Bitmask to set the RFCKS field of SRDSCR4 to the |
||||
* value 125Mhz |
||||
* @SRDSCR4_RFCKS_150: Bitmask to set the RFCKS field of SRDSCR4 to the |
||||
* value 150Mhz |
||||
* |
||||
* PROTA = Lane A protocol select |
||||
* PROTE = Lane E protocol select |
||||
* PLAME = Number of PCI Express lanes |
||||
*/ |
||||
enum srdscr4_mask { |
||||
SRDSCR4_PROTA_SATA = 0x00000800, |
||||
SRDSCR4_PROTE_SATA = 0x00000008, |
||||
SRDSCR4_PROT_SATA = SRDSCR4_PROTA_SATA | SRDSCR4_PROTE_SATA, |
||||
|
||||
SRDSCR4_PROTA_PEX = 0x00000100, |
||||
SRDSCR4_PROTE_PEX = 0x00000001, |
||||
SRDSCR4_PROT_PEX = SRDSCR4_PROTA_PEX | SRDSCR4_PROTE_PEX, |
||||
|
||||
SRDSCR4_PROTA_SGMII = 0x00000500, |
||||
SRDSCR4_PROTE_SGMII = 0x00000005, |
||||
SRDSCR4_PROT_SGMII = SRDSCR4_PROTA_SGMII | SRDSCR4_PROTE_SGMII, |
||||
|
||||
SRDSCR4_PLANE_X2 = 0x01000000, |
||||
|
||||
SRDSCR4_RFCKS_100 = (0 << 28), |
||||
SRDSCR4_RFCKS_125 = (1 << 28), |
||||
SRDSCR4_RFCKS_150 = (3 << 28), |
||||
}; |
||||
|
||||
/**
|
||||
* enum srdsrstctl_mask - Bit masks for SRDSRSTCTL (SerDes Reset Control Register) |
||||
* @SRDSRSTCTL_RST: Bitmask for the RST (Software reset) field of the |
||||
* SRDSRSTCTL |
||||
* @SRDSRSTCTL_SATA_RESET: Bitmask for the SATA_RESET (SATA reset) field of the |
||||
* SRDSRSTCTL |
||||
*/ |
||||
enum srdsrstctl_mask { |
||||
SRDSRSTCTL_RST = 0x80000000, |
||||
SRDSRSTCTL_SATA_RESET = 0xf, |
||||
}; |
||||
|
||||
/**
|
||||
* struct mpc83xx_serdes_regs - Register map of the SerDes controller |
||||
* @srdscr0: SerDes Control Register 0 |
||||
* @srdscr1: SerDes Control Register 1 |
||||
* @srdscr2: SerDes Control Register 2 |
||||
* @srdscr3: SerDes Control Register 3 |
||||
* @srdscr4: SerDes Control Register 4 |
||||
* @fill0: Reserved space in the register map |
||||
* @srdsrstctl: SerDes Reset Control Register |
||||
*/ |
||||
struct mpc83xx_serdes_regs { |
||||
u32 srdscr0; |
||||
u32 srdscr1; |
||||
u32 srdscr2; |
||||
u32 srdscr3; |
||||
u32 srdscr4; |
||||
u8 fill0[12]; |
||||
u32 srdsrstctl; |
||||
}; |
||||
|
||||
/**
|
||||
* enum pex_type - Types of PCI Express |
||||
* @PEX_X1: PCI Express in x1 mode |
||||
* @PEX_X2: PCI Express in x2 mode |
||||
*/ |
||||
enum pex_type { |
||||
PEX_X1, |
||||
PEX_X2, |
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,212 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <sysreset.h> |
||||
#include <wait_bit.h> |
||||
|
||||
#include "sysreset_mpc83xx.h" |
||||
|
||||
/* Magic 4-byte word to enable reset ('RSTE' in ASCII) */ |
||||
static const u32 RPR_MAGIC = 0x52535445; |
||||
/* Wait at most 2000ms for reset control enable bit */ |
||||
static const uint RESET_WAIT_TIMEOUT = 2000; |
||||
|
||||
/**
|
||||
* __do_reset() - Execute the system reset |
||||
* |
||||
* Return: The functions resets the system, and never returns. |
||||
*/ |
||||
static int __do_reset(void) |
||||
{ |
||||
ulong msr; |
||||
int res; |
||||
|
||||
immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
||||
|
||||
puts("Resetting the board.\n"); |
||||
|
||||
/* Interrupts and MMU off */ |
||||
msr = mfmsr(); |
||||
msr &= ~(MSR_EE | MSR_IR | MSR_DR); |
||||
mtmsr(msr); |
||||
|
||||
/* Enable Reset Control Reg */ |
||||
out_be32(&immap->reset.rpr, RPR_MAGIC); |
||||
sync(); |
||||
isync(); |
||||
|
||||
/* Confirm Reset Control Reg is enabled */ |
||||
res = wait_for_bit_be32(&immap->reset.rcer, RCER_CRE, true, |
||||
RESET_WAIT_TIMEOUT, false); |
||||
if (res) { |
||||
debug("%s: Timed out waiting for reset control to be set\n", |
||||
__func__); |
||||
return res; |
||||
} |
||||
|
||||
udelay(200); |
||||
|
||||
/* Perform reset, only one bit */ |
||||
out_be32(&immap->reset.rcr, RCR_SWHR); |
||||
|
||||
/* Never executes */ |
||||
return 0; |
||||
} |
||||
|
||||
static int mpc83xx_sysreset_request(struct udevice *dev, enum sysreset_t type) |
||||
{ |
||||
switch (type) { |
||||
case SYSRESET_WARM: |
||||
case SYSRESET_COLD: |
||||
return __do_reset(); |
||||
default: |
||||
return -EPROTONOSUPPORT; |
||||
} |
||||
|
||||
return -EINPROGRESS; |
||||
} |
||||
|
||||
/**
|
||||
* print_83xx_arb_event() - Print arbiter events to buffer |
||||
* @force: Print arbiter events, even if none are indicated by the system |
||||
* @buf: The buffer to receive the printed arbiter event information |
||||
* @size: The size of the buffer to receive the printed arbiter event |
||||
* information in bytes |
||||
* |
||||
* Return: Number of bytes printed to buffer, -ve on error |
||||
*/ |
||||
static int print_83xx_arb_event(bool force, char *buf, int size) |
||||
{ |
||||
int etype = (gd->arch.arbiter_event_attributes & AEATR_EVENT) |
||||
>> AEATR_EVENT_SHIFT; |
||||
int mstr_id = (gd->arch.arbiter_event_attributes & AEATR_MSTR_ID) |
||||
>> AEATR_MSTR_ID_SHIFT; |
||||
int tbst = (gd->arch.arbiter_event_attributes & AEATR_TBST) |
||||
>> AEATR_TBST_SHIFT; |
||||
int tsize = (gd->arch.arbiter_event_attributes & AEATR_TSIZE) |
||||
>> AEATR_TSIZE_SHIFT; |
||||
int ttype = (gd->arch.arbiter_event_attributes & AEATR_TTYPE) |
||||
>> AEATR_TTYPE_SHIFT; |
||||
int tsize_val = (tbst << 3) | tsize; |
||||
int tsize_bytes = tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize; |
||||
int res = 0; |
||||
|
||||
/*
|
||||
* If we don't force output, and there is no event (event address == |
||||
* 0), then don't print anything |
||||
*/ |
||||
if (!force && !gd->arch.arbiter_event_address) |
||||
return 0; |
||||
|
||||
if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL)) { |
||||
res = snprintf(buf, size, |
||||
"Arbiter Event Status:\n" |
||||
" %s: 0x%08lX\n" |
||||
" %s: 0x%1x = %s\n" |
||||
" %s: 0x%02x = %s\n" |
||||
" %s: 0x%1x = %d bytes\n" |
||||
" %s: 0x%02x = %s\n", |
||||
"Event Address", gd->arch.arbiter_event_address, |
||||
"Event Type", etype, event[etype], |
||||
"Master ID", mstr_id, master[mstr_id], |
||||
"Transfer Size", tsize_val, tsize_bytes, |
||||
"Transfer Type", ttype, transfer[ttype]); |
||||
} else if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) { |
||||
res = snprintf(buf, size, |
||||
"Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n", |
||||
gd->arch.arbiter_event_attributes, |
||||
gd->arch.arbiter_event_address); |
||||
} |
||||
|
||||
return res; |
||||
} |
||||
|
||||
static int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size) |
||||
{ |
||||
/* Ad-hoc data structure to map RSR bit values to their descriptions */ |
||||
static const struct { |
||||
/* Bit mask for the bit in question */ |
||||
ulong mask; |
||||
/* Description of the bitmask in question */ |
||||
char *desc; |
||||
} bits[] = { |
||||
{ |
||||
RSR_SWSR, "Software Soft"}, { |
||||
RSR_SWHR, "Software Hard"}, { |
||||
RSR_JSRS, "JTAG Soft"}, { |
||||
RSR_CSHR, "Check Stop"}, { |
||||
RSR_SWRS, "Software Watchdog"}, { |
||||
RSR_BMRS, "Bus Monitor"}, { |
||||
RSR_SRS, "External/Internal Soft"}, { |
||||
RSR_HRS, "External/Internal Hard"} |
||||
}; |
||||
int res; |
||||
ulong rsr = gd->arch.reset_status; |
||||
int i; |
||||
char *sep; |
||||
|
||||
res = snprintf(buf, size, "Reset Status:"); |
||||
if (res < 0) { |
||||
debug("%s: Could not write reset status message (err = %d)\n", |
||||
dev->name, res); |
||||
return -EIO; |
||||
} |
||||
|
||||
buf += res; |
||||
size -= res; |
||||
|
||||
sep = " "; |
||||
for (i = 0; i < ARRAY_SIZE(bits); i++) |
||||
/* Print description of set bits */ |
||||
if (rsr & bits[i].mask) { |
||||
res = snprintf(buf, size, "%s%s%s", sep, bits[i].desc, |
||||
(i == ARRAY_SIZE(bits) - 1) ? "\n" : ""); |
||||
if (res < 0) { |
||||
debug("%s: Could not write reset status message (err = %d)\n", |
||||
dev->name, res); |
||||
return -EIO; |
||||
} |
||||
buf += res; |
||||
size -= res; |
||||
sep = ", "; |
||||
} |
||||
|
||||
/*
|
||||
* TODO(mario.six@gdsys.cc): Move this into a dedicated |
||||
* arbiter driver |
||||
*/ |
||||
if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL) || |
||||
CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) { |
||||
/*
|
||||
* If there was a bus monitor reset event, we force the arbiter |
||||
* event to be printed |
||||
*/ |
||||
res = print_83xx_arb_event(rsr & RSR_BMRS, buf, size); |
||||
if (res < 0) { |
||||
debug("%s: Could not write arbiter event message (err = %d)\n", |
||||
dev->name, res); |
||||
return -EIO; |
||||
} |
||||
buf += res; |
||||
size -= res; |
||||
} |
||||
snprintf(buf, size, "\n"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static struct sysreset_ops mpc83xx_sysreset = { |
||||
.request = mpc83xx_sysreset_request, |
||||
.get_status = mpc83xx_sysreset_get_status, |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(sysreset_mpc83xx) = { |
||||
.name = "mpc83xx_sysreset", |
||||
.id = UCLASS_SYSRESET, |
||||
.ops = &mpc83xx_sysreset, |
||||
}; |
@ -0,0 +1,103 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#ifndef _SYSRESET_MPC83XX_H_ |
||||
#define _SYSRESET_MPC83XX_H_ |
||||
|
||||
/*
|
||||
* String array for all possible event types; indexed by the EVENT field of the |
||||
* AEATR register. |
||||
*/ |
||||
static const char * const event[] = { |
||||
"Address Time Out", |
||||
"Data Time Out", |
||||
"Address Only Transfer Type", |
||||
"External Control Word Transfer Type", |
||||
"Reserved Transfer Type", |
||||
"Transfer Error", |
||||
"reserved", |
||||
"reserved" |
||||
}; |
||||
|
||||
/*
|
||||
* String array for all possible master IDs, which reflects the source of the |
||||
* transaction that caused the error; indexed by the MSTR_ID field of the AEATR |
||||
* register. |
||||
*/ |
||||
static const char * const master[] = { |
||||
"e300 Core Data Transaction", |
||||
"reserved", |
||||
"e300 Core Instruction Fetch", |
||||
"reserved", |
||||
"TSEC1", |
||||
"TSEC2", |
||||
"USB MPH", |
||||
"USB DR", |
||||
"Encryption Core", |
||||
"I2C Boot Sequencer", |
||||
"JTAG", |
||||
"reserved", |
||||
"eSDHC", |
||||
"PCI1", |
||||
"PCI2", |
||||
"DMA", |
||||
"QUICC Engine 00", |
||||
"QUICC Engine 01", |
||||
"QUICC Engine 10", |
||||
"QUICC Engine 11", |
||||
"reserved", |
||||
"reserved", |
||||
"reserved", |
||||
"reserved", |
||||
"SATA1", |
||||
"SATA2", |
||||
"SATA3", |
||||
"SATA4", |
||||
"reserved", |
||||
"PCI Express 1", |
||||
"PCI Express 2", |
||||
"TDM-DMAC" |
||||
}; |
||||
|
||||
/*
|
||||
* String array for all possible transfer types; indexed by the TTYPE field of |
||||
* the AEATR register. |
||||
*/ |
||||
static const char * const transfer[] = { |
||||
"Address-only, Clean Block", |
||||
"Address-only, lwarx reservation set", |
||||
"Single-beat or Burst write", |
||||
"reserved", |
||||
"Address-only, Flush Block", |
||||
"reserved", |
||||
"Burst write", |
||||
"reserved", |
||||
"Address-only, sync", |
||||
"Address-only, tlbsync", |
||||
"Single-beat or Burst read", |
||||
"Single-beat or Burst read", |
||||
"Address-only, Kill Block", |
||||
"Address-only, icbi", |
||||
"Burst read", |
||||
"reserved", |
||||
"Address-only, eieio", |
||||
"reserved", |
||||
"Single-beat write", |
||||
"reserved", |
||||
"ecowx - Illegal single-beat write", |
||||
"reserved", |
||||
"reserved", |
||||
"reserved", |
||||
"Address-only, TLB Invalidate", |
||||
"reserved", |
||||
"Single-beat or Burst read", |
||||
"reserved", |
||||
"eciwx - Illegal single-beat read", |
||||
"reserved", |
||||
"Burst read", |
||||
"reserved" |
||||
}; |
||||
#endif /* _SYSRESET_MPC83XX_H_ */ |
@ -0,0 +1,249 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <board.h> |
||||
#include <clk.h> |
||||
#include <dm.h> |
||||
#include <timer.h> |
||||
#include <watchdog.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
/**
|
||||
* struct mpc83xx_timer_priv - Private data structure for MPC83xx timer driver |
||||
* @decrementer_count: Value to which the decrementer register should be re-set |
||||
* to when a timer interrupt occurs, thus determines the |
||||
* interrupt frequency (value for 1e6/HZ microseconds) |
||||
* @timestamp: Counter for the number of timer interrupts that have |
||||
* occurred (i.e. can be used to trigger events |
||||
* periodically in the timer interrupt) |
||||
*/ |
||||
struct mpc83xx_timer_priv { |
||||
uint decrementer_count; |
||||
ulong timestamp; |
||||
}; |
||||
|
||||
/*
|
||||
* Bitmask for enabling the time base in the SPCR (System Priority |
||||
* Configuration Register) |
||||
*/ |
||||
static const u32 SPCR_TBEN_MASK = BIT(31 - 9); |
||||
|
||||
/**
|
||||
* get_dec() - Get the value of the decrementer register |
||||
* |
||||
* Return: The value of the decrementer register |
||||
*/ |
||||
static inline unsigned long get_dec(void) |
||||
{ |
||||
unsigned long val; |
||||
|
||||
asm volatile ("mfdec %0" : "=r" (val) : ); |
||||
|
||||
return val; |
||||
} |
||||
|
||||
/**
|
||||
* set_dec() - Set the value of the decrementer register |
||||
* @val: The value of the decrementer register to be set |
||||
*/ |
||||
static inline void set_dec(unsigned long val) |
||||
{ |
||||
if (val) |
||||
asm volatile ("mtdec %0"::"r" (val)); |
||||
} |
||||
|
||||
/**
|
||||
* mftbu() - Get value of TBU (upper time base) register |
||||
* |
||||
* Return: Value of the TBU register |
||||
*/ |
||||
static inline u32 mftbu(void) |
||||
{ |
||||
u32 rval; |
||||
|
||||
asm volatile("mftbu %0" : "=r" (rval)); |
||||
return rval; |
||||
} |
||||
|
||||
/**
|
||||
* mftb() - Get value of TBL (lower time base) register |
||||
* |
||||
* Return: Value of the TBL register |
||||
*/ |
||||
static inline u32 mftb(void) |
||||
{ |
||||
u32 rval; |
||||
|
||||
asm volatile("mftb %0" : "=r" (rval)); |
||||
return rval; |
||||
} |
||||
|
||||
/*
|
||||
* TODO(mario.six@gdsys.cc): This should really be done by timer_init, and the |
||||
* interrupt init should go into a interrupt driver. |
||||
*/ |
||||
int interrupt_init(void) |
||||
{ |
||||
immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; |
||||
struct udevice *csb; |
||||
struct udevice *board; |
||||
struct udevice *timer; |
||||
struct mpc83xx_timer_priv *timer_priv; |
||||
struct clk clock; |
||||
int ret; |
||||
|
||||
ret = uclass_first_device_err(UCLASS_TIMER, &timer); |
||||
if (ret) { |
||||
debug("%s: Could not find timer device (error: %d)", |
||||
__func__, ret); |
||||
return ret; |
||||
} |
||||
|
||||
timer_priv = dev_get_priv(timer); |
||||
|
||||
if (board_get(&board)) { |
||||
debug("%s: board device could not be fetched.\n", __func__); |
||||
return -ENOENT; |
||||
} |
||||
|
||||
ret = uclass_get_device_by_phandle(UCLASS_SIMPLE_BUS, board, |
||||
"csb", &csb); |
||||
if (ret) { |
||||
debug("%s: Could not retrieve CSB device (error: %d)", |
||||
__func__, ret); |
||||
return ret; |
||||
} |
||||
|
||||
ret = clk_get_by_index(csb, 0, &clock); |
||||
if (ret) { |
||||
debug("%s: Could not retrieve clock (error: %d)", |
||||
__func__, ret); |
||||
return ret; |
||||
} |
||||
|
||||
timer_priv->decrementer_count = (clk_get_rate(&clock) / 4) |
||||
/ CONFIG_SYS_HZ; |
||||
/* Enable e300 time base */ |
||||
setbits_be32(&immr->sysconf.spcr, SPCR_TBEN_MASK); |
||||
|
||||
set_dec(timer_priv->decrementer_count); |
||||
|
||||
/* Switch on interrupts */ |
||||
set_msr(get_msr() | MSR_EE); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* timer_interrupt() - Handler for the timer interrupt |
||||
* @regs: Array of register values |
||||
*/ |
||||
void timer_interrupt(struct pt_regs *regs) |
||||
{ |
||||
struct udevice *timer = gd->timer; |
||||
struct mpc83xx_timer_priv *priv; |
||||
|
||||
/*
|
||||
* During initialization, gd->timer might not be set yet, but the timer |
||||
* interrupt may already be enabled. In this case, wait for the |
||||
* initialization to complete |
||||
*/ |
||||
if (!timer) |
||||
return; |
||||
|
||||
priv = dev_get_priv(timer); |
||||
|
||||
/* Restore Decrementer Count */ |
||||
set_dec(priv->decrementer_count); |
||||
|
||||
priv->timestamp++; |
||||
|
||||
#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG) |
||||
if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0) |
||||
WATCHDOG_RESET(); |
||||
#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */ |
||||
|
||||
#ifdef CONFIG_LED_STATUS |
||||
status_led_tick(priv->timestamp); |
||||
#endif /* CONFIG_LED_STATUS */ |
||||
|
||||
#ifdef CONFIG_SHOW_ACTIVITY |
||||
board_show_activity(priv->timestamp); |
||||
#endif /* CONFIG_SHOW_ACTIVITY */ |
||||
} |
||||
|
||||
void wait_ticks(ulong ticks) |
||||
{ |
||||
ulong end = get_ticks() + ticks; |
||||
|
||||
while (end > get_ticks()) |
||||
WATCHDOG_RESET(); |
||||
} |
||||
|
||||
static int mpc83xx_timer_get_count(struct udevice *dev, u64 *count) |
||||
{ |
||||
u32 tbu, tbl; |
||||
|
||||
/*
|
||||
* To make sure that no tbl overflow occurred between reading tbl and |
||||
* tbu, read tbu again, and compare it with the previously read tbu |
||||
* value: If they're different, a tbl overflow has occurred. |
||||
*/ |
||||
do { |
||||
tbu = mftbu(); |
||||
tbl = mftb(); |
||||
} while (tbu != mftbu()); |
||||
|
||||
*count = (tbu * 0x10000ULL) + tbl; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mpc83xx_timer_probe(struct udevice *dev) |
||||
{ |
||||
struct timer_dev_priv *uc_priv = dev->uclass_priv; |
||||
struct clk clock; |
||||
int ret; |
||||
|
||||
ret = interrupt_init(); |
||||
if (ret) { |
||||
debug("%s: interrupt_init failed (err = %d)\n", |
||||
dev->name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
ret = clk_get_by_index(dev, 0, &clock); |
||||
if (ret) { |
||||
debug("%s: Could not retrieve clock (err = %d)\n", |
||||
dev->name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
uc_priv->clock_rate = (clk_get_rate(&clock) + 3L) / 4L; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct timer_ops mpc83xx_timer_ops = { |
||||
.get_count = mpc83xx_timer_get_count, |
||||
}; |
||||
|
||||
static const struct udevice_id mpc83xx_timer_ids[] = { |
||||
{ .compatible = "fsl,mpc83xx-timer" }, |
||||
{ /* sentinel */ } |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(mpc83xx_timer) = { |
||||
.name = "mpc83xx_timer", |
||||
.id = UCLASS_TIMER, |
||||
.of_match = mpc83xx_timer_ids, |
||||
.probe = mpc83xx_timer_probe, |
||||
.ops = &mpc83xx_timer_ops, |
||||
.flags = DM_FLAG_PRE_RELOC, |
||||
.priv_auto_alloc_size = sizeof(struct mpc83xx_timer_priv), |
||||
}; |
@ -0,0 +1,33 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#ifndef DT_BINDINGS_MPC83XX_CLK_H |
||||
#define DT_BINDINGS_MPC83XX_CLK_H |
||||
#define MPC83XX_CLK_CORE 0 |
||||
#define MPC83XX_CLK_CSB 1 |
||||
#define MPC83XX_CLK_QE 2 |
||||
#define MPC83XX_CLK_BRG 3 |
||||
#define MPC83XX_CLK_LBIU 4 |
||||
#define MPC83XX_CLK_LCLK 5 |
||||
#define MPC83XX_CLK_MEM 6 |
||||
#define MPC83XX_CLK_MEM_SEC 7 |
||||
#define MPC83XX_CLK_ENC 8 |
||||
#define MPC83XX_CLK_I2C1 9 |
||||
#define MPC83XX_CLK_I2C2 10 |
||||
#define MPC83XX_CLK_TDM 11 |
||||
#define MPC83XX_CLK_SDHC 12 |
||||
#define MPC83XX_CLK_TSEC1 13 |
||||
#define MPC83XX_CLK_TSEC2 14 |
||||
#define MPC83XX_CLK_USBDR 15 |
||||
#define MPC83XX_CLK_USBMPH 16 |
||||
#define MPC83XX_CLK_PCIEXP1 17 |
||||
#define MPC83XX_CLK_PCIEXP2 18 |
||||
#define MPC83XX_CLK_SATA 19 |
||||
#define MPC83XX_CLK_DMAC 20 |
||||
#define MPC83XX_CLK_PCI 21 |
||||
/* Count */ |
||||
#define MPC83XX_CLK_COUNT 22 |
||||
#endif /* DT_BINDINGS_MPC83XX_CLK_H */ |
@ -0,0 +1,161 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#ifndef DT_BINDINGS_MPC83XX_SDRAM_H |
||||
#define DT_BINDINGS_MPC83XX_SDRAM_H |
||||
|
||||
/* DDR Control Driver register */ |
||||
|
||||
#define DSO_DISABLE 0 |
||||
#define DSO_ENABLE 1 |
||||
|
||||
#define DSO_P_IMPEDANCE_HIGHEST_Z 0x0 |
||||
#define DSO_P_IMPEDANCE_MUCH_HIGHER_Z 0x8 |
||||
#define DSO_P_IMPEDANCE_HIGHER_Z 0xC |
||||
#define DSO_P_IMPEDANCE_NOMINAL 0xE |
||||
#define DSO_P_IMPEDANCE_LOWER_Z 0xF |
||||
|
||||
#define DSO_N_IMPEDANCE_HIGHEST_Z 0x0 |
||||
#define DSO_N_IMPEDANCE_MUCH_HIGHER_Z 0x8 |
||||
#define DSO_N_IMPEDANCE_HIGHER_Z 0xC |
||||
#define DSO_N_IMPEDANCE_NOMINAL 0xE |
||||
#define DSO_N_IMPEDANCE_LOWER_Z 0xF |
||||
|
||||
#define ODT_TERMINATION_75_OHM 0 |
||||
#define ODT_TERMINATION_150_OHM 1 |
||||
|
||||
#define DDR_TYPE_DDR2_1_8_VOLT 0 |
||||
#define DDR_TYPE_DDR1_2_5_VOLT 1 |
||||
|
||||
#define MVREF_SEL_EXTERNAL 0 |
||||
#define MVREF_SEL_INTERNAL_GVDD 1 |
||||
|
||||
#define M_ODR_ENABLE 0 |
||||
#define M_ODR_DISABLE 1 |
||||
|
||||
/* CS config register */ |
||||
|
||||
#define AUTO_PRECHARGE_ENABLE 0x00800000 |
||||
#define AUTO_PRECHARGE_DISABLE 0x00000000 |
||||
|
||||
#define ODT_RD_NEVER 0x00000000 |
||||
#define ODT_RD_ONLY_CURRENT 0x00100000 |
||||
#define ODT_RD_ONLY_OTHER_CS 0x00200000 |
||||
#define ODT_RD_ONLY_OTHER_DIMM 0x00300000 |
||||
#define ODT_RD_ALL 0x00400000 |
||||
|
||||
#define ODT_WR_NEVER 0x00000000 |
||||
#define ODT_WR_ONLY_CURRENT 0x00010000 |
||||
#define ODT_WR_ONLY_OTHER_CS 0x00020000 |
||||
#define ODT_WR_ONLY_OTHER_DIMM 0x00030000 |
||||
#define ODT_WR_ALL 0x00040000 |
||||
|
||||
/* DDR SDRAM Clock Control register */ |
||||
|
||||
#define CLOCK_ADJUST_025 0x01000000 |
||||
#define CLOCK_ADJUST_05 0x02000000 |
||||
#define CLOCK_ADJUST_075 0x03000000 |
||||
#define CLOCK_ADJUST_1 0x04000000 |
||||
|
||||
#define CASLAT_20 0x3 /* CAS latency = 2.0 */ |
||||
#define CASLAT_25 0x4 /* CAS latency = 2.5 */ |
||||
#define CASLAT_30 0x5 /* CAS latency = 3.0 */ |
||||
#define CASLAT_35 0x6 /* CAS latency = 3.5 */ |
||||
#define CASLAT_40 0x7 /* CAS latency = 4.0 */ |
||||
#define CASLAT_45 0x8 /* CAS latency = 4.5 */ |
||||
#define CASLAT_50 0x9 /* CAS latency = 5.0 */ |
||||
#define CASLAT_55 0xa /* CAS latency = 5.5 */ |
||||
#define CASLAT_60 0xb /* CAS latency = 6.0 */ |
||||
#define CASLAT_65 0xc /* CAS latency = 6.5 */ |
||||
#define CASLAT_70 0xd /* CAS latency = 7.0 */ |
||||
#define CASLAT_75 0xe /* CAS latency = 7.5 */ |
||||
#define CASLAT_80 0xf /* CAS latency = 8.0 */ |
||||
|
||||
/* DDR SDRAM Timing Configuration 2 register */ |
||||
|
||||
#define READ_LAT_PLUS_1 0x0 |
||||
#define READ_LAT 0x2 |
||||
#define READ_LAT_PLUS_1_4 0x3 |
||||
#define READ_LAT_PLUS_1_2 0x4 |
||||
#define READ_LAT_PLUS_3_4 0x5 |
||||
#define READ_LAT_PLUS_5_4 0x7 |
||||
#define READ_LAT_PLUS_3_2 0x8 |
||||
#define READ_LAT_PLUS_7_4 0x9 |
||||
#define READ_LAT_PLUS_2 0xA |
||||
#define READ_LAT_PLUS_9_4 0xB |
||||
#define READ_LAT_PLUS_5_2 0xC |
||||
#define READ_LAT_PLUS_11_4 0xD |
||||
#define READ_LAT_PLUS_3 0xE |
||||
#define READ_LAT_PLUS_13_4 0xF |
||||
#define READ_LAT_PLUS_7_2 0x10 |
||||
#define READ_LAT_PLUS_15_4 0x11 |
||||
#define READ_LAT_PLUS_4 0x12 |
||||
#define READ_LAT_PLUS_17_4 0x13 |
||||
#define READ_LAT_PLUS_9_2 0x14 |
||||
#define READ_LAT_PLUS_19_4 0x15 |
||||
|
||||
#define CLOCK_DELAY_0 0x0 |
||||
#define CLOCK_DELAY_1_4 0x1 |
||||
#define CLOCK_DELAY_1_2 0x2 |
||||
#define CLOCK_DELAY_3_4 0x3 |
||||
#define CLOCK_DELAY_1 0x4 |
||||
#define CLOCK_DELAY_5_4 0x5 |
||||
#define CLOCK_DELAY_3_2 0x6 |
||||
|
||||
/* DDR SDRAM Control Configuration */ |
||||
|
||||
#define SREN_DISABLE 0x0 |
||||
#define SREN_ENABLE 0x1 |
||||
|
||||
#define ECC_DISABLE 0x0 |
||||
#define ECC_ENABLE 0x1 |
||||
|
||||
#define RD_DISABLE 0x0 |
||||
#define RD_ENABLE 0x1 |
||||
|
||||
#define TYPE_DDR1 0x2 |
||||
#define TYPE_DDR2 0x3 |
||||
|
||||
#define DYN_PWR_DISABLE 0x0 |
||||
#define DYN_PWR_ENABLE 0x1 |
||||
|
||||
#define DATA_BUS_WIDTH_16 0x1 |
||||
#define DATA_BUS_WIDTH_32 0x2 |
||||
|
||||
#define NCAP_DISABLE 0x0 |
||||
#define NCAP_ENABLE 0x1 |
||||
|
||||
#define TIMING_1T 0x0 |
||||
#define TIMING_2T 0x1 |
||||
|
||||
#define INTERLEAVE_NONE 0x0 |
||||
#define INTERLEAVE_1_AND_2 0x1 |
||||
|
||||
#define PRECHARGE_MA_10 0x0 |
||||
#define PRECHARGE_MA_8 0x1 |
||||
|
||||
#define STRENGTH_FULL 0x0 |
||||
#define STRENGTH_HALF 0x1 |
||||
|
||||
#define INITIALIZATION_DONT_BYPASS 0x0 |
||||
#define INITIALIZATION_BYPASS 0x1 |
||||
|
||||
/* DDR SDRAM Control Configuration 2 register */ |
||||
|
||||
#define MODE_NORMAL 0x0 |
||||
#define MODE_REFRESH 0x1 |
||||
|
||||
#define DLL_RESET_ENABLE 0x0 |
||||
#define DLL_RESET_DISABLE 0x1 |
||||
|
||||
#define DQS_TRUE 0x0 |
||||
|
||||
#define ODT_ASSERT_NEVER 0x0 |
||||
#define ODT_ASSERT_WRITES 0x1 |
||||
#define ODT_ASSERT_READS 0x2 |
||||
#define ODT_ASSERT_ALWAYS 0x3 |
||||
|
||||
#endif |
@ -1,21 +1,105 @@ |
||||
/* SPDX-License-Identifier: GPL-2.0+ */ |
||||
/*
|
||||
* Based on bitrev from the Linux kernel, by Akinobu Mita |
||||
*/ |
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0 */ |
||||
#ifndef _LINUX_BITREV_H |
||||
#define _LINUX_BITREV_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
extern u8 const byte_rev_table[256]; |
||||
#ifdef CONFIG_HAVE_ARCH_BITREVERSE |
||||
#include <asm/bitrev.h> |
||||
|
||||
#define __bitrev32 __arch_bitrev32 |
||||
#define __bitrev16 __arch_bitrev16 |
||||
#define __bitrev8 __arch_bitrev8 |
||||
|
||||
static inline u8 bitrev8(u8 byte) |
||||
#else |
||||
extern u8 const byte_rev_table[256]; |
||||
static inline u8 __bitrev8(u8 byte) |
||||
{ |
||||
return byte_rev_table[byte]; |
||||
} |
||||
|
||||
u16 bitrev16(u16 in); |
||||
u32 bitrev32(u32 in); |
||||
static inline u16 __bitrev16(u16 x) |
||||
{ |
||||
return (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8); |
||||
} |
||||
|
||||
static inline u32 __bitrev32(u32 x) |
||||
{ |
||||
return (__bitrev16(x & 0xffff) << 16) | __bitrev16(x >> 16); |
||||
} |
||||
|
||||
#endif /* CONFIG_HAVE_ARCH_BITREVERSE */ |
||||
|
||||
#define __bitrev8x4(x) (__bitrev32(swab32(x))) |
||||
|
||||
#define __constant_bitrev32(x) \ |
||||
({ \
|
||||
u32 __x = x; \
|
||||
__x = (__x >> 16) | (__x << 16);\
|
||||
__x = ((__x & (u32)0xFF00FF00UL) >> 8) | ((__x & (u32)0x00FF00FFUL) << 8); \
|
||||
__x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \
|
||||
__x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \
|
||||
__x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \
|
||||
__x; \
|
||||
}) |
||||
|
||||
#define __constant_bitrev16(x) \ |
||||
({ \
|
||||
u16 __x = x; \
|
||||
__x = (__x >> 8) | (__x << 8); \
|
||||
__x = ((__x & (u16)0xF0F0U) >> 4) | ((__x & (u16)0x0F0FU) << 4); \
|
||||
__x = ((__x & (u16)0xCCCCU) >> 2) | ((__x & (u16)0x3333U) << 2); \
|
||||
__x = ((__x & (u16)0xAAAAU) >> 1) | ((__x & (u16)0x5555U) << 1); \
|
||||
__x; \
|
||||
}) |
||||
|
||||
#define __constant_bitrev8x4(x) \ |
||||
({ \
|
||||
u32 __x = x; \
|
||||
__x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \
|
||||
__x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \
|
||||
__x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \
|
||||
__x; \
|
||||
}) |
||||
|
||||
#define __constant_bitrev8(x) \ |
||||
({ \
|
||||
u8 __x = x; \
|
||||
__x = (__x >> 4) | (__x << 4); \
|
||||
__x = ((__x & (u8)0xCCU) >> 2) | ((__x & (u8)0x33U) << 2); \
|
||||
__x = ((__x & (u8)0xAAU) >> 1) | ((__x & (u8)0x55U) << 1); \
|
||||
__x; \
|
||||
}) |
||||
|
||||
#define bitrev32(x) \ |
||||
({ \
|
||||
u32 __x = x; \
|
||||
__builtin_constant_p(__x) ? \
|
||||
__constant_bitrev32(__x) : \
|
||||
__bitrev32(__x); \
|
||||
}) |
||||
|
||||
#define bitrev16(x) \ |
||||
({ \
|
||||
u16 __x = x; \
|
||||
__builtin_constant_p(__x) ? \
|
||||
__constant_bitrev16(__x) : \
|
||||
__bitrev16(__x); \
|
||||
}) |
||||
|
||||
#define bitrev8x4(x) \ |
||||
({ \
|
||||
u32 __x = x; \
|
||||
__builtin_constant_p(__x) ? \
|
||||
__constant_bitrev8x4(__x) : \
|
||||
__bitrev8x4(__x); \
|
||||
}) |
||||
|
||||
#define bitrev8(x) \ |
||||
({ \
|
||||
u8 __x = x; \
|
||||
__builtin_constant_p(__x) ? \
|
||||
__constant_bitrev8(__x) : \
|
||||
__bitrev8(__x) ; \
|
||||
}) |
||||
#endif /* _LINUX_BITREV_H */ |
||||
|
@ -0,0 +1,45 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018 |
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <dm/test.h> |
||||
#include <dm/uclass-internal.h> |
||||
#include <cpu.h> |
||||
#include <test/ut.h> |
||||
|
||||
static int dm_test_cpu(struct unit_test_state *uts) |
||||
{ |
||||
struct udevice *dev; |
||||
char text[128]; |
||||
struct cpu_info info; |
||||
|
||||
ut_assertok(cpu_probe_all()); |
||||
|
||||
/* Check that cpu_probe_all really activated all CPUs */ |
||||
for (uclass_find_first_device(UCLASS_CPU, &dev); |
||||
dev; |
||||
uclass_find_next_device(&dev)) |
||||
ut_assert(dev->flags & DM_FLAG_ACTIVATED); |
||||
|
||||
ut_assertok(uclass_get_device_by_name(UCLASS_CPU, "cpu-test1", &dev)); |
||||
|
||||
ut_assertok(cpu_get_desc(dev, text, sizeof(text))); |
||||
ut_assertok(strcmp(text, "LEG Inc. SuperMegaUltraTurbo CPU No. 1")); |
||||
|
||||
ut_assertok(cpu_get_info(dev, &info)); |
||||
ut_asserteq(info.cpu_freq, 42 * 42 * 42 * 42 * 42); |
||||
ut_asserteq(info.features, 0x42424242); |
||||
|
||||
ut_asserteq(cpu_get_count(dev), 42); |
||||
|
||||
ut_assertok(cpu_get_vendor(dev, text, sizeof(text))); |
||||
ut_assertok(strcmp(text, "Languid Example Garbage Inc.")); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
DM_TEST(dm_test_cpu, DM_TESTF_SCAN_FDT); |
Loading…
Reference in new issue