blob: bb677daa8a1b305dbf20248edc11224a9ada155a [file] [log] [blame]
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
7
8#include <backlight.h>
9#include <common.h>
10#include <dm.h>
11#include <i2c.h>
12#include <log.h>
13#include <linux/delay.h>
14#include <linux/err.h>
15
16#include <asm/io.h>
17#include <asm/gpio.h>
18#include <asm/arch/display.h>
19
20#define TEGRA_DISPLAY_A_BASE 0x54200000
21#define TEGRA_DISPLAY_B_BASE 0x54240000
22
23#define TEGRA_PWM_BL_MIN_BRIGHTNESS 0x10
24#define TEGRA_PWM_BL_MAX_BRIGHTNESS 0xFF
25
26#define TEGRA_PWM_BL_PERIOD 0xFF
27#define TEGRA_PWM_BL_CLK_DIV 0x14
28#define TEGRA_PWM_BL_CLK_SELECT 0x00
29
30#define PM_PERIOD_SHIFT 18
31#define PM_CLK_DIVIDER_SHIFT 4
32
33#define TEGRA_PWM_PM0 0
34#define TEGRA_PWM_PM1 1
35
36struct tegra_pwm_backlight_priv {
37 struct dc_ctlr *dc; /* Display controller regmap */
38
39 u32 pwm_source;
40 u32 period;
41 u32 clk_div;
42 u32 clk_select;
43 u32 dft_brightness;
44};
45
46static int tegra_pwm_backlight_set_brightness(struct udevice *dev, int percent)
47{
48 struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
49 struct dc_cmd_reg *cmd = &priv->dc->cmd;
50 struct dc_com_reg *com = &priv->dc->com;
51 unsigned int ctrl;
52 unsigned long out_sel;
53 unsigned long cmd_state;
54
55 if (percent == BACKLIGHT_DEFAULT)
56 percent = priv->dft_brightness;
57
58 if (percent < TEGRA_PWM_BL_MIN_BRIGHTNESS)
59 percent = TEGRA_PWM_BL_MIN_BRIGHTNESS;
60
61 if (percent > TEGRA_PWM_BL_MAX_BRIGHTNESS)
62 percent = TEGRA_PWM_BL_MAX_BRIGHTNESS;
63
64 ctrl = ((priv->period << PM_PERIOD_SHIFT) |
65 (priv->clk_div << PM_CLK_DIVIDER_SHIFT) |
66 priv->clk_select);
67
68 /* The new value should be effected immediately */
69 cmd_state = readl(&cmd->state_access);
70 writel((cmd_state | (1 << 2)), &cmd->state_access);
71
72 switch (priv->pwm_source) {
73 case TEGRA_PWM_PM0:
74 /* Select the LM0 on PM0 */
75 out_sel = readl(&com->pin_output_sel[5]);
76 out_sel &= ~(7 << 0);
77 out_sel |= (3 << 0);
78 writel(out_sel, &com->pin_output_sel[5]);
79 writel(ctrl, &com->pm0_ctrl);
80 writel(percent, &com->pm0_duty_cycle);
81 break;
82 case TEGRA_PWM_PM1:
83 /* Select the LM1 on PM1 */
84 out_sel = readl(&com->pin_output_sel[5]);
85 out_sel &= ~(7 << 4);
86 out_sel |= (3 << 4);
87 writel(out_sel, &com->pin_output_sel[5]);
88 writel(ctrl, &com->pm1_ctrl);
89 writel(percent, &com->pm1_duty_cycle);
90 break;
91 default:
92 break;
93 }
94
95 writel(cmd_state, &cmd->state_access);
96 return 0;
97}
98
99static int tegra_pwm_backlight_enable(struct udevice *dev)
100{
101 struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
102
103 return tegra_pwm_backlight_set_brightness(dev, priv->dft_brightness);
104}
105
106static int tegra_pwm_backlight_probe(struct udevice *dev)
107{
108 struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
109
110 if (dev_read_bool(dev, "nvidia,display-b-base"))
111 priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_B_BASE;
112 else
113 priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_A_BASE;
114
115 if (!priv->dc) {
116 log_err("no display controller address\n");
117 return -EINVAL;
118 }
119
120 priv->pwm_source =
121 dev_read_u32_default(dev, "nvidia,pwm-source",
122 TEGRA_PWM_PM0);
123 priv->period =
124 dev_read_u32_default(dev, "nvidia,period",
125 TEGRA_PWM_BL_PERIOD);
126 priv->clk_div =
127 dev_read_u32_default(dev, "nvidia,clock-div",
128 TEGRA_PWM_BL_CLK_DIV);
129 priv->clk_select =
130 dev_read_u32_default(dev, "nvidia,clock-select",
131 TEGRA_PWM_BL_CLK_SELECT);
132 priv->dft_brightness =
133 dev_read_u32_default(dev, "nvidia,default-brightness",
134 TEGRA_PWM_BL_MAX_BRIGHTNESS);
135
136 return 0;
137}
138
139static const struct backlight_ops tegra_pwm_backlight_ops = {
140 .enable = tegra_pwm_backlight_enable,
141 .set_brightness = tegra_pwm_backlight_set_brightness,
142};
143
144static const struct udevice_id tegra_pwm_backlight_ids[] = {
145 { .compatible = "nvidia,tegra-pwm-backlight" },
146 { }
147};
148
149U_BOOT_DRIVER(tegra_pwm_backlight) = {
150 .name = "tegra_pwm_backlight",
151 .id = UCLASS_PANEL_BACKLIGHT,
152 .of_match = tegra_pwm_backlight_ids,
153 .probe = tegra_pwm_backlight_probe,
154 .ops = &tegra_pwm_backlight_ops,
155 .priv_auto = sizeof(struct tegra_pwm_backlight_priv),
156};