-
-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathbacklight.zig
More file actions
244 lines (213 loc) · 8.61 KB
/
backlight.zig
File metadata and controls
244 lines (213 loc) · 8.61 KB
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
//***************************************************************************
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership. The
// ASF licenses this file to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance with the
// License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
//***************************************************************************
//! PinePhone Display Backlight Driver for Apache NuttX RTOS
//! See https://lupyuen.github.io/articles/de#appendix-display-backlight
//! "A64 Page ???" refers to Allwinner A64 User Manual: https://github.com/lupyuen/pinephone-nuttx/releases/download/doc/Allwinner_A64_User_Manual_V1.1.pdf
/// Import the Zig Standard Library
const std = @import("std");
/// Import NuttX Functions from C
const c = @cImport({
// NuttX Defines
@cDefine("__NuttX__", "");
@cDefine("NDEBUG", "");
@cDefine("FAR", "");
// NuttX Header Files
@cInclude("arch/types.h");
@cInclude("../../nuttx/include/limits.h");
@cInclude("nuttx/config.h");
@cInclude("inttypes.h");
@cInclude("unistd.h");
@cInclude("stdlib.h");
@cInclude("stdio.h");
});
/// PIO Base Address (CPUx-PORT) (A64 Page 376)
const PIO_BASE_ADDRESS = 0x01C2_0800;
/// PWM Base Address (CPUx-PWM?) (A64 Page 194)
const PWM_BASE_ADDRESS = 0x01C2_1400;
/// R_PIO Base Address (CPUs-PORT) (A64 Page 410)
const R_PIO_BASE_ADDRESS = 0x01F0_2C00;
/// R_PWM Base Address (CPUs-PWM?) (CPUs Domain, A64 Page 256)
const R_PWM_BASE_ADDRESS = 0x01F0_3800;
/// Turn on PinePhone Display Backlight.
/// Based on https://lupyuen.github.io/articles/de#appendix-display-backlight
pub export fn backlight_enable(
percent: u32 // Percent brightness
) void {
debug("backlight_enable: start, percent={}", .{ percent });
defer { debug("backlight_enable: end", .{}); }
// Configure PL10 for PWM
// Register PL_CFG1_REG (Port L Configure Register 1)
// At R_PIO Offset 4 (A64 Page 412)
// Set PL10_SELECT (Bits 8 to 10) to 2 (S_PWM)
debug("Configure PL10 for PWM", .{});
const PL_CFG1_REG = R_PIO_BASE_ADDRESS + 4;
comptime { assert(PL_CFG1_REG == 0x1f02c04); }
modreg32(2 << 8, 0b111 << 8, PL_CFG1_REG);
// Disable R_PWM (Undocumented)
// Register R_PWM_CTRL_REG? (R_PWM Control Register?)
// At R_PWM Offset 0 (A64 Page 194)
// Set SCLK_CH0_GATING (Bit 6) to 0 (Mask)
debug("Disable R_PWM", .{});
const R_PWM_CTRL_REG = R_PWM_BASE_ADDRESS + 0;
comptime { assert(R_PWM_CTRL_REG == 0x1f03800); }
modreg32(0, 1 << 6, R_PWM_CTRL_REG);
// Configure R_PWM Period (Undocumented)
// Register R_PWM_CH0_PERIOD? (R_PWM Channel 0 Period Register?)
// At R_PWM Offset 4 (A64 Page 195)
// PWM_CH0_ENTIRE_CYS (Upper 16 Bits) = Period (0x4af)
// PWM_CH0_ENTIRE_ACT_CYS (Lower 16 Bits) = Period * Percent / 100 (0x0437)
// Period = 1199 (Cycles of PWM Clock)
// Percent = 90 (90% Brightness)
debug("Configure R_PWM Period", .{});
const R_PWM_CH0_PERIOD = R_PWM_BASE_ADDRESS + 4;
comptime { assert(R_PWM_CH0_PERIOD == 0x1f03804); }
const PERIOD = 1199;
const PERCENT = 90;
const PWM_CH0_ENTIRE_CYS: u32 = PERIOD << 16;
const PWM_CH0_ENTIRE_ACT_CYS: u16 = PERIOD * PERCENT / 100;
const val = PWM_CH0_ENTIRE_CYS
| PWM_CH0_ENTIRE_ACT_CYS;
comptime { assert(val == 0x4af0437); }
putreg32(val, R_PWM_CH0_PERIOD);
assert(percent == PERCENT);
// Enable R_PWM (Undocumented)
// Register R_PWM_CTRL_REG? (R_PWM Control Register?)
// At R_PWM Offset 0 (A64 Page 194)
// Set SCLK_CH0_GATING (Bit 6) to 1 (Pass)
// Set PWM_CH0_EN (Bit 4) to 1 (Enable)
// Set PWM_CH0_PRESCAL (Bits 0 to 3) to 0b1111 (Prescalar 1)
debug("Enable R_PWM", .{});
comptime { assert(R_PWM_CTRL_REG == 0x1f03800); }
const SCLK_CH0_GATING: u7 = 1 << 6;
const PWM_CH0_EN: u5 = 1 << 4;
const PWM_CH0_PRESCAL: u4 = 0b1111 << 0;
const ctrl = SCLK_CH0_GATING
| PWM_CH0_EN
| PWM_CH0_PRESCAL;
comptime { assert(ctrl == 0x5f); }
putreg32(ctrl, R_PWM_CTRL_REG);
// Configure PH10 for Output
// Register PH_CFG1_REG (PH Configure Register 1)
// At PIO Offset 0x100 (A64 Page 401)
// Set PH10_SELECT (Bits 8 to 10) to 1 (Output)
debug("Configure PH10 for Output", .{});
const PH_CFG1_REG = PIO_BASE_ADDRESS + 0x100;
comptime { assert(PH_CFG1_REG == 0x1c20900); }
const PH10_SELECT: u11 = 0b001 << 8;
const PH10_MASK: u11 = 0b111 << 8;
comptime { assert(PH10_SELECT == 0x100); }
comptime { assert(PH10_MASK == 0x700); }
modreg32(PH10_SELECT, PH10_MASK, PH_CFG1_REG);
// Set PH10 to High
// Register PH_DATA_REG (PH Data Register)
// At PIO Offset 0x10C (A64 Page 403)
// Set PH10 (Bit 10) to 1 (High)
debug("Set PH10 to High", .{});
const PH_DATA_REG = PIO_BASE_ADDRESS + 0x10C;
comptime { assert(PH_DATA_REG == 0x1c2090c); }
const PH10: u11 = 1 << 10;
modreg32(PH10, PH10, PH_DATA_REG);
}
/// Modify the specified bits in a memory mapped register.
/// Note: Parameters are different from modifyreg32
/// Based on https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_arch.h#L473
fn modreg32(
comptime val: u32, // Bits to set, like (1 << bit)
comptime mask: u32, // Bits to clear, like (1 << bit)
addr: u64 // Address to modify
) void {
comptime { assert(val & mask == val); }
debug(" *0x{x}: clear 0x{x}, set 0x{x}", .{ addr, mask, val & mask });
putreg32(
(getreg32(addr) & ~(mask))
| ((val) & (mask)),
(addr)
);
}
/// Get the 32-bit value at the address
fn getreg32(addr: u64) u32 {
const ptr = @intToPtr(*const volatile u32, addr);
return ptr.*;
}
/// Set the 32-bit value at the address
fn putreg32(val: u32, addr: u64) void {
if (enableLog) { debug(" *0x{x} = 0x{x}", .{ addr, val }); }
const ptr = @intToPtr(*volatile u32, addr);
ptr.* = val;
}
/// Set to False to disable log
var enableLog = true;
///////////////////////////////////////////////////////////////////////////////
// Panic Handler
/// Called by Zig when it hits a Panic. We print the Panic Message, Stack Trace and halt. See
/// https://andrewkelley.me/post/zig-stack-traces-kernel-panic-bare-bones-os.html
/// https://github.com/ziglang/zig/blob/master/lib/std/builtin.zig#L763-L847
pub fn panic(
message: []const u8,
_stack_trace: ?*std.builtin.StackTrace
) noreturn {
// Print the Panic Message
_ = _stack_trace;
_ = puts("\n!ZIG PANIC!");
_ = puts(@ptrCast([*c]const u8, message));
// Print the Stack Trace
_ = puts("Stack Trace:");
var it = std.debug.StackIterator.init(@returnAddress(), null);
while (it.next()) |return_address| {
_ = printf("%p\n", return_address);
}
// Halt
c.exit(1);
}
///////////////////////////////////////////////////////////////////////////////
// Logging
/// Called by Zig for `std.log.debug`, `std.log.info`, `std.log.err`, ...
/// https://gist.github.com/leecannon/d6f5d7e5af5881c466161270347ce84d
pub fn log(
comptime _message_level: std.log.Level,
comptime _scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: anytype,
) void {
_ = _message_level;
_ = _scope;
// Format the message
var buf: [100]u8 = undefined; // Limit to 100 chars
var slice = std.fmt.bufPrint(&buf, format, args)
catch { _ = puts("*** log error: buf too small"); return; };
// Terminate the formatted message with a null
var buf2: [buf.len + 1 : 0]u8 = undefined;
std.mem.copy(
u8,
buf2[0..slice.len],
slice[0..slice.len]
);
buf2[slice.len] = 0;
// Print the formatted message
_ = puts(&buf2);
}
///////////////////////////////////////////////////////////////////////////////
// Imported Functions and Variables
/// For safety, we import these functions ourselves to enforce Null-Terminated Strings.
/// We changed `[*c]const u8` to `[*:0]const u8`
extern fn printf(format: [*:0]const u8, ...) c_int;
extern fn puts(str: [*:0]const u8) c_int;
/// Aliases for Zig Standard Library
const assert = std.debug.assert;
const debug = std.log.debug;