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