lcd_hal.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "hal/lcd_hal.h"
  7. #include "hal/lcd_ll.h"
  8. #include "hal/log.h"
  9. void lcd_hal_init(lcd_hal_context_t *hal, int id)
  10. {
  11. hal->dev = LCD_LL_GET_HW(id);
  12. }
  13. /**
  14. * @brief helper function, calculate the Greatest Common Divisor
  15. * @note gcd(a, b) = gcd(b, a % b)
  16. * @param a bigger value
  17. * @param b smaller value
  18. * @return result of gcd(a, b)
  19. */
  20. __attribute__((always_inline))
  21. static inline uint32_t _gcd(uint32_t a, uint32_t b)
  22. {
  23. uint32_t c = a % b;
  24. while (c != 0) {
  25. a = b;
  26. b = c;
  27. c = a % b;
  28. }
  29. return b;
  30. }
  31. uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, int lcd_clk_flags)
  32. {
  33. // lcd_clk = module_clock_src / (n + b / a)
  34. // pixel_clk = lcd_clk / mo
  35. uint32_t mo = src_freq_hz / expect_pclk_freq_hz / LCD_LL_CLK_FRAC_DIV_N_MAX + 1;
  36. if (mo == 1 && !(lcd_clk_flags & LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK)) {
  37. mo = 2;
  38. }
  39. uint32_t n = src_freq_hz / expect_pclk_freq_hz / mo;
  40. uint32_t a = 0;
  41. uint32_t b = 0;
  42. // delta_hz / expect_pclk_freq_hz <==> b / a
  43. uint32_t delta_hz = src_freq_hz / mo - expect_pclk_freq_hz * n;
  44. // fractional divider
  45. if (delta_hz) {
  46. uint32_t gcd = _gcd(expect_pclk_freq_hz, delta_hz);
  47. a = expect_pclk_freq_hz / gcd;
  48. b = delta_hz / gcd;
  49. // normalize div_a and div_b
  50. uint32_t d = a / LCD_LL_CLK_FRAC_DIV_AB_MAX + 1;
  51. a /= d;
  52. b /= d;
  53. }
  54. HAL_EARLY_LOGD("lcd_hal", "n=%d,a=%d,b=%d,mo=%d", n, a, b, mo);
  55. lcd_ll_set_group_clock_coeff(hal->dev, n, a, b);
  56. lcd_ll_set_pixel_clock_prescale(hal->dev, mo);
  57. if (delta_hz) {
  58. return ((uint64_t)src_freq_hz * a) / (n * a + b) / mo;
  59. } else {
  60. return src_freq_hz / n / mo;
  61. }
  62. }