summaryrefslogtreecommitdiff
path: root/src/cpu/samsung/exynos5250/clock.c
diff options
context:
space:
mode:
authorRonald G. Minnich <rminnich@gmail.com>2013-03-04 09:46:31 -0800
committerRonald G. Minnich <rminnich@gmail.com>2013-03-04 19:43:19 +0100
commit026bbda071161ad56822dceaabea03bceefac9ac (patch)
tree4d67044debe77486daa9d56348b3689f90341873 /src/cpu/samsung/exynos5250/clock.c
parent1a43309bf7222fc25e8583d128c9685ec251dd76 (diff)
ARM: remove code that is IMHO a dangerous design
OK, this is tl;dr. But I need to write this in hopes we make sure we don't put code like this into coreboot. Ever. Our excuse in this case is that it was imported, not obviously wrong, and easily changed. It made sense to get it in, make it work, then do a cleanup pass, because changing everything up front is almost impossible to debug. The exynos code has bunch of base register values, e.g. These are base addresses of things that look like a memory-mapped struct. To get these to a pointer, they created the following macro, which creates an inline function. static inline unsigned int samsung_get_base_##device(void) \ { \ return cpu_is_exynos5() ? EXYNOS5_##base : 0; \ } And then invoke it 31 times in a .h file, e.g.: SAMSUNG_BASE(clock, CLOCK_BASE) to create 31 functions. And then use it: struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock(); OK, what's wrong with this? It's easier to ask what's right with it. Answer: nothing. I have a long list of what's wrong, and I may leave some things out, but here goes: 1. the "function" can return a NULL if we're not on exynos5. Most uses of the code don't check the return value. 2. And why would this function be running, if we're not on an exynos5? Why compile it in? 3. Note the cast everywhere a samsung_get_base_xxx is used. The function returns an untyped variable, requiring the *user* to get two things right: the cast, and the function invocation. One can replace that _clock(); with _power(); in the code above, and they will be referencing the wrong registers, and they'll never get an error! We have a C compiler; use it to type data. 4. You're generating 31 functions using cpp each and every time the file is included. The C compiler has to parse these each time. It's not at all like a simple cpp macro which is only generated on use. 5. You can't tags or etags this code 6. In fact, any kind of analysis tool will be unable to do anything with this cpp magic. That's only a partial list. So what's the right way to do it? Just make typed constants, viz: Or, since I expect people will want the lower case function syntax, I've left it that way: Now we've got something that is efficient, and we don't even need to protect with any more. Hence this change. We've got something that is type checked, does not require users to cast on each use, will catch simple programming errors, can be analyzed with standard tools, and builds faster. So if we make a mistake: struct exynos5_clock *clk = samsung_get_base_adc(); We'll see it: src/cpu/samsung/exynos5250/clock.c: In function 'get_pll_clk': src/cpu/samsung/exynos5250/clock.c:183:3: error: initialization from incompatible pointer type [-Werror] which we would not have seen before. As a minor benefit, it shaves most of a second off the compilation. Change-Id: Ie67bc4bc038a8dd1837b977d07332d7d7fd6be1f Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Reviewed-on: http://review.coreboot.org/2582 Tested-by: build bot (Jenkins)
Diffstat (limited to 'src/cpu/samsung/exynos5250/clock.c')
-rw-r--r--src/cpu/samsung/exynos5250/clock.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/src/cpu/samsung/exynos5250/clock.c b/src/cpu/samsung/exynos5250/clock.c
index 115d40dc4b..6b7927287f 100644
--- a/src/cpu/samsung/exynos5250/clock.c
+++ b/src/cpu/samsung/exynos5250/clock.c
@@ -180,7 +180,7 @@ static struct st_epll_con_val epll_div[] = {
unsigned long get_pll_clk(int pllreg)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
unsigned long r, m, p, s, k = 0, mask, fout;
unsigned int freq;
@@ -246,7 +246,7 @@ unsigned long get_pll_clk(int pllreg)
unsigned long clock_get_periph_rate(enum periph_id peripheral)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
unsigned long sclk, sub_clk;
unsigned int src, div, sub_div;
@@ -341,7 +341,7 @@ unsigned long clock_get_periph_rate(enum periph_id peripheral)
unsigned long get_arm_clk(void)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
unsigned long div;
unsigned long armclk;
unsigned int arm_ratio;
@@ -378,7 +378,7 @@ struct arm_clk_ratios *get_arm_clk_ratios(void)
void set_mmc_clk(int dev_index, unsigned int div)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
unsigned int addr;
unsigned int val;
@@ -404,7 +404,7 @@ void set_mmc_clk(int dev_index, unsigned int div)
void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
unsigned shift;
unsigned mask = 0xff;
u32 *reg;
@@ -449,7 +449,7 @@ void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor)
void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
unsigned shift;
unsigned mask = 0xff;
u32 *reg;
@@ -574,7 +574,7 @@ int clock_set_rate(enum periph_id periph_id, unsigned int rate)
int clock_set_mshci(enum periph_id peripheral)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
u32 *addr;
unsigned int clock;
unsigned int tmp;
@@ -635,7 +635,7 @@ int clock_epll_set_rate(unsigned long rate)
unsigned int lockcnt;
unsigned int start;
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
epll_con = readl(&clk->epll_con0);
epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
@@ -685,7 +685,7 @@ int clock_epll_set_rate(unsigned long rate)
void clock_select_i2s_clk_source(void)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
(CLK_SRC_SCLK_EPLL));
@@ -694,7 +694,7 @@ void clock_select_i2s_clk_source(void)
int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
{
struct exynos5_clock *clk =
- (struct exynos5_clock *)samsung_get_base_clock();
+ samsung_get_base_clock();
unsigned int div ;
if ((dst_frq == 0) || (src_frq == 0)) {