aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/samsung/exynos5250/cpu.h
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/cpu.h
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/cpu.h')
-rw-r--r--src/cpu/samsung/exynos5250/cpu.h85
1 files changed, 32 insertions, 53 deletions
diff --git a/src/cpu/samsung/exynos5250/cpu.h b/src/cpu/samsung/exynos5250/cpu.h
index b8598239ca..772e591cd5 100644
--- a/src/cpu/samsung/exynos5250/cpu.h
+++ b/src/cpu/samsung/exynos5250/cpu.h
@@ -79,59 +79,38 @@
/* Distance between each Trust Zone PC register set */
#define TZPC_BASE_OFFSET 0x10000
-#ifndef __ASSEMBLER__
-
-/* FIXME(dhendrix): cpu_is_exynos5() seems broken atm... */
-#if 0
-#define SAMSUNG_BASE(device, base) \
-static inline unsigned int samsung_get_base_##device(void) \
-{ \
- return cpu_is_exynos5() ? EXYNOS5_##base : 0; \
-}
-#endif
-#define SAMSUNG_BASE(device, base) \
-static inline unsigned int samsung_get_base_##device(void) \
-{ \
- return EXYNOS5_##base; \
-}
-
-SAMSUNG_BASE(adc, ADC_BASE)
-SAMSUNG_BASE(clock, CLOCK_BASE)
-SAMSUNG_BASE(ace_sfr, ACE_SFR_BASE)
-SAMSUNG_BASE(dsim, MIPI_DSI1_BASE)
-SAMSUNG_BASE(disp_ctrl, DISP1_CTRL_BASE)
-SAMSUNG_BASE(fimd, FIMD_BASE)
-SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE)
-SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE)
-SAMSUNG_BASE(gpio_part3, GPIO_PART3_BASE)
-SAMSUNG_BASE(gpio_part4, GPIO_PART4_BASE)
-SAMSUNG_BASE(gpio_part5, GPIO_PART5_BASE)
-SAMSUNG_BASE(gpio_part6, GPIO_PART6_BASE)
-SAMSUNG_BASE(pro_id, PRO_ID)
-
-#ifndef CONFIG_OF_CONTROL
-SAMSUNG_BASE(mmc, MMC_BASE)
-SAMSUNG_BASE(mshci, MSHC_BASE)
-#endif
-
-SAMSUNG_BASE(modem, MODEM_BASE)
-SAMSUNG_BASE(sromc, SROMC_BASE)
-SAMSUNG_BASE(swreset, SWRESET)
-SAMSUNG_BASE(sysreg, SYSREG_BASE)
-SAMSUNG_BASE(timer, PWMTIMER_BASE)
-SAMSUNG_BASE(uart, UART_BASE)
-SAMSUNG_BASE(usb_phy, USBPHY_BASE)
-SAMSUNG_BASE(usb_otg, USBOTG_BASE)
-SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
-SAMSUNG_BASE(power, POWER_BASE)
-SAMSUNG_BASE(i2s, I2S_BASE)
-SAMSUNG_BASE(spi1, SPI1_BASE)
-#ifndef CONFIG_OF_CONTROL
-SAMSUNG_BASE(i2c, I2C_BASE)
-SAMSUNG_BASE(spi, SPI_BASE)
-SAMSUNG_BASE(spi_isp, SPI_ISP_BASE)
-#endif
-#endif
+#define samsung_get_base_adc() ((struct exynos5_adc *)EXYNOS5_ADC_BASE)
+#define samsung_get_base_clock() ((struct exynos5_clock *)EXYNOS5_CLOCK_BASE)
+#define samsung_get_base_ace_sfr() ((struct exynos5_ace_sfr *)EXYNOS5_ACE_SFR_BASE)
+#define samsung_get_base_dsim() ((struct exynos5_dsim *)EXYNOS5_MIPI_DSI1_BASE)
+#define samsung_get_base_disp_ctrl() ((struct exynos5_disp_ctrl *)EXYNOS5_DISP1_CTRL_BASE)
+#define samsung_get_base_fimd() ((struct exynos5_fimd *)EXYNOS5_FIMD_BASE)
+#define samsung_get_base_gpio_part1() ((struct exynos5_gpio_part1 *)EXYNOS5_GPIO_PART1_BASE)
+#define samsung_get_base_gpio_part2() ((struct exynos5_gpio_part2 *)EXYNOS5_GPIO_PART2_BASE)
+#define samsung_get_base_gpio_part3() ((struct exynos5_gpio_part3 *)EXYNOS5_GPIO_PART3_BASE)
+#define samsung_get_base_gpio_part4() ((struct exynos5_gpio_part4 *)EXYNOS5_GPIO_PART4_BASE)
+#define samsung_get_base_gpio_part5() ((struct exynos5_gpio_part5 *)EXYNOS5_GPIO_PART5_BASE)
+#define samsung_get_base_gpio_part6() ((struct exynos5_gpio_part6 *)EXYNOS5_GPIO_PART6_BASE)
+#define samsung_get_base_pro_id() ((struct exynos5_pro_id *)EXYNOS5_PRO_ID)
+
+#define samsung_get_base_mmc() ((struct exynos5_mmc *)EXYNOS5_MMC_BASE)
+#define samsung_get_base_mshci() ((struct exynos5_mshci *)EXYNOS5_MSHC_BASE)
+
+#define samsung_get_base_modem() ((struct exynos5_modem *)EXYNOS5_MODEM_BASE)
+#define samsung_get_base_sromc() ((struct exynos5_sromc *)EXYNOS5_SROMC_BASE)
+#define samsung_get_base_swreset() ((struct exynos5_swreset *)EXYNOS5_SWRESET)
+#define samsung_get_base_sysreg() ((struct exynos5_sysreg *)EXYNOS5_SYSREG_BASE)
+#define samsung_get_base_timer() ((struct s5p_timer *)EXYNOS5_PWMTIMER_BASE)
+#define samsung_get_base_uart() ((struct exynos5_uart *)EXYNOS5_UART_BASE)
+#define samsung_get_base_usb_phy() ((struct exynos5_usb_phy *)EXYNOS5_USBPHY_BASE)
+#define samsung_get_base_usb_otg() ((struct exynos5_usb_otg *)EXYNOS5_USBOTG_BASE)
+#define samsung_get_base_watchdog() ((struct exynos5_watchdog *)EXYNOS5_WATCHDOG_BASE)
+#define samsung_get_base_power() ((struct exynos5_power *)EXYNOS5_POWER_BASE)
+#define samsung_get_base_i2s() ((struct exynos5_i2s *)EXYNOS5_I2S_BASE)
+#define samsung_get_base_spi1() ((struct exynos5_spi1 *)EXYNOS5_SPI1_BASE)
+#define samsung_get_base_i2c() ((struct exynos5_i2c *)EXYNOS5_I2C_BASE)
+#define samsung_get_base_spi() ((struct exynos5_spi *)EXYNOS5_SPI_BASE)
+#define samsung_get_base_spi_isp() ((struct exynos5_spi_isp *)EXYNOS5_SPI_ISP_BASE)
#define EXYNOS5_SPI_NUM_CONTROLLERS 5
#define EXYNOS_I2C_MAX_CONTROLLERS 8