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