2017-12-22 05:45:18 +03:00
// SPDX-License-Identifier: GPL-2.0+
2019-08-25 17:18:47 +03:00
// Copyright IBM Corp
2017-12-22 05:45:18 +03:00
# define pr_fmt(fmt) "clk-aspeed: " fmt
# include <linux/mfd/syscon.h>
# include <linux/of_address.h>
2017-12-22 05:45:20 +03:00
# include <linux/of_device.h>
# include <linux/platform_device.h>
2017-12-22 05:45:18 +03:00
# include <linux/regmap.h>
# include <linux/slab.h>
# include <dt-bindings/clock/aspeed-clock.h>
2019-08-25 17:18:47 +03:00
# include "clk-aspeed.h"
2019-10-10 05:06:55 +03:00
# define ASPEED_NUM_CLKS 38
2017-12-22 05:45:18 +03:00
2018-04-27 05:55:47 +03:00
# define ASPEED_RESET2_OFFSET 32
2017-12-22 05:45:18 +03:00
2017-12-22 05:45:19 +03:00
# define ASPEED_RESET_CTRL 0x04
# define ASPEED_CLK_SELECTION 0x08
# define ASPEED_CLK_STOP_CTRL 0x0c
# define ASPEED_MPLL_PARAM 0x20
# define ASPEED_HPLL_PARAM 0x24
# define AST2500_HPLL_BYPASS_EN BIT(20)
2018-06-29 02:15:40 +03:00
# define AST2400_HPLL_PROGRAMMED BIT(18)
2017-12-22 05:45:19 +03:00
# define AST2400_HPLL_BYPASS_EN BIT(17)
# define ASPEED_MISC_CTRL 0x2c
# define UART_DIV13_EN BIT(12)
2019-10-10 05:06:55 +03:00
# define ASPEED_MAC_CLK_DLY 0x48
2017-12-22 05:45:18 +03:00
# define ASPEED_STRAP 0x70
2017-12-22 05:45:19 +03:00
# define CLKIN_25MHZ_EN BIT(23)
# define AST2400_CLK_SOURCE_SEL BIT(18)
# define ASPEED_CLK_SELECTION_2 0xd8
2018-04-27 05:55:47 +03:00
# define ASPEED_RESET_CTRL2 0xd4
2017-12-22 05:45:19 +03:00
/* Globally visible clocks */
static DEFINE_SPINLOCK ( aspeed_clk_lock ) ;
2017-12-22 05:45:18 +03:00
/* Keeps track of all clocks */
static struct clk_hw_onecell_data * aspeed_clk_data ;
static void __iomem * scu_base ;
/* TODO: ask Aspeed about the actual parent data */
static const struct aspeed_gate_data aspeed_gates [ ] = {
/* clk rst name parent flags */
2019-04-02 21:25:03 +03:00
[ ASPEED_CLK_GATE_ECLK ] = { 0 , 6 , " eclk-gate " , " eclk " , 0 } , /* Video Engine */
2017-12-22 05:45:18 +03:00
[ ASPEED_CLK_GATE_GCLK ] = { 1 , 7 , " gclk-gate " , NULL , 0 } , /* 2D engine */
[ ASPEED_CLK_GATE_MCLK ] = { 2 , - 1 , " mclk-gate " , " mpll " , CLK_IS_CRITICAL } , /* SDRAM */
2019-04-02 21:25:03 +03:00
[ ASPEED_CLK_GATE_VCLK ] = { 3 , - 1 , " vclk-gate " , NULL , 0 } , /* Video Capture */
2018-06-07 10:09:59 +03:00
[ ASPEED_CLK_GATE_BCLK ] = { 4 , 8 , " bclk-gate " , " bclk " , CLK_IS_CRITICAL } , /* PCIe/PCI */
[ ASPEED_CLK_GATE_DCLK ] = { 5 , - 1 , " dclk-gate " , NULL , CLK_IS_CRITICAL } , /* DAC */
2017-12-22 05:45:18 +03:00
[ ASPEED_CLK_GATE_REFCLK ] = { 6 , - 1 , " refclk-gate " , " clkin " , CLK_IS_CRITICAL } ,
[ ASPEED_CLK_GATE_USBPORT2CLK ] = { 7 , 3 , " usb-port2-gate " , NULL , 0 } , /* USB2.0 Host port 2 */
[ ASPEED_CLK_GATE_LCLK ] = { 8 , 5 , " lclk-gate " , NULL , 0 } , /* LPC */
[ ASPEED_CLK_GATE_USBUHCICLK ] = { 9 , 15 , " usb-uhci-gate " , NULL , 0 } , /* USB1.1 (requires port 2 enabled) */
[ ASPEED_CLK_GATE_D1CLK ] = { 10 , 13 , " d1clk-gate " , NULL , 0 } , /* GFX CRT */
[ ASPEED_CLK_GATE_YCLK ] = { 13 , 4 , " yclk-gate " , NULL , 0 } , /* HAC */
[ ASPEED_CLK_GATE_USBPORT1CLK ] = { 14 , 14 , " usb-port1-gate " , NULL , 0 } , /* USB2 hub/USB2 host port 1/USB1.1 dev */
[ ASPEED_CLK_GATE_UART1CLK ] = { 15 , - 1 , " uart1clk-gate " , " uart " , 0 } , /* UART1 */
[ ASPEED_CLK_GATE_UART2CLK ] = { 16 , - 1 , " uart2clk-gate " , " uart " , 0 } , /* UART2 */
[ ASPEED_CLK_GATE_UART5CLK ] = { 17 , - 1 , " uart5clk-gate " , " uart " , 0 } , /* UART5 */
[ ASPEED_CLK_GATE_ESPICLK ] = { 19 , - 1 , " espiclk-gate " , NULL , 0 } , /* eSPI */
[ ASPEED_CLK_GATE_MAC1CLK ] = { 20 , 11 , " mac1clk-gate " , " mac " , 0 } , /* MAC1 */
[ ASPEED_CLK_GATE_MAC2CLK ] = { 21 , 12 , " mac2clk-gate " , " mac " , 0 } , /* MAC2 */
[ ASPEED_CLK_GATE_RSACLK ] = { 24 , - 1 , " rsaclk-gate " , NULL , 0 } , /* RSA */
[ ASPEED_CLK_GATE_UART3CLK ] = { 25 , - 1 , " uart3clk-gate " , " uart " , 0 } , /* UART3 */
[ ASPEED_CLK_GATE_UART4CLK ] = { 26 , - 1 , " uart4clk-gate " , " uart " , 0 } , /* UART4 */
2018-06-26 04:55:25 +03:00
[ ASPEED_CLK_GATE_SDCLK ] = { 27 , 16 , " sdclk-gate " , NULL , 0 } , /* SDIO/SD */
2017-12-22 05:45:18 +03:00
[ ASPEED_CLK_GATE_LHCCLK ] = { 28 , - 1 , " lhclk-gate " , " lhclk " , 0 } , /* LPC master/LPC+ */
} ;
2019-04-02 21:25:03 +03:00
static const char * const eclk_parent_names [ ] = {
" mpll " ,
" hpll " ,
" dpll " ,
} ;
static const struct clk_div_table ast2500_eclk_div_table [ ] = {
{ 0x0 , 2 } ,
{ 0x1 , 2 } ,
{ 0x2 , 3 } ,
{ 0x3 , 4 } ,
{ 0x4 , 5 } ,
{ 0x5 , 6 } ,
{ 0x6 , 7 } ,
{ 0x7 , 8 } ,
{ 0 }
} ;
2017-12-22 05:45:20 +03:00
static const struct clk_div_table ast2500_mac_div_table [ ] = {
{ 0x0 , 4 } , /* Yep, really. Aspeed confirmed this is correct */
{ 0x1 , 4 } ,
{ 0x2 , 6 } ,
{ 0x3 , 8 } ,
{ 0x4 , 10 } ,
{ 0x5 , 12 } ,
{ 0x6 , 14 } ,
{ 0x7 , 16 } ,
{ 0 }
} ;
2017-12-22 05:45:19 +03:00
static const struct clk_div_table ast2400_div_table [ ] = {
{ 0x0 , 2 } ,
{ 0x1 , 4 } ,
{ 0x2 , 6 } ,
{ 0x3 , 8 } ,
{ 0x4 , 10 } ,
{ 0x5 , 12 } ,
{ 0x6 , 14 } ,
{ 0x7 , 16 } ,
{ 0 }
} ;
static const struct clk_div_table ast2500_div_table [ ] = {
{ 0x0 , 4 } ,
{ 0x1 , 8 } ,
{ 0x2 , 12 } ,
{ 0x3 , 16 } ,
{ 0x4 , 20 } ,
{ 0x5 , 24 } ,
{ 0x6 , 28 } ,
{ 0x7 , 32 } ,
{ 0 }
} ;
static struct clk_hw * aspeed_ast2400_calc_pll ( const char * name , u32 val )
{
unsigned int mult , div ;
if ( val & AST2400_HPLL_BYPASS_EN ) {
/* Pass through mode */
mult = div = 1 ;
} else {
/* F = 24Mhz * (2-OD) * [(N + 2) / (D + 1)] */
u32 n = ( val > > 5 ) & 0x3f ;
u32 od = ( val > > 4 ) & 0x1 ;
u32 d = val & 0xf ;
mult = ( 2 - od ) * ( n + 2 ) ;
div = d + 1 ;
}
return clk_hw_register_fixed_factor ( NULL , name , " clkin " , 0 ,
mult , div ) ;
} ;
static struct clk_hw * aspeed_ast2500_calc_pll ( const char * name , u32 val )
{
unsigned int mult , div ;
if ( val & AST2500_HPLL_BYPASS_EN ) {
/* Pass through mode */
mult = div = 1 ;
} else {
/* F = clkin * [(M+1) / (N+1)] / (P + 1) */
u32 p = ( val > > 13 ) & 0x3f ;
u32 m = ( val > > 5 ) & 0xff ;
u32 n = val & 0x1f ;
mult = ( m + 1 ) / ( n + 1 ) ;
div = p + 1 ;
}
return clk_hw_register_fixed_factor ( NULL , name , " clkin " , 0 ,
mult , div ) ;
}
2017-12-22 05:45:20 +03:00
static const struct aspeed_clk_soc_data ast2500_data = {
. div_table = ast2500_div_table ,
2019-04-02 21:25:03 +03:00
. eclk_div_table = ast2500_eclk_div_table ,
2017-12-22 05:45:20 +03:00
. mac_div_table = ast2500_mac_div_table ,
. calc_pll = aspeed_ast2500_calc_pll ,
} ;
static const struct aspeed_clk_soc_data ast2400_data = {
. div_table = ast2400_div_table ,
2019-04-02 21:25:03 +03:00
. eclk_div_table = ast2400_div_table ,
2017-12-22 05:45:20 +03:00
. mac_div_table = ast2400_div_table ,
. calc_pll = aspeed_ast2400_calc_pll ,
} ;
2018-03-08 23:57:20 +03:00
static int aspeed_clk_is_enabled ( struct clk_hw * hw )
{
struct aspeed_clk_gate * gate = to_aspeed_clk_gate ( hw ) ;
u32 clk = BIT ( gate - > clock_idx ) ;
2018-07-03 10:24:47 +03:00
u32 rst = BIT ( gate - > reset_idx ) ;
2018-03-08 23:57:20 +03:00
u32 enval = ( gate - > flags & CLK_GATE_SET_TO_DISABLE ) ? 0 : clk ;
u32 reg ;
2018-07-03 10:24:47 +03:00
/*
* If the IP is in reset , treat the clock as not enabled ,
* this happens with some clocks such as the USB one when
* coming from cold reset . Without this , aspeed_clk_enable ( )
* will fail to lift the reset .
*/
if ( gate - > reset_idx > = 0 ) {
regmap_read ( gate - > map , ASPEED_RESET_CTRL , & reg ) ;
if ( reg & rst )
return 0 ;
}
2018-03-08 23:57:20 +03:00
regmap_read ( gate - > map , ASPEED_CLK_STOP_CTRL , & reg ) ;
return ( ( reg & clk ) = = enval ) ? 1 : 0 ;
}
2017-12-22 05:45:21 +03:00
static int aspeed_clk_enable ( struct clk_hw * hw )
{
struct aspeed_clk_gate * gate = to_aspeed_clk_gate ( hw ) ;
unsigned long flags ;
u32 clk = BIT ( gate - > clock_idx ) ;
u32 rst = BIT ( gate - > reset_idx ) ;
2018-01-12 08:48:01 +03:00
u32 enval ;
2017-12-22 05:45:21 +03:00
spin_lock_irqsave ( gate - > lock , flags ) ;
2018-03-08 23:57:20 +03:00
if ( aspeed_clk_is_enabled ( hw ) ) {
spin_unlock_irqrestore ( gate - > lock , flags ) ;
return 0 ;
}
2017-12-22 05:45:21 +03:00
if ( gate - > reset_idx > = 0 ) {
/* Put IP in reset */
regmap_update_bits ( gate - > map , ASPEED_RESET_CTRL , rst , rst ) ;
/* Delay 100us */
udelay ( 100 ) ;
}
/* Enable clock */
2018-01-12 08:48:01 +03:00
enval = ( gate - > flags & CLK_GATE_SET_TO_DISABLE ) ? 0 : clk ;
regmap_update_bits ( gate - > map , ASPEED_CLK_STOP_CTRL , clk , enval ) ;
2017-12-22 05:45:21 +03:00
if ( gate - > reset_idx > = 0 ) {
/* A delay of 10ms is specified by the ASPEED docs */
mdelay ( 10 ) ;
/* Take IP out of reset */
regmap_update_bits ( gate - > map , ASPEED_RESET_CTRL , rst , 0 ) ;
}
spin_unlock_irqrestore ( gate - > lock , flags ) ;
return 0 ;
}
static void aspeed_clk_disable ( struct clk_hw * hw )
{
struct aspeed_clk_gate * gate = to_aspeed_clk_gate ( hw ) ;
unsigned long flags ;
u32 clk = BIT ( gate - > clock_idx ) ;
2018-01-12 08:48:01 +03:00
u32 enval ;
2017-12-22 05:45:21 +03:00
spin_lock_irqsave ( gate - > lock , flags ) ;
2018-01-12 08:48:01 +03:00
enval = ( gate - > flags & CLK_GATE_SET_TO_DISABLE ) ? clk : 0 ;
regmap_update_bits ( gate - > map , ASPEED_CLK_STOP_CTRL , clk , enval ) ;
2017-12-22 05:45:21 +03:00
spin_unlock_irqrestore ( gate - > lock , flags ) ;
}
static const struct clk_ops aspeed_clk_gate_ops = {
. enable = aspeed_clk_enable ,
. disable = aspeed_clk_disable ,
. is_enabled = aspeed_clk_is_enabled ,
} ;
2017-12-22 05:45:22 +03:00
static const u8 aspeed_resets [ ] = {
2018-04-27 05:55:47 +03:00
/* SCU04 resets */
2017-12-22 05:45:22 +03:00
[ ASPEED_RESET_XDMA ] = 25 ,
[ ASPEED_RESET_MCTP ] = 24 ,
[ ASPEED_RESET_ADC ] = 23 ,
[ ASPEED_RESET_JTAG_MASTER ] = 22 ,
[ ASPEED_RESET_MIC ] = 18 ,
[ ASPEED_RESET_PWM ] = 9 ,
2018-04-26 20:22:32 +03:00
[ ASPEED_RESET_PECI ] = 10 ,
2017-12-22 05:45:22 +03:00
[ ASPEED_RESET_I2C ] = 2 ,
[ ASPEED_RESET_AHB ] = 1 ,
2018-04-27 05:55:47 +03:00
/*
* SCUD4 resets start at an offset to separate them from
* the SCU04 resets .
*/
[ ASPEED_RESET_CRT1 ] = ASPEED_RESET2_OFFSET + 5 ,
2017-12-22 05:45:22 +03:00
} ;
static int aspeed_reset_deassert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
struct aspeed_reset * ar = to_aspeed_reset ( rcdev ) ;
2018-04-27 05:55:47 +03:00
u32 reg = ASPEED_RESET_CTRL ;
u32 bit = aspeed_resets [ id ] ;
2017-12-22 05:45:22 +03:00
2018-04-27 05:55:47 +03:00
if ( bit > = ASPEED_RESET2_OFFSET ) {
bit - = ASPEED_RESET2_OFFSET ;
reg = ASPEED_RESET_CTRL2 ;
}
2017-12-22 05:45:22 +03:00
2018-04-27 05:55:47 +03:00
return regmap_update_bits ( ar - > map , reg , BIT ( bit ) , 0 ) ;
2017-12-22 05:45:22 +03:00
}
static int aspeed_reset_assert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
struct aspeed_reset * ar = to_aspeed_reset ( rcdev ) ;
2018-04-27 05:55:47 +03:00
u32 reg = ASPEED_RESET_CTRL ;
u32 bit = aspeed_resets [ id ] ;
2017-12-22 05:45:22 +03:00
2018-04-27 05:55:47 +03:00
if ( bit > = ASPEED_RESET2_OFFSET ) {
bit - = ASPEED_RESET2_OFFSET ;
reg = ASPEED_RESET_CTRL2 ;
}
2017-12-22 05:45:22 +03:00
2018-04-27 05:55:47 +03:00
return regmap_update_bits ( ar - > map , reg , BIT ( bit ) , BIT ( bit ) ) ;
2017-12-22 05:45:22 +03:00
}
static int aspeed_reset_status ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
struct aspeed_reset * ar = to_aspeed_reset ( rcdev ) ;
2018-04-27 05:55:47 +03:00
u32 reg = ASPEED_RESET_CTRL ;
u32 bit = aspeed_resets [ id ] ;
int ret , val ;
if ( bit > = ASPEED_RESET2_OFFSET ) {
bit - = ASPEED_RESET2_OFFSET ;
reg = ASPEED_RESET_CTRL2 ;
}
2017-12-22 05:45:22 +03:00
2018-04-27 05:55:47 +03:00
ret = regmap_read ( ar - > map , reg , & val ) ;
2017-12-22 05:45:22 +03:00
if ( ret )
return ret ;
2018-04-27 05:55:47 +03:00
return ! ! ( val & BIT ( bit ) ) ;
2017-12-22 05:45:22 +03:00
}
static const struct reset_control_ops aspeed_reset_ops = {
. assert = aspeed_reset_assert ,
. deassert = aspeed_reset_deassert ,
. status = aspeed_reset_status ,
} ;
2017-12-22 05:45:21 +03:00
static struct clk_hw * aspeed_clk_hw_register_gate ( struct device * dev ,
const char * name , const char * parent_name , unsigned long flags ,
struct regmap * map , u8 clock_idx , u8 reset_idx ,
u8 clk_gate_flags , spinlock_t * lock )
{
struct aspeed_clk_gate * gate ;
struct clk_init_data init ;
struct clk_hw * hw ;
int ret ;
gate = kzalloc ( sizeof ( * gate ) , GFP_KERNEL ) ;
if ( ! gate )
return ERR_PTR ( - ENOMEM ) ;
init . name = name ;
init . ops = & aspeed_clk_gate_ops ;
init . flags = flags ;
init . parent_names = parent_name ? & parent_name : NULL ;
init . num_parents = parent_name ? 1 : 0 ;
gate - > map = map ;
gate - > clock_idx = clock_idx ;
gate - > reset_idx = reset_idx ;
gate - > flags = clk_gate_flags ;
gate - > lock = lock ;
gate - > hw . init = & init ;
hw = & gate - > hw ;
ret = clk_hw_register ( dev , hw ) ;
if ( ret ) {
kfree ( gate ) ;
hw = ERR_PTR ( ret ) ;
}
return hw ;
}
2017-12-22 05:45:20 +03:00
static int aspeed_clk_probe ( struct platform_device * pdev )
{
const struct aspeed_clk_soc_data * soc_data ;
struct device * dev = & pdev - > dev ;
2017-12-22 05:45:22 +03:00
struct aspeed_reset * ar ;
2017-12-22 05:45:20 +03:00
struct regmap * map ;
struct clk_hw * hw ;
u32 val , rate ;
2017-12-22 05:45:22 +03:00
int i , ret ;
2017-12-22 05:45:20 +03:00
map = syscon_node_to_regmap ( dev - > of_node ) ;
if ( IS_ERR ( map ) ) {
dev_err ( dev , " no syscon regmap \n " ) ;
return PTR_ERR ( map ) ;
}
2017-12-22 05:45:22 +03:00
ar = devm_kzalloc ( dev , sizeof ( * ar ) , GFP_KERNEL ) ;
if ( ! ar )
return - ENOMEM ;
ar - > map = map ;
ar - > rcdev . owner = THIS_MODULE ;
ar - > rcdev . nr_resets = ARRAY_SIZE ( aspeed_resets ) ;
ar - > rcdev . ops = & aspeed_reset_ops ;
ar - > rcdev . of_node = dev - > of_node ;
ret = devm_reset_controller_register ( dev , & ar - > rcdev ) ;
if ( ret ) {
dev_err ( dev , " could not register reset controller \n " ) ;
return ret ;
}
2017-12-22 05:45:20 +03:00
/* SoC generations share common layouts but have different divisors */
soc_data = of_device_get_match_data ( dev ) ;
if ( ! soc_data ) {
dev_err ( dev , " no match data for platform \n " ) ;
return - EINVAL ;
}
/* UART clock div13 setting */
regmap_read ( map , ASPEED_MISC_CTRL , & val ) ;
if ( val & UART_DIV13_EN )
rate = 24000000 / 13 ;
else
rate = 24000000 ;
/* TODO: Find the parent data for the uart clock */
hw = clk_hw_register_fixed_rate ( dev , " uart " , NULL , 0 , rate ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_UART ] = hw ;
/*
* Memory controller ( M - PLL ) PLL . This clock is configured by the
* bootloader , and is exposed to Linux as a read - only clock rate .
*/
regmap_read ( map , ASPEED_MPLL_PARAM , & val ) ;
hw = soc_data - > calc_pll ( " mpll " , val ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_MPLL ] = hw ;
2019-07-10 17:10:09 +03:00
/* SD/SDIO clock divider and gate */
hw = clk_hw_register_gate ( dev , " sd_extclk_gate " , " hpll " , 0 ,
scu_base + ASPEED_CLK_SELECTION , 15 , 0 ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
hw = clk_hw_register_divider_table ( dev , " sd_extclk " , " sd_extclk_gate " ,
0 , scu_base + ASPEED_CLK_SELECTION , 12 , 3 , 0 ,
2017-12-22 05:45:20 +03:00
soc_data - > div_table ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_SDIO ] = hw ;
/* MAC AHB bus clock divider */
hw = clk_hw_register_divider_table ( dev , " mac " , " hpll " , 0 ,
scu_base + ASPEED_CLK_SELECTION , 16 , 3 , 0 ,
soc_data - > mac_div_table ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_MAC ] = hw ;
2019-10-10 05:06:55 +03:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " aspeed,ast2500-scu " ) ) {
/* RMII 50MHz RCLK */
hw = clk_hw_register_fixed_rate ( dev , " mac12rclk " , " hpll " , 0 ,
50000000 ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
/* RMII1 50MHz (RCLK) output enable */
hw = clk_hw_register_gate ( dev , " mac1rclk " , " mac12rclk " , 0 ,
scu_base + ASPEED_MAC_CLK_DLY , 29 , 0 ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_MAC1RCLK ] = hw ;
/* RMII2 50MHz (RCLK) output enable */
hw = clk_hw_register_gate ( dev , " mac2rclk " , " mac12rclk " , 0 ,
scu_base + ASPEED_MAC_CLK_DLY , 30 , 0 ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_MAC2RCLK ] = hw ;
}
2017-12-22 05:45:20 +03:00
/* LPC Host (LHCLK) clock divider */
hw = clk_hw_register_divider_table ( dev , " lhclk " , " hpll " , 0 ,
scu_base + ASPEED_CLK_SELECTION , 20 , 3 , 0 ,
soc_data - > div_table ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_LHCLK ] = hw ;
/* P-Bus (BCLK) clock divider */
hw = clk_hw_register_divider_table ( dev , " bclk " , " hpll " , 0 ,
scu_base + ASPEED_CLK_SELECTION_2 , 0 , 2 , 0 ,
soc_data - > div_table ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_BCLK ] = hw ;
2018-05-18 11:57:02 +03:00
/* Fixed 24MHz clock */
hw = clk_hw_register_fixed_rate ( NULL , " fixed-24m " , " clkin " ,
0 , 24000000 ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_24M ] = hw ;
2019-04-02 21:25:03 +03:00
hw = clk_hw_register_mux ( dev , " eclk-mux " , eclk_parent_names ,
ARRAY_SIZE ( eclk_parent_names ) , 0 ,
scu_base + ASPEED_CLK_SELECTION , 2 , 0x3 , 0 ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_ECLK_MUX ] = hw ;
hw = clk_hw_register_divider_table ( dev , " eclk " , " eclk-mux " , 0 ,
scu_base + ASPEED_CLK_SELECTION , 28 ,
3 , 0 , soc_data - > eclk_div_table ,
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_ECLK ] = hw ;
2017-12-22 05:45:21 +03:00
/*
* TODO : There are a number of clocks that not included in this driver
* as more information is required :
* D2 - PLL
* D - PLL
* YCLK
* RGMII
* RMII
* UART [ 1. .5 ] clock source mux
*/
for ( i = 0 ; i < ARRAY_SIZE ( aspeed_gates ) ; i + + ) {
const struct aspeed_gate_data * gd = & aspeed_gates [ i ] ;
2018-01-12 08:48:01 +03:00
u32 gate_flags ;
2017-12-22 05:45:21 +03:00
2018-01-12 08:48:01 +03:00
/* Special case: the USB port 1 clock (bit 14) is always
* working the opposite way from the other ones .
*/
gate_flags = ( gd - > clock_idx = = 14 ) ? 0 : CLK_GATE_SET_TO_DISABLE ;
2017-12-22 05:45:21 +03:00
hw = aspeed_clk_hw_register_gate ( dev ,
gd - > name ,
gd - > parent_name ,
gd - > flags ,
map ,
gd - > clock_idx ,
gd - > reset_idx ,
2018-01-12 08:48:01 +03:00
gate_flags ,
2017-12-22 05:45:21 +03:00
& aspeed_clk_lock ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
aspeed_clk_data - > hws [ i ] = hw ;
}
2017-12-22 05:45:20 +03:00
return 0 ;
} ;
static const struct of_device_id aspeed_clk_dt_ids [ ] = {
{ . compatible = " aspeed,ast2400-scu " , . data = & ast2400_data } ,
{ . compatible = " aspeed,ast2500-scu " , . data = & ast2500_data } ,
{ }
} ;
static struct platform_driver aspeed_clk_driver = {
. probe = aspeed_clk_probe ,
. driver = {
. name = " aspeed-clk " ,
. of_match_table = aspeed_clk_dt_ids ,
. suppress_bind_attrs = true ,
} ,
} ;
builtin_platform_driver ( aspeed_clk_driver ) ;
2017-12-22 05:45:19 +03:00
static void __init aspeed_ast2400_cc ( struct regmap * map )
{
struct clk_hw * hw ;
2018-06-29 02:15:40 +03:00
u32 val , div , clkin , hpll ;
const u16 hpll_rates [ ] [ 4 ] = {
{ 384 , 360 , 336 , 408 } ,
{ 400 , 375 , 350 , 425 } ,
} ;
int rate ;
2017-12-22 05:45:19 +03:00
/*
* CLKIN is the crystal oscillator , 24 , 48 or 25 MHz selected by
* strapping
*/
regmap_read ( map , ASPEED_STRAP , & val ) ;
2018-06-29 02:15:40 +03:00
rate = ( val > > 8 ) & 3 ;
if ( val & CLKIN_25MHZ_EN ) {
clkin = 25000000 ;
hpll = hpll_rates [ 1 ] [ rate ] ;
} else if ( val & AST2400_CLK_SOURCE_SEL ) {
clkin = 48000000 ;
hpll = hpll_rates [ 0 ] [ rate ] ;
} else {
clkin = 24000000 ;
hpll = hpll_rates [ 0 ] [ rate ] ;
}
hw = clk_hw_register_fixed_rate ( NULL , " clkin " , NULL , 0 , clkin ) ;
pr_debug ( " clkin @%u MHz \n " , clkin / 1000000 ) ;
2017-12-22 05:45:19 +03:00
/*
* High - speed PLL clock derived from the crystal . This the CPU clock ,
2018-06-29 02:15:40 +03:00
* and we assume that it is enabled . It can be configured through the
* HPLL_PARAM register , or set to a specified frequency by strapping .
2017-12-22 05:45:19 +03:00
*/
regmap_read ( map , ASPEED_HPLL_PARAM , & val ) ;
2018-06-29 02:15:40 +03:00
if ( val & AST2400_HPLL_PROGRAMMED )
hw = aspeed_ast2400_calc_pll ( " hpll " , val ) ;
else
hw = clk_hw_register_fixed_rate ( NULL , " hpll " , " clkin " , 0 ,
hpll * 1000000 ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_HPLL ] = hw ;
2017-12-22 05:45:19 +03:00
/*
* Strap bits 11 : 10 define the CPU / AHB clock frequency ratio ( aka HCLK )
* 00 : Select CPU : AHB = 1 : 1
* 01 : Select CPU : AHB = 2 : 1
* 10 : Select CPU : AHB = 4 : 1
* 11 : Select CPU : AHB = 3 : 1
*/
regmap_read ( map , ASPEED_STRAP , & val ) ;
val = ( val > > 10 ) & 0x3 ;
div = val + 1 ;
if ( div = = 3 )
div = 4 ;
else if ( div = = 4 )
div = 3 ;
hw = clk_hw_register_fixed_factor ( NULL , " ahb " , " hpll " , 0 , 1 , div ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_AHB ] = hw ;
/* APB clock clock selection register SCU08 (aka PCLK) */
hw = clk_hw_register_divider_table ( NULL , " apb " , " hpll " , 0 ,
scu_base + ASPEED_CLK_SELECTION , 23 , 3 , 0 ,
ast2400_div_table ,
& aspeed_clk_lock ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_APB ] = hw ;
}
static void __init aspeed_ast2500_cc ( struct regmap * map )
{
struct clk_hw * hw ;
u32 val , freq , div ;
/* CLKIN is the crystal oscillator, 24 or 25MHz selected by strapping */
regmap_read ( map , ASPEED_STRAP , & val ) ;
if ( val & CLKIN_25MHZ_EN )
freq = 25000000 ;
else
freq = 24000000 ;
hw = clk_hw_register_fixed_rate ( NULL , " clkin " , NULL , 0 , freq ) ;
pr_debug ( " clkin @%u MHz \n " , freq / 1000000 ) ;
/*
* High - speed PLL clock derived from the crystal . This the CPU clock ,
* and we assume that it is enabled
*/
regmap_read ( map , ASPEED_HPLL_PARAM , & val ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_HPLL ] = aspeed_ast2500_calc_pll ( " hpll " , val ) ;
/* Strap bits 11:9 define the AXI/AHB clock frequency ratio (aka HCLK)*/
regmap_read ( map , ASPEED_STRAP , & val ) ;
val = ( val > > 9 ) & 0x7 ;
WARN ( val = = 0 , " strapping is zero: cannot determine ahb clock " ) ;
div = 2 * ( val + 1 ) ;
hw = clk_hw_register_fixed_factor ( NULL , " ahb " , " hpll " , 0 , 1 , div ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_AHB ] = hw ;
/* APB clock clock selection register SCU08 (aka PCLK) */
regmap_read ( map , ASPEED_CLK_SELECTION , & val ) ;
val = ( val > > 23 ) & 0x7 ;
div = 4 * ( val + 1 ) ;
hw = clk_hw_register_fixed_factor ( NULL , " apb " , " hpll " , 0 , 1 , div ) ;
aspeed_clk_data - > hws [ ASPEED_CLK_APB ] = hw ;
} ;
2017-12-22 05:45:18 +03:00
static void __init aspeed_cc_init ( struct device_node * np )
{
struct regmap * map ;
u32 val ;
int ret ;
int i ;
scu_base = of_iomap ( np , 0 ) ;
2018-01-05 04:41:01 +03:00
if ( ! scu_base )
2017-12-22 05:45:18 +03:00
return ;
treewide: Use struct_size() for kmalloc()-family
One of the more common cases of allocation size calculations is finding
the size of a structure that has a zero-sized array at the end, along
with memory for some number of elements for that array. For example:
struct foo {
int stuff;
void *entry[];
};
instance = kmalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL);
Instead of leaving these open-coded and prone to type mistakes, we can
now use the new struct_size() helper:
instance = kmalloc(struct_size(instance, entry, count), GFP_KERNEL);
This patch makes the changes for kmalloc()-family (and kvmalloc()-family)
uses. It was done via automatic conversion with manual review for the
"CHECKME" non-standard cases noted below, using the following Coccinelle
script:
// pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len *
// sizeof *pkey_cache->table, GFP_KERNEL);
@@
identifier alloc =~ "kmalloc|kzalloc|kvmalloc|kvzalloc";
expression GFP;
identifier VAR, ELEMENT;
expression COUNT;
@@
- alloc(sizeof(*VAR) + COUNT * sizeof(*VAR->ELEMENT), GFP)
+ alloc(struct_size(VAR, ELEMENT, COUNT), GFP)
// mr = kzalloc(sizeof(*mr) + m * sizeof(mr->map[0]), GFP_KERNEL);
@@
identifier alloc =~ "kmalloc|kzalloc|kvmalloc|kvzalloc";
expression GFP;
identifier VAR, ELEMENT;
expression COUNT;
@@
- alloc(sizeof(*VAR) + COUNT * sizeof(VAR->ELEMENT[0]), GFP)
+ alloc(struct_size(VAR, ELEMENT, COUNT), GFP)
// Same pattern, but can't trivially locate the trailing element name,
// or variable name.
@@
identifier alloc =~ "kmalloc|kzalloc|kvmalloc|kvzalloc";
expression GFP;
expression SOMETHING, COUNT, ELEMENT;
@@
- alloc(sizeof(SOMETHING) + COUNT * sizeof(ELEMENT), GFP)
+ alloc(CHECKME_struct_size(&SOMETHING, ELEMENT, COUNT), GFP)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-05-08 23:45:50 +03:00
aspeed_clk_data = kzalloc ( struct_size ( aspeed_clk_data , hws ,
ASPEED_NUM_CLKS ) ,
GFP_KERNEL ) ;
2017-12-22 05:45:18 +03:00
if ( ! aspeed_clk_data )
return ;
/*
* This way all clocks fetched before the platform device probes ,
* except those we assign here for early use , will be deferred .
*/
for ( i = 0 ; i < ASPEED_NUM_CLKS ; i + + )
aspeed_clk_data - > hws [ i ] = ERR_PTR ( - EPROBE_DEFER ) ;
map = syscon_node_to_regmap ( np ) ;
if ( IS_ERR ( map ) ) {
pr_err ( " no syscon regmap \n " ) ;
return ;
}
/*
* We check that the regmap works on this very first access ,
* but as this is an MMIO - backed regmap , subsequent regmap
* access is not going to fail and we skip error checks from
* this point .
*/
ret = regmap_read ( map , ASPEED_STRAP , & val ) ;
if ( ret ) {
pr_err ( " failed to read strapping register \n " ) ;
return ;
}
2017-12-22 05:45:19 +03:00
if ( of_device_is_compatible ( np , " aspeed,ast2400-scu " ) )
aspeed_ast2400_cc ( map ) ;
else if ( of_device_is_compatible ( np , " aspeed,ast2500-scu " ) )
aspeed_ast2500_cc ( map ) ;
else
pr_err ( " unknown platform, failed to add clocks \n " ) ;
2017-12-22 05:45:18 +03:00
aspeed_clk_data - > num = ASPEED_NUM_CLKS ;
ret = of_clk_add_hw_provider ( np , of_clk_hw_onecell_get , aspeed_clk_data ) ;
if ( ret )
pr_err ( " failed to add DT provider: %d \n " , ret ) ;
} ;
CLK_OF_DECLARE_DRIVER ( aspeed_cc_g5 , " aspeed,ast2500-scu " , aspeed_cc_init ) ;
CLK_OF_DECLARE_DRIVER ( aspeed_cc_g4 , " aspeed,ast2400-scu " , aspeed_cc_init ) ;