Compare commits

...

9 Commits

32 changed files with 18484 additions and 0 deletions

Binary file not shown.

View File

@@ -10,3 +10,8 @@ http://88proof.com/hardware/kindle-20131009.html
### Boot over USB
* https://www.mobileread.com/forums/showthread.php?t=341361#google_vignette
### Regmaps and I2C
* https://github.com/guolibao/Linux-Learning/blob/f5455358f6e968ce57d985ef4d3f31b2ca1b6a8f/regmap/regmap.org#L215
* https://labcsmart.com/controlling-power-with-the-linux-kernel-regulator-framework/

View File

@@ -0,0 +1,333 @@
# Kindle Paperwhite 3 (KPW3) Mainline Linux Port — Project Notes
**Goal:** Get mainline Linux 6.15 booting on a Kindle Paperwhite 3, an
i.MX6SoloLite ("Wario") board, replacing/supplementing the stock Amazon
2009.08-lab126 U-Boot and 3.0.35 kernel.
---
## Hardware Summary
- **SoC:** i.MX6SoloLite, 512MB LPDDR2 (Nanya)
- **Compatible string:** `fsl,imx6sl-wario`, `fsl,imx6sl`
- **UART1:** `0x02020000`, console = `ttymxc0,115200`
- **eMMC:** SEM04G, 3.68GiB
- Kernel device: `mmc0` / `/dev/mmcblk0`
- BIST device: `dev 1`
- Boot partitions: `mmcblk0boot0` / `boot1` (2MB each)
- **I2C0 (kernel `i2c1`):**
- max77696 PMIC @ `0x3c`
- max17135 EPD PMIC @ `0x34` / `0x35`
- Possible RTC @ `0x68`
- **I2C1 (kernel `i2c2`):** Cypress CYTTSP4 touchscreen @ `0x24`
- **WiFi:** Atheros ath6kl over SDIO (`mmc1`)
- **GPIOs:**
- `gpio-82` — watchdog (`wario_wdog`, **active!** — must be serviced or
disabled or the board reboots)
- `gpio-93` — wifi power
- `gpio-113` / `gpio-119` — eMMC 3.3V / 1.8V enables
- `gpio-116` — max77696 IRQ
### eMMC Partition Table (`/dev/mmcblk0`)
| Partition | Size | FS | Notes |
|-----------|--------|-------|--------------------------------|
| p1 | 450MB | ext3 | root — **do not touch** |
| p2 | 64MB | ? | `/usr/share/nh` |
| p3 | 64MB | ? | `/var/local` |
| p4 | 3.1GB | FAT32 | books — expendable, usable space |
### Stock Kernel Cmdline (original Amazon 3.0.35 kernel)
```
rootwait log_pos_goal=0x8fff0000 console=ttymxc0,115200 root=/dev/mmcblk0p1 ro ip=off quiet video=mxcepdcfb:E60,bpp=8,x_mem=3M
```
---
## Stock Bootloader (U-Boot 2009.08-lab126)
This is a **very old, heavily customized** U-Boot. Key facts:
- `bootcmd=bootm 0x41000`**this is a raw byte offset into `/dev/mmcblk0`**,
not an LBA / sector number. The stock `bootm` implementation has been
patched to read directly from this byte offset.
- `bootcmd_diags=bootm 0xE41000` — diagnostic/recovery kernel slot, also a
raw byte offset. **This is the recovery path that saved the device** when
the main kernel slot got corrupted during testing.
- Gap between main kernel slot (`0x41000`) and diags slot (`0xE41000`) is
`0xE00000` = **14MB** — this is our usable space for a custom kernel image
at the main slot.
### Confirmed via hexdump of `/dev/mmcblk0`
- At byte offset `0x41000`: real Amazon uImage header
- magic: `27 05 19 56`
- data size: `0x3a6cf4` (3,829,492 bytes)
- load/entry: `0x80008000`
- name: `"Linux-3.0.35-lab126"`
- uncompressed
- At byte offset `0xE41000`: diags kernel, same uImage format.
### Compression / Multi-file image support — **the blocker**
Stock 2009.08-lab126 U-Boot's `bootm` **only supports**:
- `Image Type: ARM Linux Kernel Image (uncompressed)`
Tried and **all rejected**:
- gzip (compression type 1) → `"Unimplemented compression type 1"`
- lzo (compression type 4) → rejected
- lzma (compression type 3) → rejected
- Multi-file uImage (kernel + DTB) → old `bootm` doesn't parse the
multi-image DTB component correctly. Got "Bad Data CRC" on one attempt
(likely transfer corruption of that particular copy), and even with a
valid CRC the old `bootm` likely can't pass the DTB to the kernel anyway.
This concern is **moot now** since we're moving to a new U-Boot.
### BIST (factory diagnostic) commands — confirmed working
- `mmc read <ram_addr> <byte_offset> <count>`**uses byte offsets**, not
sectors, for the offset parameter (empirically confirmed: offset `266240`
decimal = `0x41000` byte offset works).
- `mmc write <ram_addr> <byte_offset> <count>` — same byte-offset semantics.
- `loady`, `loadb` — load binary into RAM over serial (Y-modem / raw binary).
- `source` — run a U-Boot script from RAM.
- `go <addr>` — jump to and execute code at a RAM address. **This is our
planned non-destructive test mechanism for the new U-Boot.**
- `iminfo` — inspect a uImage header in RAM.
---
## Mainline Kernel Build
- Source tree: mainline Linux **6.15.0**, built on
`/media/atticpi/.../build_drive/linux`
- Config: stripped-down `imx_v6_v7_defconfig`
- Removed: non-i.MX6SL SoCs, sound, DRM, media, USB gadget, and other
unused subsystems.
- Build artifact sizes:
- `arch/arm/boot/Image` (uncompressed): **13MB** (down from 23MB
unstripped)
- `arch/arm/boot/zImage` (self-decompressing): confirmed buildable,
~9.3MB compressed (uImage-wrapped zImage was 9,757,400 bytes /
~9.31MB per a successful build log)
- `arch/arm/boot/uImage` — successfully built, e.g.:
```
Image Name: Linux-6.15.0
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 9757400 Bytes = 9528.71 KiB = 9.31 MiB
Load Address: 80008000
Entry Point: 80008000
```
- **Conclusion:** even the stripped uncompressed `Image` (13MB) plus a
~21KB DTB doesn't comfortably fit alongside the compression
incompatibility of the stock U-Boot. The zImage at ~9.3MB *would* fit in
the 14MB window, but the stock `bootm` can't run a zImage via `bootz`
(that command doesn't exist in 2009.08-lab126) — hence the need for a
new U-Boot.
---
## Device Tree Sources
Two candidate Wario DTS sources identified:
1. **u-boot-wario's built-in "wario" DTS** at `boot/dts/` in the
`u-boot-wario` repo — likely the most relevant since it's paired with
the U-Boot fork we're using. (Not yet fully inspected.)
2. **Gist by Reagan Bohan** —
`https://gist.github.com/gdamjan/13fc8c75a2f8bb34541da0948739baed`
- Working `imx6sl-wario.dts` skeleton
- `compatible = "fsl,imx6sl-wario", "fsl,imx6sl"`
- Includes `imx6sl.dtsi`
- Has `uart1` with `pinctrl_uart1`, `usdhc1` pinctrl
- `chosen { stdout-path = &uart1; }`
- `memory@80000000` node: `reg = <0x80000000 0x10000000>` (256MB —
note actual board has 512MB, may need adjusting)
3. **In-progress mainline kernel-side DTS** (may be superseded by #1):
`arch/arm/boot/dts/imx6sl-kindle-pw3.dts`
- includes `imx6sl.dtsi`
- `pinctrl_uart1`
- `usdhc2` for eMMC
- `i2c1`: max77696, max17135
- `i2c2`: cyttsp4 touchscreen
- `wdog1`
---
## Decision Log
1. **QEMU testing abandoned** — `mcimx6ul-evk` / `qemu_arm_defconfig` had
incomplete peripheral emulation for this board. Pivoted to real hardware
testing via serial/BIST since we have physical access to a KPW3.
2. **New U-Boot fork chosen:** `bdm310/u-boot-wario`, branch
`amazon-wario-max77696`
- Repo: `https://github.com/bdm310/u-boot-wario` (public, C, by user
`bdm310`, confirmed to exist via search; direct fetch blocked by
GitHub robots.txt but repo was successfully **cloned locally**)
- Has a `wario_defconfig` board config (confirmed)
- Key config options present:
```
CONFIG_CMD_BOOTZ=y
CONFIG_CMD_BOOTMENU=y
CONFIG_CMD_DM=y
CONFIG_CMD_MMC=y
CONFIG_CMD_USB=y
CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_CMD_USB_MASS_STORAGE=y
CONFIG_OF_CONTROL=y
CONFIG_OF_LIBFDT=y
CONFIG_DEFAULT_DEVICE_TREE="wario"
CONFIG_DM=y
CONFIG_DM_GPIO=y
CONFIG_DM_MMC=y
CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_SERIAL=y
CONFIG_DM_THERMAL=y
CONFIG_DM_USB=y
CONFIG_FSL_USDHC=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_IMX6=y
CONFIG_IMX_THERMAL=y
CONFIG_MXC_UART=y
CONFIG_USB=y
CONFIG_USB_HOST=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_MANUFACTURER="FSL"
CONFIG_USB_GADGET_VENDOR_NUM=0x0525
CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_CI_UDC=y
CONFIG_MMC=y
CONFIG_SPL_WATCHDOG_SUPPORT=y
CONFIG_SPL_MMC_SUPPORT=y
CONFIG_SPL_MMC_TINY=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_EARLY_BSS=y
```
- This solves both blockers from the stock U-Boot: `bootz` gives us
zImage (compressed) support, and `CONFIG_OF_CONTROL` gives us proper
DTB passing to the kernel.
3. **DDR init concern (unresolved):** the Amazon boot ROM already
initializes DDR before handing off to stock U-Boot. The new U-Boot's
SPL would normally re-init DDR itself. If we chainload the new U-Boot
via `go` from the stock U-Boot/BIST (DRAM already up), running SPL's DDR
init again could be risky or redundant.
- **Open question:** can we jump directly into the post-SPL
`u-boot.bin` / `u-boot.img` (skipping SPL) and have it work given DRAM
is already initialized? Need to check `CONFIG_SYS_TEXT_BASE` for
`wario_defconfig` and test via `loady` + `go` before any flashing.
---
## Current Status / Risk State
- **Main kernel slot (`0x41000`) was written with a multi-file uImage**
(kernel + DTB) and **did boot** to the point of:
```
Image Type: ARM Linux Multi-File Image
Verifying Checksum...OK
Loading Multi-File Image...OK
Starting kernel...
```
...but produced **no further serial output** — likely missing
earlycon / DTB-passing issue in how the old `bootm` hands off to the
kernel.
- **Diags kernel slot (`0xE41000`) is intact** and is the fallback recovery
path via `bootcmd_diags` / `bootm 0xE41000`. This gives a limited busybox
shell.
- `/dev` is not populated by default in this diags environment — need
`mount -t devtmpfs devtmpfs /dev` or `mdev -s` to get block device
nodes before you can access `/dev/mmcblk0*`.
- **Main Kindle shell** (the original Android-like Kindle OS root shell)
is currently reported as broken/inaccessible. A `kernel.bak` restoration
was attempted but reportedly corrupted earlier in the session.
- **Available recovery/access paths:**
- Serial console + BIST (always available, lowest-level)
- Stock U-Boot prompt
- Diags kernel (limited busybox shell via `bootm 0xE41000`)
- WiFi-enabled root shell (when the device is in a state where it comes
up far enough for networking)
- A second/spare KPW3 unit was on order as a hardware fallback.
---
## Build Environment
- Build machine path root:
`/media/atticpi/69626740-3694-4e07-956f-49cc8e0219a4/build_drive/`
- Relevant directories:
- `linux/` — mainline kernel source, currently configured and building
successfully (6.15.0, `Image`/`zImage`/`uImage` all built)
- `linux-imx/` — (NXP's downstream i.MX kernel tree, presumably for
reference)
- `u-boot/` — original/stock-related U-Boot tree
- `u-boot-wario/` — **target U-Boot fork**, cloned, `wario_defconfig`
confirmed present, currently being explored at `boot/dts/`
- `kindle-linux-3.0.35-lab126/` — stock Amazon kernel source (reference)
---
## Next Steps (as of last session)
1. Inspect `u-boot-wario/boot/dts/` for the `wario` DTS and compare against
the Reagan Bohan gist DTS and the in-progress mainline
`imx6sl-kindle-pw3.dts`.
2. Build u-boot-wario:
```sh
cd u-boot-wario
make mrproper
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
make wario_defconfig
make -j$(nproc)
```
Confirm it produces `SPL` and `u-boot.img` (or `u-boot-dtb.img`).
3. Check `CONFIG_SYS_TEXT_BASE` for `wario_defconfig` (`grep TEXT_BASE
.config`, or `include/configs/wario.h` if present) to determine the load
address for testing.
4. **Test without flashing**: via BIST, `loady <addr>` the new U-Boot
binary into RAM, then `go <addr>` to execute it — non-destructive since
nothing is written to eMMC.
- Resolve the open DDR-init/SPL question above before/while doing this.
5. If the new U-Boot runs successfully with `bootz` + OF support:
- Build the mainline kernel as a **zImage** (~9.3MB, fits the 14MB
window easily since compression is now supported) plus a separate
`wario.dtb`.
- Boot with `bootz <kernel_addr> - <fdt_addr>`.
6. Eventually, flash the new U-Boot to replace/supplement the stock
2009.08 bootloader at the appropriate eMMC offset — exact location and
method **TBD**, but expected to be in the boot0/early region of the
eMMC, separate from the `0x41000` kernel slot.
---
## Useful External References
- u-boot-wario repo: `https://github.com/bdm310/u-boot-wario`
(branch `amazon-wario-max77696`) — direct GitHub fetch blocked by
robots.txt, but repo confirmed public and already cloned locally.
- Wario DTS gist (Reagan Bohan):
`https://gist.github.com/gdamjan/13fc8c75a2f8bb34541da0948739baed`
- General KPW3 mainline porting thread: MobileRead Forums — "PW3 Kindle
Paperwhite 3 Schematics and Mainline u-boot/Linux", Kindle Developer's
Corner (`mobileread.com/forums/showthread.php?t=332253` — returned 404
on last check, may have moved/been removed).

View File

@@ -0,0 +1,301 @@
# Kindle Paperwhite 3 — Mainline Linux Port Progress Summary
**Last updated:** 18 June 2026
**Kernel version:** Linux 6.15.0
**Status:** 🟢 Alpine Linux running with WiFi, NTP, apk — EPD regulator driver
validated on hardware, EPDC driver integration up next
---
## Hardware Summary
| Component | Detail |
|---|---|
| SoC | Freescale i.MX6SoloLite @ 996MHz |
| RAM | 512MB LPDDR2 (Nanya) |
| eMMC | SEM04G, 3.69GiB |
| WiFi | Atheros AR6003 hw2.1.1 over SDIO (mmc2) |
| Display | E Ink ED060KD1C2, 6" EPD via i.MX6SL EPDC |
| PMIC | Maxim max77696 @ I2C0/0x3c |
| EPD PMIC | max77696 internal EPD block (not max17135 as previously thought) |
| Touchscreen | Cypress CYTTSP4 @ I2C1/0x24 |
| RTC | max77696 internal RTC @ I2C0/0x68 (sub-address) |
| Watchdog | i.MX2 watchdog @ 0x20bc000 |
---
## Session Progress
### 1. Alpine Linux on p4 ✅
Reformatted p4 as ext4 and installed Alpine Linux armhf minirootfs. apk, networking,
and NTP are all working. System clock is now set correctly at boot via NTP, which is
required for TLS certificate validation and apk to function.
**Key commands used:**
```sh
mkfs.ext4 /dev/mmcblk1p4
mount /dev/mmcblk1p4 /mnt/alpine
wget -O - https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/armhf/alpine-minirootfs-*-armhf.tar.gz | tar -xzf - -C /mnt/alpine
```
---
### 2. usdhc3 Pinctrl Fix ✅
**Problem:** `could not get pinctrl` warning on boot for usdhc3 (WiFi SDIO).
**Root cause:** Missing `pinctrl_usdhc3` node in DTS.
**Fix:** Added pinctrl node from Reagan Bohan's reference DTS using pad value `0x41f0b1`,
consistent with usdhc1 and usdhc2.
```dts
pinctrl_usdhc3: usdhc3grp {
fsl,pins = <
MX6SL_PAD_SD3_CMD__SD3_CMD 0x41f0b1
MX6SL_PAD_SD3_CLK__SD3_CLK 0x41f0b1
MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x41f0b1
MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x41f0b1
MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x41f0b1
MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x41f0b1
>;
};
```
WiFi still working correctly after fix. Warning gone.
---
### 3. max17135 Investigation — Not Present on KPW3 ✅
**Finding:** The KPW3 does **not** use a max17135 EPD PMIC. This was confirmed by:
- No reference to max17135 in `board-mx6sl_wario.c` or `board-mx6sl_wario.h`
- i2cdetect showing no device at `0x48` (max17135 address)
- Addresses `0x34`/`0x35` are max77696 sub-addresses, not max17135
- Stock kernel log showing EPD power handled entirely by max77696's internal EPD block
**Action:** Removed max17135 DTS node entirely. EPD power sequencing is handled by
the max77696 EPD regulator block which exposes: `max77696-display`, `max77696-vcom`,
`max77696-vee`, `max77696-vneg`, `max77696-vpos`, `max77696-vddh`.
---
### 4. RTC Investigation ✅
**Finding:** Device at I2C0/0x68 is **not** a ds1307 — it is the max77696 internal
RTC sub-address. Confirmed by:
- ds1307 driver binding but failing to read time
- Register dump after unbind showing max77696 RTC register layout, not ds1307
- Stock kernel log showing max77696-rtc registered as rtc0/rtc1
**Action:** Removed ds1307 DTS node. Using SNVS RTC (rtc1 under mainline) for now.
max77696 RTC will only be accessible once a proper max77696 MFD driver exists.
**Current state:** SNVS RTC working, time set via NTP on each boot.
---
### 5. Current DTS State ✅ (superseded — see §8 below)
This was the placeholder node before the EPD regulator driver existed.
**Replaced** on 18 June — see §8 "EPD Regulator DTS Node — Merged and
Validated" for the actual current state. Only one node may exist per I2C
address, so this placeholder was removed entirely rather than kept
alongside the real EPD node.
```dts
&i2c1 {
clock-frequency = <100000>;
status = "okay";
max77696: pmic@3c {
compatible = "maxim,max77696";
reg = <0x3c>;
interrupt-parent = <&gpio4>;
interrupts = <20 IRQ_TYPE_LEVEL_LOW>; /* gpio-116 */
};
};
```
---
### 6. EPDC Driver Research ✅
Cloned Andreas Kemnade's linux tree (`akemnade/linux`) and identified the EPDC driver
at `drivers/gpu/drm/mxc-epdc/`. Key findings:
**Compatible string:** `fsl,imx6sl-epdc` — matches KPW3's SoC ✅
**Regulator supply names the EPDC driver expects:**
```c
priv->display_regulator = devm_regulator_get(priv->drm.dev, "DISPLAY");
priv->vcom_regulator = devm_regulator_get(priv->drm.dev, "VCOM");
priv->v3p3_regulator = devm_regulator_get(priv->drm.dev, "V3P3");
```
**Reference DTS pattern** (from Tolino Shine 3, same imx6sl SoC):
```dts
&epdc {
V3P3-supply = <&V3P3_reg>;
VCOM-supply = <&VCOM_reg>;
DISPLAY-supply = <&DISPLAY_reg>;
};
```
**EPD GPIO mapping** (identical between Tolino Shine 3 and KPW3):
| Signal | GPIO | Pad |
|---|---|---|
| pwrgood | GPIO2/13 | EPDC_PWRSTAT |
| vcom_ctrl | GPIO2/3 | EPDC_VCOM0 |
| wakeup | GPIO2/14 | EPDC_PWRWAKEUP |
| v3p3 / pwrctrl0 | GPIO2/7 | EPDC_PWRCTRL0 |
| interrupt | GPIO2/12 | EPDC_PWRINT |
---
### 7. max77696 EPD Register Map ✅
Extracted from Amazon 3.0.35 kernel source (`max77696_registers.h`):
| Register | Address | Purpose |
|---|---|---|
| `EPDCNFG` | `0x60` | bit7=EPDEN, bit6=VCOMEN, bit1=SSHVDDH |
| `EPDINTS` | `0x61` | Interrupt status |
| `EPDINT` | `0x62` | Fault status |
| `EPDINTM` | `0x63` | Interrupt mask |
| `EPDVCOM` | `0x64` | VCOM voltage (low byte) |
| `EPDVEE` | `0x65` | VEE voltage |
| `EPDVNEG` | `0x66` | VNEG voltage |
| `EPDVPOS` | `0x67` | VPOS voltage |
| `EPDVDDH` | `0x68` | VDDH/V3P3 voltage |
| `EPDSEQ` | `0x69` | Power sequence |
| `EPDOKINTS` | `0x6A` | Power OK interrupt status |
| `EPDOKINT` | `0xB2` | Power OK interrupt |
| `EPDOKINTM` | `0xB3` | Power OK interrupt mask |
| `EPDVCOMR` | `0xB4` | VCOM voltage high bit (VCOMR bit0) |
| `EPDDIS` | `0xB5` | Display disable |
---
### 8. EPD Regulator DTS Node — Merged and Validated ✅
The placeholder `pmic@3c` node (§5, now superseded) has been replaced with
the real node the EPD regulator driver (`drivers/regulator/max77696-regulator.c`,
compatible `maxim,max77696-epd` — renamed from `max77696-epd.c` to match
other regulator driver filenames; compatible string deliberately kept
narrower, see driver summary doc) binds to.
```dts
&i2c1 {
clock-frequency = <100000>;
status = "okay";
max77696_epd: epd-pmic@3c {
compatible = "maxim,max77696-epd";
reg = <0x3c>;
interrupt-parent = <&gpio4>;
interrupts = <20 IRQ_TYPE_LEVEL_LOW>; /* gpio-116 */
/* pwrgood-gpios intentionally omitted — not yet requested by driver */
regulators {
DISPLAY_reg: DISPLAY {
regulator-name = "DISPLAY";
};
VCOM_reg: VCOM {
regulator-name = "VCOM";
};
V3P3_reg: V3P3 {
regulator-name = "V3P3";
};
};
};
};
```
**Hardware validation (18 June 2026):** built the driver as a module
(`CONFIG_REGULATOR_MAX77696_EPD=m`), sent the rebuilt `.dtb` over U-Boot
serial, booted, `insmod`'d. Confirmed via sysfs:
- I2C driver bound: `/sys/bus/i2c/drivers/max77696-epd/0-003c`
- All three regulators registered with correct names (`DISPLAY`, `VCOM`,
`V3P3`) under `/sys/class/regulator/` — confirms DT child-node name
matching works correctly with no explicit `.of_match` needed in the
driver
- Baseline register read via `regmap` debugfs (`/sys/kernel/debug/regmap/0-003c/registers`)
shows `60: 00` — confirms no spurious enable writes at probe
Full command reference and remaining gap (enable/disable not yet exercised
on hardware) recorded in `max77696-epd-driver-summary.md`.
A useful side-lesson from this session: `i2cget` on an address already
claimed by a bound kernel driver returns `Resource busy` — this is the
I2C core correctly enforcing exclusivity, not a fault. Use `regmap`
debugfs to read live register state without unbinding the driver.
---
### EPDC node — pending
Not yet started. The `&epdc { ... }` supply-reference snippet (referencing
`DISPLAY_reg`/`VCOM_reg`/`V3P3_reg` above) can't be merged until the EPDC
node itself exists in this DTS — there's currently no `epdc` label defined
anywhere in `imx6sl-kindle-pw3.dts`.
---
## Next Steps
### ✅ Done: max77696 EPD Regulator Driver
Was the "Immediate" next step as of 15 June; now complete and validated on
hardware as of 18 June. See §8 above and `max77696-epd-driver-summary.md`
for full detail. Remaining gap: enable/disable not yet exercised on real
hardware (sysfs `state` is read-only without a consumer wired up).
### Immediate: EPDC DTS Node
Now the live next step. Add the EPDC node with:
- Pinctrl for all EPDC data/control pads (same as Tolino Shine 3)
- Regulator supply references (`DISPLAY-supply`, `VCOM-supply`,
`V3P3-supply` — phandles already exist and are ready: `DISPLAY_reg`,
`VCOM_reg`, `V3P3_reg`, defined in §8 above)
- Timing values for ED060KD1C2 panel
- Waveform file reference
This will also be the natural way to validate the regulator
enable/disable path on real hardware, since the EPDC driver is the
intended real consumer (`devm_regulator_get(dev, "DISPLAY")` etc.) rather
than needing a synthetic userspace-consumer test.
### Then: EPDC Driver Integration
Cherry-pick Kemnade's `drivers/gpu/drm/mxc-epdc/` into the mainline kernel tree
and build against 6.15.
---
## Key Technical Lessons from This Session
- **max17135 is not present on KPW3** — EPD power is entirely max77696
- **0x34/0x35 on i2cdetect are max77696 sub-addresses**, not a separate PMIC
- **0x68 on i2cdetect is the max77696 RTC**, not a ds1307
- **Tolino Shine 3 uses identical EPD GPIO wiring** to KPW3 — valuable reference
- **No mainline max77696 driver exists** — standalone EPD regulator driver needed
- **EPDC expects exactly three supply names**: `DISPLAY`, `VCOM`, `V3P3`
- **waveform format is `.wrf.gz`** (proprietary), not standard `.wbf`
- **Only one DT node may exist per I2C address** — the placeholder
`pmic@3c` had to be fully replaced, not kept alongside the real
`epd-pmic@3c` node, once the EPD regulator driver existed
- **DT child-node name matching works without an explicit `.of_match`**
in `regulator_desc` — confirmed on real hardware, regulator core
matches `regulators { DISPLAY {}; ... }` subnodes by name correctly
- **`i2cget` on an address held by a bound kernel driver returns
`Resource busy`** — expected I2C core behaviour, not a bug. Use
`regmap` debugfs (`/sys/kernel/debug/regmap/<bus>-<addr>/registers`)
to read live register state without unbinding
- **Filename and DT compatible string don't have to match** — renamed
the driver file to `max77696-regulator.c` for consistency with other
regulator drivers, kept the compatible string as the narrower
`maxim,max77696-epd` since it describes the specific hardware
function block, not the driver category

View File

@@ -0,0 +1,233 @@
# Kindle Paperwhite 3 — Mainline Linux Port Progress Summary
**Last updated:** 15 June 2026
**Kernel version:** Linux 6.15.0
**Status:** 🟢 Alpine Linux running with WiFi, NTP, apk — EPDC driver work in progress
---
## Hardware Summary
| Component | Detail |
|---|---|
| SoC | Freescale i.MX6SoloLite @ 996MHz |
| RAM | 512MB LPDDR2 (Nanya) |
| eMMC | SEM04G, 3.69GiB |
| WiFi | Atheros AR6003 hw2.1.1 over SDIO (mmc2) |
| Display | E Ink ED060KD1C2, 6" EPD via i.MX6SL EPDC |
| PMIC | Maxim max77696 @ I2C0/0x3c |
| EPD PMIC | max77696 internal EPD block (not max17135 as previously thought) |
| Touchscreen | Cypress CYTTSP4 @ I2C1/0x24 |
| RTC | max77696 internal RTC @ I2C0/0x68 (sub-address) |
| Watchdog | i.MX2 watchdog @ 0x20bc000 |
---
## Session Progress
### 1. Alpine Linux on p4 ✅
Reformatted p4 as ext4 and installed Alpine Linux armhf minirootfs. apk, networking,
and NTP are all working. System clock is now set correctly at boot via NTP, which is
required for TLS certificate validation and apk to function.
**Key commands used:**
```sh
mkfs.ext4 /dev/mmcblk1p4
mount /dev/mmcblk1p4 /mnt/alpine
wget -O - https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/armhf/alpine-minirootfs-*-armhf.tar.gz | tar -xzf - -C /mnt/alpine
```
---
### 2. usdhc3 Pinctrl Fix ✅
**Problem:** `could not get pinctrl` warning on boot for usdhc3 (WiFi SDIO).
**Root cause:** Missing `pinctrl_usdhc3` node in DTS.
**Fix:** Added pinctrl node from Reagan Bohan's reference DTS using pad value `0x41f0b1`,
consistent with usdhc1 and usdhc2.
```dts
pinctrl_usdhc3: usdhc3grp {
fsl,pins = <
MX6SL_PAD_SD3_CMD__SD3_CMD 0x41f0b1
MX6SL_PAD_SD3_CLK__SD3_CLK 0x41f0b1
MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x41f0b1
MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x41f0b1
MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x41f0b1
MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x41f0b1
>;
};
```
WiFi still working correctly after fix. Warning gone.
---
### 3. max17135 Investigation — Not Present on KPW3 ✅
**Finding:** The KPW3 does **not** use a max17135 EPD PMIC. This was confirmed by:
- No reference to max17135 in `board-mx6sl_wario.c` or `board-mx6sl_wario.h`
- i2cdetect showing no device at `0x48` (max17135 address)
- Addresses `0x34`/`0x35` are max77696 sub-addresses, not max17135
- Stock kernel log showing EPD power handled entirely by max77696's internal EPD block
**Action:** Removed max17135 DTS node entirely. EPD power sequencing is handled by
the max77696 EPD regulator block which exposes: `max77696-display`, `max77696-vcom`,
`max77696-vee`, `max77696-vneg`, `max77696-vpos`, `max77696-vddh`.
---
### 4. RTC Investigation ✅
**Finding:** Device at I2C0/0x68 is **not** a ds1307 — it is the max77696 internal
RTC sub-address. Confirmed by:
- ds1307 driver binding but failing to read time
- Register dump after unbind showing max77696 RTC register layout, not ds1307
- Stock kernel log showing max77696-rtc registered as rtc0/rtc1
**Action:** Removed ds1307 DTS node. Using SNVS RTC (rtc1 under mainline) for now.
max77696 RTC will only be accessible once a proper max77696 MFD driver exists.
**Current state:** SNVS RTC working, time set via NTP on each boot.
---
### 5. Current DTS State ✅
```dts
&i2c1 {
clock-frequency = <100000>;
status = "okay";
max77696: pmic@3c {
compatible = "maxim,max77696";
reg = <0x3c>;
interrupt-parent = <&gpio4>;
interrupts = <20 IRQ_TYPE_LEVEL_LOW>; /* gpio-116 */
};
};
```
---
### 6. EPDC Driver Research ✅
Cloned Andreas Kemnade's linux tree (`akemnade/linux`) and identified the EPDC driver
at `drivers/gpu/drm/mxc-epdc/`. Key findings:
**Compatible string:** `fsl,imx6sl-epdc` — matches KPW3's SoC ✅
**Regulator supply names the EPDC driver expects:**
```c
priv->display_regulator = devm_regulator_get(priv->drm.dev, "DISPLAY");
priv->vcom_regulator = devm_regulator_get(priv->drm.dev, "VCOM");
priv->v3p3_regulator = devm_regulator_get(priv->drm.dev, "V3P3");
```
**Reference DTS pattern** (from Tolino Shine 3, same imx6sl SoC):
```dts
&epdc {
V3P3-supply = <&V3P3_reg>;
VCOM-supply = <&VCOM_reg>;
DISPLAY-supply = <&DISPLAY_reg>;
};
```
**EPD GPIO mapping** (identical between Tolino Shine 3 and KPW3):
| Signal | GPIO | Pad |
|---|---|---|
| pwrgood | GPIO2/13 | EPDC_PWRSTAT |
| vcom_ctrl | GPIO2/3 | EPDC_VCOM0 |
| wakeup | GPIO2/14 | EPDC_PWRWAKEUP |
| v3p3 / pwrctrl0 | GPIO2/7 | EPDC_PWRCTRL0 |
| interrupt | GPIO2/12 | EPDC_PWRINT |
---
### 7. max77696 EPD Register Map ✅
Extracted from Amazon 3.0.35 kernel source (`max77696_registers.h`):
| Register | Address | Purpose |
|---|---|---|
| `EPDCNFG` | `0x60` | bit7=EPDEN, bit6=VCOMEN, bit1=SSHVDDH |
| `EPDINTS` | `0x61` | Interrupt status |
| `EPDINT` | `0x62` | Fault status |
| `EPDINTM` | `0x63` | Interrupt mask |
| `EPDVCOM` | `0x64` | VCOM voltage (low byte) |
| `EPDVEE` | `0x65` | VEE voltage |
| `EPDVNEG` | `0x66` | VNEG voltage |
| `EPDVPOS` | `0x67` | VPOS voltage |
| `EPDVDDH` | `0x68` | VDDH/V3P3 voltage |
| `EPDSEQ` | `0x69` | Power sequence |
| `EPDOKINTS` | `0x6A` | Power OK interrupt status |
| `EPDOKINT` | `0xB2` | Power OK interrupt |
| `EPDOKINTM` | `0xB3` | Power OK interrupt mask |
| `EPDVCOMR` | `0xB4` | VCOM voltage high bit (VCOMR bit0) |
| `EPDDIS` | `0xB5` | Display disable |
---
## Next Steps
### Immediate: max77696 EPD Regulator Driver
A standalone regulator driver needs to be written at
`drivers/regulator/max77696-epd.c` that:
- Probes on I2C at `0x3c` with `compatible = "maxim,max77696-epd"`
- Uses `regmap` (8-bit reg, 8-bit val) for register access
- Exposes three regulators: `DISPLAY`, `VCOM`, `V3P3`
- `DISPLAY` enable/disable → EPDEN bit7 of `0x60`
- `VCOM` enable/disable → VCOMEN bit6 of `0x60`
- `V3P3` enable/disable → SSHVDDH bit1 of `0x60`
- Gets `pwrgood` GPIO via `devm_gpiod_get`
- Start with enable/disable only, add voltage control later
**DTS node planned:**
```dts
max77696_epd: epd-pmic@3c {
compatible = "maxim,max77696-epd";
reg = <0x3c>;
pwrgood-gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
regulators {
DISPLAY_reg: DISPLAY {
regulator-name = "DISPLAY";
};
VCOM_reg: VCOM {
regulator-name = "VCOM";
};
V3P3_reg: V3P3 {
regulator-name = "V3P3";
};
};
};
```
### Following: EPDC DTS Node
Once the regulator driver is working, add the EPDC node with:
- Pinctrl for all EPDC data/control pads (same as Tolino Shine 3)
- Regulator supply references
- Timing values for ED060KD1C2 panel
- Waveform file reference
### Then: EPDC Driver Integration
Cherry-pick Kemnade's `drivers/gpu/drm/mxc-epdc/` into the mainline kernel tree
and build against 6.15.
---
## Key Technical Lessons from This Session
- **max17135 is not present on KPW3** — EPD power is entirely max77696
- **0x34/0x35 on i2cdetect are max77696 sub-addresses**, not a separate PMIC
- **0x68 on i2cdetect is the max77696 RTC**, not a ds1307
- **Tolino Shine 3 uses identical EPD GPIO wiring** to KPW3 — valuable reference
- **No mainline max77696 driver exists** — standalone EPD regulator driver needed
- **EPDC expects exactly three supply names**: `DISPLAY`, `VCOM`, `V3P3`
- **waveform format is `.wrf.gz`** (proprietary), not standard `.wbf`

View File

@@ -0,0 +1,281 @@
# Kindle Paperwhite 3 (KPW3) Mainline Linux Port — Complete Project Summary
**Last updated:** 14 June 2026
**Status:** 🎉 **Mainline Linux 6.15 fully booted, WiFi connected, root shell on own DTS**
---
## Hardware Summary
| Component | Detail |
|---|---|
| SoC | Freescale i.MX6SoloLite, rev1.3 @ 996MHz |
| RAM | 512MB LPDDR2 (Nanya) |
| eMMC | SEM04G, 3.69GiB (SEM04G) |
| WiFi | Atheros AR6003 hw2.1.1 over SDIO (mmc2) |
| Display | E Ink ED060KD1C2, 6" EPD via i.MX6SL EPDC |
| PMIC | Maxim max77696 @ I2C0/0x3c |
| EPD PMIC | Maxim max17135 @ I2C0/0x34+0x35 |
| Touchscreen | Cypress CYTTSP4 @ I2C1/0x24 |
| RTC | Unknown @ I2C0/0x68 (electrically confirmed) |
| Watchdog | i.MX2 watchdog @ 0x20bc000 (active from boot ROM) |
| Compatible | `amazon,kindle-pw3`, `fsl,imx6sl` |
| Console | UART1 @ 0x02020000, ttymxc0, 115200 baud |
### eMMC Partition Layout (`/dev/mmcblk1` under mainline)
| Partition | Size | FS | Notes |
|---|---|---|---|
| p1 | 450MB | ext3 | Amazon rootfs — working under mainline |
| p2 | 64MB | ? | `/usr/share/nh` — contains EPD NightHawk binary, WiFi firmware |
| p3 | 64MB | ? | `/var/local` — contains EPD waveform file |
| p4 | 3.1GB | FAT32 | Books — expendable, target for Alpine Linux rootfs |
### Key eMMC Raw Offsets (byte offsets, stock U-Boot semantics)
| Offset | Content |
|---|---|
| `0x41000` (block `0x208`) | Main kernel slot — currently holds mainline 6.15 gzip uImage |
| `0xE41000` | Diags kernel slot — stock Amazon 3.0.35 busybox recovery, **untouched** |
---
## Bootloader Situation
### Stock U-Boot (2009.08-lab126)
- Extremely old, heavily patched Amazon fork
- `bootcmd=bootm 0x41000` — reads kernel from raw byte offset `0x41000` on eMMC
- `bootcmd_diags=bootm 0xE41000` — recovery path, always available
- **Very limited command set** at interactive prompt: no `mmc`, no `loady`, no `source`
- BIST environment (separate from U-Boot prompt) has `mmc`, `loady`, `loadb`, `source`, `go`
- `bootm` only supports uncompressed ARM Linux Kernel Images natively; all compression types rejected
- **Chainload-via-standalone-image abandoned**: writing u-boot-wario as a standalone uImage to `0x41000` caused `bootm` to load it but return "OK" without jumping, leaving console unresponsive
### u-boot-wario (2021.04-rc3, `bdm310/u-boot-wario`, branch `amazon-wario-max77696`)
- `CONFIG_SYS_TEXT_BASE=0x87800000`, `CONFIG_SPL_TEXT_BASE=0x00908000`
- **Successfully chainloaded via BIST**: `loady 0x87800000``go 0x87800000`
- DDR already initialized by boot ROM — jumping directly into post-SPL `u-boot.bin` works perfectly, no SPL DDR re-init needed
- Correctly identifies SoC, sees full 512MiB DRAM, both MMC controllers
- eMMC is `mmc dev 1` (FSL_SDHC: 1), WiFi SDIO is `mmc dev 2`
- **Block-offset math**: byte offset `0x41000` ÷ 512 = block `0x208` for `mmc read`/`mmc write`
- Supports `bootz`, `bootm`, gzip, `OF_CONTROL` for DTB passing — solves all stock U-Boot blockers
- **Start-of-session sequence** (every boot):
```
# From BIST:
loady 0x87800000 # transfer u-boot.bin (353KB, ~seconds)
go 0x87800000 # chainload into u-boot-wario
# From u-boot-wario prompt:
mmc dev 1
mmc read 0x87800000 0x208 0x5000 # read kernel from eMMC
loady 0x83000000 # transfer .dtb over serial (small, fast)
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p1 rootwait rw'
bootm 0x87800000 - 0x83000000
```
---
## Kernel
- **Version**: Linux 6.15.0
- **Config base**: `imx_v6_v7_defconfig` (switched from stripped config after confirming gzip fits the 14MB window)
- **Compression**: gzip uImage (~9.3MB), built with `make uImage LOADADDR=0x80008000`
- **Cross-compiler**: `arm-linux-gnueabi-gcc` (Debian 12.2.0-14)
- **Stored at**: byte offset `0x41000` on eMMC (block `0x208`), read by u-boot-wario each session
### Key kernel config options enabled/confirmed
```
CONFIG_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_ATH6KL=y
CONFIG_ATH6KL_SDIO=y
CONFIG_EXTRA_FIRMWARE="ath6k/AR6003/hw2.1.1/athwlan.bin ath6k/AR6003/hw2.1.1/otp.bin ..."
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
```
---
## Device Tree (`imx6sl-kindle-pw3.dts`)
### Current working state
```dts
/dts-v1/;
#include "imx6sl.dtsi"
// includes imx6sl-pinfunc.h, gpio.h, input.h
/ {
model = "Amazon Kindle Paperwhite 3 (Wario)";
compatible = "amazon,kindle-pw3", "fsl,imx6sl";
memory@80000000 { reg = <0x80000000 0x20000000>; }; // 512MB
chosen { stdout-path = &uart1; };
regulators {
emmc_3v3: regulator-fixed, gpio4/17 (gpio-113)
regulator-boot-on; regulator-always-on; // CRITICAL
emmc_1v8: regulator-fixed, gpio4/23 (gpio-119)
regulator-boot-on; regulator-always-on; // CRITICAL
wifi_pwr: regulator-fixed, gpio3/29 (gpio-93)
3300000 microvolt min/max // needed for OCR
};
};
```
### Node status
| Node | Status | Notes |
|---|---|---|
| `uart1` | ✅ enabled | console, pinctrl_uart1 |
| `usdhc2` (eMMC) | ✅ enabled | `pinctrl_usdhc2`, both supplies `boot-on`+`always-on` — **both required** |
| `usdhc3` (WiFi SDIO) | ✅ enabled | `could not get pinctrl` warning (needs pinctrl_usdhc3) but works |
| `i2c1` (PMIC bus) | ✅ enabled | max77696 + max17135 + RTC detected |
| `i2c2` (touch bus) | ✅ enabled | cyttsp4 driver bound |
| `wdog1` | ✅ enabled | `imx2-wdt` manages hardware watchdog |
| `gpu_2d` / `gpu_3d` | ❌ disabled | GPC power-domain hang — needs anatop regulator fix |
| `epdc` / `pxp` | ❌ not yet enabled | EPDC driver not in mainline 6.15 |
### Critical DTS lessons learned
1. **eMMC regulators**: both `vmmc-supply` and `vqmmc-supply` must have `regulator-boot-on; regulator-always-on;` — without these, eMMC either fails to init or misidentifies as wrong card
2. **GPU power domain hang**: `gpu@2200000`/`gpu@2204000` nodes with `power-domains = <&pgc_power_domain_1>` cause a silent infinite hang after etnaviv binds, because the GPC power domain waits on anatop regulators that never enable. **Disable GPU nodes** until anatop regulator `regulator-always-on`/`anatop-enable-bit` settings are corrected to match working reference DTB
3. **`usdhc2` block offset**: byte offset `0x41000` ÷ 512 = block `0x208` — confusing because BIST uses byte offsets, u-boot-wario uses block offsets
4. **WiFi regulator**: `wifi_pwr` regulator-fixed needs explicit `regulator-min/max-microvolt = <3300000>` or SDHCI returns `-EINVAL` on OCR request
5. **`mmc` device index**: eMMC is `mmc1` / `mmcblk1` under mainline (not `mmc0`) — root= must be `/dev/mmcblk1p1`
6. **Reference DTB**: `bdm310/wario-hardware/wario.dtb` (decompile with `dtc -I dtb -O dts`) was invaluable for diffing against custom DTS to find working eMMC clock/pinctrl settings
---
## Hardware Status
### Working on mainline 6.15
| Hardware | Status | Notes |
|---|---|---|
| UART console | ✅ | ttymxc0, 115200 — rock solid throughout |
| eMMC (SEM04G) | ✅ | all partitions, boot0/boot1/rpmb, DDR high speed |
| I2C-0 bus | ✅ | both adapters registered |
| max77696 PMIC | ✅ | driver bound (waiting_for_supplier — GPIO fw_devlink issue) |
| max17135 EPD PMIC | ✅ | detected at 0x34/0x35, no mainline driver yet |
| RTC @ 0x68 | ✅ | electrically present, no DTS node yet |
| CYTTSP4 touchscreen | ✅ | driver bound (waiting_for_supplier) |
| WiFi AR6003 SDIO | ✅ | fully working, WPA2 connected, DHCP, ping |
| Watchdog | ✅ | imx2-wdt managing hardware watchdog |
| SNVS RTC | ✅ | registered as rtc0 |
| RNGB | ✅ | HW random registered |
| etnaviv GPU | ✅ | driver binds, but GPU nodes disabled in DTS |
### Not yet working / pending
| Hardware | Status | Notes |
|---|---|---|
| GPU (2D/3D) | ⏳ | Disabled — needs anatop regulator `regulator-always-on` fix for GPC power domain |
| EPD display | ⏳ | EPDC driver not in mainline 6.15 — needs Andreas Kemnade's out-of-tree driver (akemnade/linux) |
| max17135 regulator | ⏳ | No mainline driver — needs backport from Amazon 3.0.35 kernel source (`drivers/mfd/max17135-core.c`, `drivers/regulator/max17135-regulator.c`) |
| WiFi board file | ⚠️ | Using Amazon's `bdata.bin` from p2 at runtime; should be added to `EXTRA_FIRMWARE` for next kernel build |
| usdhc3 pinctrl | ⚠️ | `could not get pinctrl` warning — needs `pinctrl_usdhc3` node in DTS |
| RTC DTS node | ⏳ | Device at 0x68 confirmed, likely ds1307-compatible, no DTS node added yet |
| Alpine Linux on p4 | ⏳ | Planned — reformat p4 as ext4, extract Alpine armhf minirootfs |
---
## WiFi Setup
**Hardware**: Atheros AR6003 hw2.1.1 on SDIO (mmc2)
**Driver**: `ath6kl_sdio` (built-in, `CONFIG_ATH6KL=y`, `CONFIG_ATH6KL_SDIO=y`)
**Firmware**: Embedded via `EXTRA_FIRMWARE` + Amazon's own `bdata.bin` from `/opt/ar6k/target/AR6003/hw2.1.1/bin/` on p2
**Amazon firmware files** (copy to `/lib/firmware/ath6k/AR6003/hw2.1.1/`):
```sh
/opt/ar6k/target/AR6003/hw2.1.1/bin/bdata.bin # board calibration
/opt/ar6k/target/AR6003/hw2.1.1/bin/athwlan.bin # main firmware
/opt/ar6k/target/AR6003/hw2.1.1/bin/otp.bin # OTP data
/opt/ar6k/target/AR6003/hw2.1.1/bin/data.patch.hw3_0.bin # patch
/opt/ar6k/target/AR6003/hw2.1.1/bin/fw-4.bin # firmware v4
```
**Connection sequence**:
```sh
mkdir -p /run/wpa_supplicant
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf -D nl80211
udhcpc -i wlan0
echo "nameserver 8.8.8.8" > /etc/resolv.conf
ping -c 3 8.8.8.8
```
**Note**: `bdata.bin` (hardware-specific RF calibration) is critical — without it, scanning returns no results. The generic `bdata.SD31.bin`/`bdata.SD32.bin` from linux-firmware.git are insufficient for this hardware.
---
## EPD Display — Status & Plan
**Panel**: E Ink ED060KD1C2 (6", KPW3-specific)
**Waveform**: `320_R200_AEC241_ED060KD1C2_TC.wbf` found on p3 at `/mnt/eink/waveforms/`
**Controller**: i.MX6SL EPDC @ `0x20f4000` + PxP @ `0x20f0000` (both in `imx6sl.dtsi`)
**Blocker**: No EPDC driver in mainline Linux 6.15. Only clock definitions exist (`drivers/clk/imx/clk-imx6sl.c`).
**Path forward**:
1. Andreas Kemnade (`akemnade`) has an out-of-tree EPDC DRM driver for Kobo devices (same i.MX6SL SoC) — `git ls-remote https://github.com/akemnade/linux.git` to find relevant branches (fetch in progress)
2. max17135 EPD PMIC driver needs backporting from Amazon 3.0.35 source (`drivers/mfd/max17135-core.c` + `drivers/regulator/max17135-regulator.c` + `drivers/hwmon/max17135-hwmon.c`)
3. Once both drivers available: enable `epdc` and `pxp` nodes in DTS with correct max17135 regulator supplies, load waveform from `/lib/firmware/`
---
## Next Steps (Priority Order)
1. **Alpine Linux on p4** — reformat p4 as ext4, extract Alpine armhf minirootfs, boot with `root=/dev/mmcblk1p4`. Gives proper package manager, SSH, wpa_supplicant, etc.
```sh
mkfs.ext4 /dev/mmcblk1p4
mount /dev/mmcblk1p4 /mnt
# extract alpine-minirootfs-*-armhf.tar.gz to /mnt
```
2. **WiFi board file in EXTRA_FIRMWARE** — add Amazon's `bdata.bin` and other firmware to kernel's `EXTRA_FIRMWARE` so WiFi works from first boot without manual copying
3. **Fix usdhc3 pinctrl** — add `pinctrl_usdhc3` node (SD3 pad mux settings) to DTS
4. **Fix GPIO supplier issue** — resolve `waiting_for_supplier` for max77696 and cyttsp4; likely needs `fw_devlink` investigation or explicit GPIO supplier registration in DTS
5. **GPU power domain fix** — compare anatop regulator settings with `wario.dtb` reference, add `regulator-always-on` to correct rail, re-enable `gpu_2d`/`gpu_3d`
6. **RTC DTS node** — add node for device at I2C0/0x68 (likely `ds1307` or similar compatible)
7. **EPDC display driver** — cherry-pick Andreas Kemnade's DRM EPDC driver + backport max17135 MFD/regulator drivers from Amazon 3.0.35 source
8. **Persistent U-Boot** — investigate flashing u-boot-wario to eMMC boot ROM search location to avoid BIST+loady each session (needs careful offset research + full backup first)
---
## Key Reference Files & Locations
| Item | Location |
|---|---|
| Mainline kernel source | `/media/atticpi/.../build_drive/linux/` |
| u-boot-wario source | `/media/atticpi/.../build_drive/u-boot-wario/` |
| Amazon 3.0.35 kernel (reference) | `/media/atticpi/.../build_drive/kindle-linux-3.0.35-lab126/` |
| NXP linux-imx (reference) | `/media/atticpi/.../build_drive/linux-imx/` |
| Custom DTS | `arch/arm/boot/dts/nxp/imx/imx6sl-kindle-pw3.dts` |
| imx6sl.dtsi | `arch/arm/boot/dts/nxp/imx/imx6sl.dtsi` |
| Reference wario.dtb | `bdm310/wario-hardware` repo |
| Waveform file | `/dev/mmcblk1p3` → `/eink/waveforms/320_R200_AEC241_ED060KD1C2_TC.wbf` |
| WiFi firmware | `/dev/mmcblk1p2` → `/opt/ar6k/target/AR6003/hw2.1.1/bin/` |
| max17135 driver source | `kindle-linux-3.0.35-lab126/drivers/mfd/max17135-core.c` |
| u-boot.bin load address | `0x87800000` (`CONFIG_SYS_TEXT_BASE`) |
| Kernel slot (block) | `0x208` (byte offset `0x41000` ÷ 512) |
| Diags slot (byte) | `0xE41000` — **never overwrite** |
---
## Key Technical Lessons
- **BIST ≠ stock U-Boot prompt**: BIST has `mmc`/`loady`/`source`/`go`; stock U-Boot interactive prompt only has `go` plus basic memory commands
- **Byte vs block offsets**: BIST/stock `bootm` use byte offsets; u-boot-wario `mmc read`/`write` use 512-byte block offsets — always convert (`byte ÷ 512`)
- **`bootz` vs `bootm`**: `bootz` = raw zImage only; `bootm` = legacy uImage wrapper (any compression the U-Boot supports)
- **Silent hangs = probe blocking on dependency**: the GPU/GPC power-domain hang printed nothing after `etnaviv: bound` for 5+ minutes — isolated by disabling nodes one at a time
- **eMMC dual-supply sequencing**: both `vmmc` (3.3V card power) and `vqmmc` (1.8V I/O) need `regulator-boot-on` + `regulator-always-on` when using GPIO-controlled fixed regulators — otherwise eMMC either fails to init or misidentifies
- **Reference DTB diffing**: `dtc -I dtb -O dts` to decompile any binary DTB; diffing specific nodes (not whole file) against your own tree is the fastest way to find working configuration deltas
- **Firmware timing**: ath6kl probes before rootfs mounts — firmware must be built into kernel via `EXTRA_FIRMWARE` or it will always fail to load
- **Amazon firmware is better**: generic linux-firmware `bdata.SD31/SD32.bin` insufficient for KPW3 RF calibration; Amazon's own `bdata.bin` from p2 gives working scan/connect
- **`/dev/mmcblk1` not `mmcblk0`**: under mainline's probe order with this DTS, eMMC is the second MMC device — `root=` must specify `mmcblk1p1`

View File

@@ -0,0 +1,185 @@
# Kindle Paperwhite 3 (KPW3) Mainline Linux Port — Session Summary
**Session date:** 13 June 2026
**Outcome:** 🎉 **Mainline Linux 6.15 successfully booted to a root shell on real KPW3 hardware**, using both a borrowed reference DTB and (eventually) the project's own custom DTS.
---
## Starting Point
At the start of this session, the project had:
- Confirmed hardware details (SoC, eMMC layout, peripherals — see project notes)
- A non-destructive test method via BIST `go` to chainload a new U-Boot
- `u-boot-wario` (2021.04-rc3, `bdm310/u-boot-wario`, `wario_defconfig`) built but not yet tested
- A mainline 6.15 kernel built with a stripped-down `imx_v6_v7_defconfig`
- An in-progress custom DTS (`imx6sl-kindle-pw3.dts`) for the board
- One eMMC kernel slot (`0x41000`) already overwritten with a prior lzma test image (non-stock, considered disposable)
- Diags kernel slot (`0xE41000`) intact as a recovery fallback
---
## 1. u-boot-wario Brought Up Successfully
- Used BIST: `loady` to transfer `u-boot.bin` (353KB) to `0x87800000` (`CONFIG_SYS_TEXT_BASE`), then `go 0x87800000`
- **Worked first try** — DDR was already initialized by the boot ROM, so jumping directly into the post-SPL binary (skipping SPL's DDR init) was the correct, low-risk approach
- Result: full u-boot-wario 2021.04-rc3 banner, correct SoC identification (i.MX6SL rev1.3 @ 996MHz), **512MiB DRAM correctly detected** (vs the 256MB placeholder in the Reagan Bohan gist DTS)
- Both `FSL_SDHC: 1` (eMMC) and `FSL_SDHC: 2` controllers detected
### eMMC confirmed via `mmc info`
- `mmc dev 1` (note: index **1**, not 0)
- Manufacturer: SEM04G, 3.7GiB, 8-bit bus, MMC 4.5, High Speed (52MHz)
- Boot areas (2MB each), RPMB present — matches hardware notes
### Block-offset math confirmed
- Byte offset `0x41000` = block `0x208` (= 1032 decimal) for `mmc read`/`mmc write` under u-boot-wario
- `mmc read 0x87800000 0x208 <count>` + `iminfo` successfully read back the existing lzma test image header — confirms mainline U-Boot's block-based addressing lines up correctly with the byte-offset semantics used by BIST/stock U-Boot
---
## 2. Compression Support — Resolved
- The old `0x41000` slot contained an **lzma-compressed** uImage from earlier testing
- `bootm` on that image failed: **"Unimplemented compression type 3"** — lzma not compiled into this u-boot-wario build
- **Resolution:** moved to **gzip**-compressed uImages (default for mainline kernel `uImage` target), which u-boot-wario supports out of the box
- Also clarified: `bootz` requires a raw zImage-type image; **legacy uImage-wrapped images (any compression) must use `bootm`**, not `bootz`
---
## 3. Chainload-via-stock-bootcmd — Abandoned
**Goal:** make stock 2009.08-lab126 U-Boot automatically chainload into u-boot-wario via `bootcmd=bootm 0x41000`, to avoid needing BIST+`loady` every session.
**Findings:**
- Stock U-Boot's command set (confirmed via `help`) lacks `mmc`, `source`, `loady` — these are BIST-only commands, not available at the interactive stock U-Boot prompt
- Wrote `u-boot.bin` as a `mkimage -T standalone` legacy uImage to `0x41000`
- `bootcmd=bootm 0x41000` **loaded it successfully** ("Loading Standalone Program ... OK") but **returned "OK" without jumping** — the standalone-type auto-jump either didn't occur or jumped into u-boot-wario in a state where it executed briefly then returned/reset, never printing its banner
- **Critically, this left the console unresponsive** — even chaining `bootm 0x41000; go 0x87800000` on one line did not recover an interactive prompt afterward
- **Conclusion:** this chainload approach is a dead end with this stock U-Boot. The BIST `loady` + `go` path remains the only reliable way to start u-boot-wario each session (note: u-boot.bin is only 353KB, so this transfer is fast — the real time cost was always the multi-MB kernel, addressed separately below)
---
## 4. Fast Iteration Loop Established
To avoid re-transferring the multi-MB kernel over serial every test cycle:
1. `dd` the current kernel uImage to the eMMC at byte offset `0x41000` (the disposable slot) from the development machine / diags shell
2. Each test cycle, from a freshly-started u-boot-wario prompt:
```
mmc dev 1
mmc read 0x87800000 0x208 0x5000 # ~10MB, covers a 9.3MB uImage + header
loady 0x83000000 # transfer only the small .dtb (~20KB)
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p1 rootwait ro'
bootm 0x87800000 - 0x83000000
```
3. Diags slot (`0xE41000`) kept untouched throughout as the recovery fallback
This reduced each iteration to a small DTB transfer only.
---
## 5. Kernel Rebuilt on `imx_v6_v7_defconfig`
- Switched from the heavily stripped defconfig to full `imx_v6_v7_defconfig` (size is no longer a constraint now that gzip uImages work and fit the 14MB window)
- Confirmed `CONFIG_MMC_SDHCI_ESDHC_IMX=y` present (this was a suspected gap in the old stripped config, but turned out not to be the actual blocker — see below)
- New uImage: gzip-compressed, ~9.3MB
---
## 6. The Long Hang-After-`etnaviv` Debugging Saga
Across multiple kernel boots (both stripped and full defconfig), the kernel consistently hung immediately after:
```
etnaviv etnaviv: bound 2200000.gpu (ops ...)
etnaviv etnaviv: bound 2204000.gpu (ops ...)
```
with **zero further output**, even after 5+ minutes — a true hang, not a silent/deferred probe.
### Ruled out one at a time (each via `status = "disabled"` + rebuild):
- `usdhc2` (eMMC) — not the cause
- `i2c1` (max77696 PMIC, max17135 EPD PMIC) — not the cause
- `i2c2` (cyttsp4 touchscreen) — not the cause
- `usdhc3` (WiFi/ath6kl) — not the cause
### Breakthrough via reference DTB
A second DTS source was found: **`bdm310/wario-hardware`'s `wario.dtb`** (binary only). Decompiled with `dtc -I dtb -O dts` and **booted successfully past the hang point**, all the way to a root shell on the original Amazon ext3 rootfs (`mmcblk1p1`).
### Diffing the two flattened device trees revealed the actual cause
Your DTS's `gpc@20dc000` (GPC power-controller) node included nested `pgc`/`power-domain@0/1/2` subnodes, with the **GPU nodes** (`gpu@2200000`, `gpu@2204000`) declaring `power-domains = <&pgc_power_domain_1>`. `wario.dtb` has **no GPU nodes and no nested power-domain subnodes at all**.
**Root cause:** the GPU's power-domain dependency, combined with anatop regulator settings that differ from wario.dtb's (missing `regulator-always-on` on the relevant rail), caused etnaviv's post-bind power-on call to **block indefinitely** waiting on a power domain that never becomes ready.
**Fix:** disabled `gpu_2d` and `gpu_3d` nodes (`status = "disabled"`) in the custom DTS. Boot proceeded immediately past the former hang point.
---
## 7. eMMC Power Sequencing — Second Blocker, Now Resolved
With GPU disabled, boot proceeded to `Waiting for root device /dev/mmcblk1p1...` but then failed in progressively more informative ways:
1. **First attempt** (usdhc2 still disabled from earlier isolation testing — forgot to re-enable): no `mmcblk1` device at all. *(Fixed by re-enabling `usdhc2`.)*
2. **Second attempt** (`usdhc2` enabled, both `vmmc-supply`/`vqmmc-supply` present, neither `boot-on`/`always-on`):
- Card misidentified as `SDM032 30.6 MiB` (wrong — real eMMC is `SEM04G 3.69 GiB`)
- `Power: 0x00000000` in SDHCI register dump — **no power being supplied to the card**
- Timeout waiting for hardware interrupt, eventual kernel panic (unable to mount root)
3. **Third attempt** (dropped `vmmc-supply`, kept only `vqmmc-supply` with `regulator-boot-on; regulator-always-on;`, matching wario.dtb's single-supply approach):
- New failure: `mmc1: Card stuck being busy! __mmc_poll_for_busy` (repeated, then "Failed to initialize a non-removable card")
- Different failure mode = real progress (card now powered, but stuck in a busy/voltage-switch state)
4. **Fourth attempt — SUCCESS:** re-added **both** `vmmc-supply` (`emmc_3v3`, gpio-113) and `vqmmc-supply` (`emmc_1v8`, gpio-119), with **`regulator-boot-on; regulator-always-on;` added to BOTH regulators** (not just one).
**Result: full boot to root shell**, using the project's own `imx6sl-kindle-pw3.dts`:
```
mmc1: new high speed DDR MMC card at address 0001
mmcblk1: mmc1:0001 SEM04G 3.69 GiB
mmcblk1: p1 p2 p3 p4
mmcblk1boot0/boot1/rpmb: ... 2.00 MiB
EXT4-fs (mmcblk1p1): mounted filesystem ... ro
Run /bin/sh as init process
/ #
```
---
## Current Known-Working DTS Configuration
`imx6sl-kindle-pw3.dts`, working state at end of session:
| Node | Status | Notes |
|---|---|---|
| `uart1` | ✅ enabled | console working throughout |
| `usdhc2` (eMMC) | ✅ enabled | requires `pinctrl_usdhc2`, **both** `vmmc-supply`/`vqmmc-supply` with `regulator-boot-on; regulator-always-on;` on both `emmc_3v3` and `emmc_1v8` |
| `gpu_2d` / `gpu_3d` | ❌ disabled | causes hang via GPC power-domain dependency; needs anatop regulator fix (`regulator-always-on` on relevant rail) before re-enabling |
| `i2c1` (max77696 PMIC, max17135 EPD PMIC) | ❌ disabled | disabled during isolation testing, not yet re-tested in working config; also has a dtc warning: `max17135@48` node name doesn't match `reg = <0x34>` |
| `i2c2` (cyttsp4 touchscreen) | ❌ disabled | disabled during isolation testing, not yet re-tested |
| `usdhc3` (WiFi/ath6kl) | ❌ disabled | disabled during isolation testing, not yet re-tested |
| `wdog1` | ✅ enabled | present in working boot, not yet stress-tested for long-running stability |
`root=/dev/mmcblk1p1` (note: **mmcblk1**, not mmcblk0 — eMMC is the second MMC device under mainline's probe order with this DTS)
---
## Next Steps
1. **Re-enable incrementally, one at a time**, using the now-fast iteration loop (BIST `go` → `mmc read` kernel from `0x41000` → `loady` dtb → `bootm`):
- `i2c1` (PMIC/EPD) — fix `max17135@48` reg/name mismatch (`reg = <0x34>` per hardware notes, not `0x48`) while re-enabling
- `i2c2` (touchscreen)
- `usdhc3` (WiFi)
2. **GPU**: compare anatop regulator `regulator-min/max-microvolt` and `anatop-enable-bit`/`regulator-always-on` settings between your DTS and wario.dtb to find the specific fix needed to re-enable `gpu_2d`/`gpu_3d` without reintroducing the power-domain hang
3. **Watchdog**: verify `wdog1` is actively serviced by mainline's `imx2-wdt` during longer-running sessions (hardware notes flag this as active/must-be-serviced)
4. **Persistence**: now that a known-working kernel+DTS combination exists, consider:
- Writing the working DTB to a fixed eMMC offset (avoiding `loady` entirely)
- Revisiting U-Boot persistence options (the standalone-chainload approach was abandoned, but other options — e.g. flashing u-boot-wario to the boot ROM's primary search location — remain on the table, with appropriate backups)
5. **Full backup**: before any further eMMC writes beyond the disposable `0x41000` slot, take a full or partial `dd` backup of `/dev/mmcblk0` from the diags shell
---
## Key Technical Lessons
- **BIST and stock U-Boot are different command environments** — BIST has `mmc`, `loady`, `source`, `go`; stock U-Boot's interactive prompt has none of these except `go`
- **`mmc read`/`write` use block (512-byte) offsets** in mainline U-Boot, vs **byte offsets** in BIST/stock U-Boot's patched `bootm` — always convert (`byte_offset / 512`)
- **`bootz` requires raw zImage type; `bootm` handles legacy uImage-wrapped images** regardless of inner compression (provided the compression algorithm is supported by that U-Boot build)
- **A clean "hang with zero output" after a specific driver bind is often a *later* driver blocking on a dependency** (e.g. GPU blocking on a GPC power domain) — isolate by disabling nodes one at a time, but also consider what comes *after* the last successful message, not just the message itself
- **eMMC power sequencing matters**: both `vmmc` (card power) and `vqmmc` (I/O voltage) supplies often need `regulator-boot-on` + `regulator-always-on` for non-removable eMMC, especially when using GPIO-controlled fixed regulators rather than always-on board rails
- **A working reference DTB (even without source) is extremely valuable** — `dtc -I dtb -O dts` to decompile, then diff specific nodes against your own tree to find configuration deltas

View File

@@ -0,0 +1,235 @@
# max77696-epd Regulator Driver — Development Summary
**Last updated:** 18 June 2026
**File:** `drivers/regulator/max77696-regulator.c`
**Compatible string:** `maxim,max77696-epd` (kept narrower than the filename —
see "Naming" note below)
**Status:** ✅ Builds clean (both built-in and as a module). Probes successfully
on real hardware via DT; all three regulators confirmed registered with
correct names. Enable/disable path not yet exercised on hardware.
---
## Purpose
A standalone regulator driver exposing the three EPD power rails the mainline
i.MX6SL EPDC driver (`drivers/gpu/drm/mxc-epdc/`, from Andreas Kemnade's tree)
requires by name:
- `DISPLAY` — master EPD power enable
- `VCOM` — VCOM rail enable
- `V3P3` — 3.3V rail enable
These three rails are all controlled by individual bits within a single register
(`EPDCNFG`, address `0x60`) on the MAX77696 PMIC's internal EPD power block.
This driver intentionally does **not** depend on a full MAX77696 MFD driver,
since none exists in mainline. It probes directly as a standalone I2C client on
the MAX77696's main address (`0x3c`) and only touches the EPD register subset
(`0x60``0x68`, `0xB2``0xB5`). It is expected to be superseded by a proper MFD
sub-driver once a mainline MAX77696 core driver exists — noted in the file's
header comment.
---
## Naming
The source file was renamed from `max77696-epd.c` to `max77696-regulator.c`
to match the naming convention of other regulator drivers in
`drivers/regulator/` (subsystem-first naming).
The DT `compatible` string and I2C device ID were **deliberately left
unchanged** as `maxim,max77696-epd` / `max77696-epd`. Rationale: the
filename describes the driver's category (a regulator driver, part of the
max77696 family); the compatible string describes the specific hardware
function block being bound (the EPD power sub-block specifically). These
are allowed to diverge. Renaming the compatible string to something like
`maxim,max77696-regulator` would have implied coverage of all max77696
regulator outputs, when this driver only covers the EPD block's three
rails — keeping `-epd` avoids a future naming collision if a separate
driver ever covers the rest of max77696's regulators (e.g. once a proper
MFD core driver exists).
---
## Hardware Validation (18 June 2026 session)
Built as a module (`CONFIG_REGULATOR_MAX77696_EPD=m`) and tested on real
KPW3 hardware via `insmod` after merging the DT node (see
`kindle-pw3-mainline-progress.md` for the DTS change) and sending the
rebuilt `.dtb` over U-Boot serial.
**Results:**
| Check | Result |
|---|---|
| Module load | Clean. Kernel taint warning is expected for any out-of-tree module load and is not an error. |
| I2C driver bind | `/sys/bus/i2c/drivers/max77696-epd/0-003c` present — confirms driver bound to device at bus 0, address `0x3c` |
| Regulator registration | All three present and correctly named under `/sys/class/regulator/`: `DISPLAY` (regulator.10), `VCOM` (regulator.11), `V3P3` (regulator.12) |
| DT name-matching | Confirmed working — regulator core matched descriptors to DT subnodes by name with no explicit `.of_match` set in the driver |
| Baseline register state | `EPDCNFG` (`0x60`) reads `0x00` via `cat /sys/kernel/debug/regmap/0-003c/registers` — confirms no spurious enable writes happen during probe (this was one of the original bugs fixed earlier; confirmed not to have regressed) |
| sysfs `state` | Reports `disabled`, `num_users: 0` — expected, no consumer exists yet to call `regulator_enable()` |
**Useful commands for next session:**
```sh
# confirm driver bound
ls /sys/bus/i2c/drivers/max77696-epd/
# list all regulators with names (they are NOT numbered consistently across boots)
for r in /sys/class/regulator/regulator.*; do echo "$r: $(cat $r/name 2>/dev/null)"; done
# read live register state without conflicting with the kernel-held I2C client
# (direct i2cget while the driver is bound returns "Resource busy", which is
# expected/correct, not a fault)
mount -t debugfs none /sys/kernel/debug # if not already mounted
cat /sys/kernel/debug/regmap/0-003c/registers
```
**Not yet tested:** actually calling `regulator_enable()`/`disable()` and
confirming the bit flips in `EPDCNFG`. sysfs `state` is read-only without
a `CONFIG_REGULATOR_USERSPACE_CONSUMER`-style consumer or
`regulator-allow-set-load`-equivalent DT permission, neither of which is
currently set on these subnodes. Options for next session: temporary
userspace-consumer test, or proceed directly to EPDC integration (the
real eventual consumer) and validate enable/disable through that.
---
Initial investigation assumed the KPW3 used a discrete MAX17135 EPD PMIC (per
earlier project notes and i2cdetect output showing devices at `0x34`/`0x35`).
This was disproven during this session:
- No reference to `max17135` exists anywhere in the Amazon board file
(`board-mx6sl_wario.c`/`.h`)
- `0x34`/`0x35`/`0x68` are all **MAX77696 sub-addresses**, not separate chips
- The stock Amazon 3.0.35 kernel log confirms EPD power is provided entirely by
MAX77696's internal regulators: `max77696-display`, `max77696-vcom`,
`max77696-vee`, `max77696-vneg`, `max77696-vpos`, `max77696-vddh`
The Amazon kernel's `drivers/regulator/max77696-epd.c` was used as the reference
register map and behavioural source, but could not be used directly — it depends
on Amazon's entire custom MAX77696 MFD framework (`max77696_chip`, `max77696_i2c`,
`max77696_eventhandler_register`, `VREG_REG()` macros, proprietary event/logging
subsystems) none of which exist in mainline.
---
## Register Map Used
Extracted from the Amazon kernel's `include/max77696_registers.h`:
| Register | Address | Bits used |
|---|---|---|
| `EPDCNFG` | `0x60` | bit7 `EPDEN` (DISPLAY), bit6 `VCOMEN` (VCOM), bit1 `SSHVDDH` (V3P3) |
Only this single register is currently used. The fuller register set
(`EPDVCOM`, `EPDVDDH`, `EPDINT`, etc. — see prior session summary) is reserved
for future voltage-control and fault-reporting support.
---
## Design Decisions Made
1. **Standalone driver, not MFD sub-device** — simpler to get working now;
matches the scope of what's actually needed today.
2. **regmap (8-bit reg, 8-bit val)** — chosen for mainline-style consistency and
to ease future maintenance/upstreaming, rather than raw `i2c_smbus_*` calls.
3. **`enable_reg`/`enable_mask` regmap helper ops** instead of hand-written
enable/disable/is_enabled functions — `regulator_enable_regmap`,
`regulator_disable_regmap`, and `regulator_is_enabled_regmap` are mainline
helpers that read the register/mask directly off the `regulator_desc`,
eliminating ~36 lines of repetitive boilerplate across three near-identical
trios of functions. This is the idiomatic pattern used by many existing
regulator drivers in `drivers/regulator/`.
4. **`struct max77696_epd_data` retained** even though the regmap helper ops
don't need it (they reach the regmap via `rdev_get_regmap()`, populated from
`regulator_config.regmap`). Kept as scaffolding for an anticipated future
need: a `pwrgood` GPIO descriptor for a custom `is_enabled`/status check on
`DISPLAY` specifically, mirroring the Amazon driver's `_display_is_enabled()`
which also checks the `EPDINT` fault register and a `pwrgood_gpio` line, not
just the enable bit.
5. **Voltage control deferred** — VCOM and V3P3 voltage-setting registers
(`EPDVCOM`/`EPDVCOMR`, `EPDVDDH`) are documented but not yet wired up.
Enable/disable only for this pass, per explicit scoping decision early in
the session.
---
## Bugs Found and Fixed During Development
| Issue | Problem | Fix |
|---|---|---|
| Dead/incorrect read helper | `max77696_epd_read_reg()` passed the I2C slave address (`0x3c`) as a register address to `regmap_read` | Removed; regmap already knows the slave address from `devm_regmap_init_i2c` |
| Misleading register macros | `DISPLAY_REG`, `VCOM_REG`, `V3P3_REG` were three separate macros all defined as `0x60`, obscuring that they share one register | Replaced with single `EPDCNFG_REG` + three named bitmasks (`EPDCNFG_EPDEN`, `EPDCNFG_VCOMEN`, `EPDCNFG_SSHVDDH`) |
| Unconditional register write in probe | `regmap_set_bits()` called directly in `probe()` permanently enabled all three rails at boot with no way to disable them, and bypassed the regulator framework entirely | Replaced with proper `regulator_desc`/`regulator_ops` registration via `devm_regulator_register()` |
| `regmap_set_bits` masking risk | Using `set_bits` (OR only) on a shared register risks fine, but the broader pattern of independent reads/writes per "register" risked clobbering other rails' bits | Switched to `regmap_update_bits()` semantics (via the regmap helper ops), which only ever touch the specified mask |
| Missing struct / dangling `rdev_get_drvdata` | Ops functions referenced `struct max77696_epd_data` and called `rdev_get_drvdata(rdev)` but the struct was deleted and `driver_data` was never set in `regulator_config` | Re-added struct, allocated via `devm_kzalloc`, set `config.driver_data = data` |
| Wrong field for driver data | `regulator_config.regmap` was being set, expecting it to populate `rdev_get_drvdata()` | Clarified that `.regmap` and `.driver_data` are separate mechanisms; both are now set for their respective purposes (regmap helper ops use `.regmap`; any future custom ops use `.driver_data`) |
| Missing ops/descriptors | `max77696_epd_regs[]` referenced `max77696_epd_vcom_ops` and `max77696_epd_v3p3_ops` before they were written | Resolved by switching to the shared `max77696_epd_regmap_ops` approach — one ops struct now serves all three descriptors |
| Undefined enum/array size | `MAX77696_EPD_NUM_REGS`, `MAX77696_EPD_DISPLAY`, etc. used without declaration | Added explicit `enum { ... }` block before the descriptor array |
| Naming inconsistency | Probe loop referenced `max77696_epd_regulators[]` while the array was declared as `max77696_epd_regs[]` | Standardised on `max77696_epd_regs` throughout |
| DT/I2C naming convention | `compatible = "maxim,max77696_epd"` and i2c device id `"max77696_epd"` used underscores | Changed to hyphenated form (`maxim,max77696-epd`, `max77696-epd`) per Linux DT/i2c naming conventions, relevant for passing `dt-schema` validation when upstreaming |
---
## Current Driver Structure (Final State This Session)
```c
enum { MAX77696_EPD_DISPLAY, MAX77696_EPD_VCOM, MAX77696_EPD_V3P3, MAX77696_EPD_NUM_REGS };
struct max77696_epd_data {
struct regmap *regmap;
};
static const struct regulator_ops max77696_epd_regmap_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
static const struct regulator_desc max77696_epd_regs[MAX77696_EPD_NUM_REGS] = {
[MAX77696_EPD_DISPLAY] = { .name = "DISPLAY", .enable_reg = EPDCNFG_REG, .enable_mask = EPDCNFG_EPDEN, ... },
[MAX77696_EPD_VCOM] = { .name = "VCOM", .enable_reg = EPDCNFG_REG, .enable_mask = EPDCNFG_VCOMEN, ... },
[MAX77696_EPD_V3P3] = { .name = "V3P3", .enable_reg = EPDCNFG_REG, .enable_mask = EPDCNFG_SSHVDDH, ... },
};
```
Probe allocates `max77696_epd_data`, initialises regmap, and loops over the
three descriptors calling `devm_regulator_register()` with both `.driver_data`
and `.regmap` set in `regulator_config`.
---
## Next Steps
1. ~~**Isolated module build**~~ — ✅ Done. Builds clean both built-in and as
a module.
2. ~~**Makefile/Kconfig wiring**~~ — ✅ Done. `CONFIG_REGULATOR_MAX77696_EPD`
set as `tristate` in `drivers/regulator/Kconfig`; `Makefile` entry points
at `max77696-regulator.o`.
3. ~~**DTS node**~~ — ✅ Done and validated on hardware. See
`kindle-pw3-mainline-progress.md` for the merged node. Replaced the
placeholder `max77696: pmic@3c` node (duplicate address conflict —
only one node may exist per I2C address).
4. **Hardware validation** — Partially done. Confirmed: driver binds,
regulators register with correct names via DT matching, baseline
register state is correct (no spurious writes at probe). **Remaining:**
confirm `regulator_enable()`/`disable()` actually toggles bits in
`0x60`, since sysfs `state` is read-only without a consumer currently
wired up.
5. **Future enhancement** — add VCOM/V3P3 voltage control
(`set_voltage`/`get_voltage` ops) and a `pwrgood`-aware custom `is_enabled`
for DISPLAY, once basic enable/disable is confirmed working on hardware.
6. **Next major step:** EPDC DTS node (pinctrl, panel timing, waveform
reference, regulator supply references) — this is the real eventual
consumer that will exercise enable/disable naturally. See
`kindle-pw3-mainline-progress.md` "Following: EPDC DTS Node".

View File

@@ -0,0 +1,162 @@
# max77696-epd Regulator Driver — Development Summary
**Last updated:** 15 June 2026
**File:** `drivers/regulator/max77696-epd.c`
**Status:** Source complete, pending isolated build test
---
## Purpose
A standalone regulator driver exposing the three EPD power rails the mainline
i.MX6SL EPDC driver (`drivers/gpu/drm/mxc-epdc/`, from Andreas Kemnade's tree)
requires by name:
- `DISPLAY` — master EPD power enable
- `VCOM` — VCOM rail enable
- `V3P3` — 3.3V rail enable
These three rails are all controlled by individual bits within a single register
(`EPDCNFG`, address `0x60`) on the MAX77696 PMIC's internal EPD power block.
This driver intentionally does **not** depend on a full MAX77696 MFD driver,
since none exists in mainline. It probes directly as a standalone I2C client on
the MAX77696's main address (`0x3c`) and only touches the EPD register subset
(`0x60``0x68`, `0xB2``0xB5`). It is expected to be superseded by a proper MFD
sub-driver once a mainline MAX77696 core driver exists — noted in the file's
header comment.
---
## Background: Why This Driver Is Needed
Initial investigation assumed the KPW3 used a discrete MAX17135 EPD PMIC (per
earlier project notes and i2cdetect output showing devices at `0x34`/`0x35`).
This was disproven during this session:
- No reference to `max17135` exists anywhere in the Amazon board file
(`board-mx6sl_wario.c`/`.h`)
- `0x34`/`0x35`/`0x68` are all **MAX77696 sub-addresses**, not separate chips
- The stock Amazon 3.0.35 kernel log confirms EPD power is provided entirely by
MAX77696's internal regulators: `max77696-display`, `max77696-vcom`,
`max77696-vee`, `max77696-vneg`, `max77696-vpos`, `max77696-vddh`
The Amazon kernel's `drivers/regulator/max77696-epd.c` was used as the reference
register map and behavioural source, but could not be used directly — it depends
on Amazon's entire custom MAX77696 MFD framework (`max77696_chip`, `max77696_i2c`,
`max77696_eventhandler_register`, `VREG_REG()` macros, proprietary event/logging
subsystems) none of which exist in mainline.
---
## Register Map Used
Extracted from the Amazon kernel's `include/max77696_registers.h`:
| Register | Address | Bits used |
|---|---|---|
| `EPDCNFG` | `0x60` | bit7 `EPDEN` (DISPLAY), bit6 `VCOMEN` (VCOM), bit1 `SSHVDDH` (V3P3) |
Only this single register is currently used. The fuller register set
(`EPDVCOM`, `EPDVDDH`, `EPDINT`, etc. — see prior session summary) is reserved
for future voltage-control and fault-reporting support.
---
## Design Decisions Made
1. **Standalone driver, not MFD sub-device** — simpler to get working now;
matches the scope of what's actually needed today.
2. **regmap (8-bit reg, 8-bit val)** — chosen for mainline-style consistency and
to ease future maintenance/upstreaming, rather than raw `i2c_smbus_*` calls.
3. **`enable_reg`/`enable_mask` regmap helper ops** instead of hand-written
enable/disable/is_enabled functions — `regulator_enable_regmap`,
`regulator_disable_regmap`, and `regulator_is_enabled_regmap` are mainline
helpers that read the register/mask directly off the `regulator_desc`,
eliminating ~36 lines of repetitive boilerplate across three near-identical
trios of functions. This is the idiomatic pattern used by many existing
regulator drivers in `drivers/regulator/`.
4. **`struct max77696_epd_data` retained** even though the regmap helper ops
don't need it (they reach the regmap via `rdev_get_regmap()`, populated from
`regulator_config.regmap`). Kept as scaffolding for an anticipated future
need: a `pwrgood` GPIO descriptor for a custom `is_enabled`/status check on
`DISPLAY` specifically, mirroring the Amazon driver's `_display_is_enabled()`
which also checks the `EPDINT` fault register and a `pwrgood_gpio` line, not
just the enable bit.
5. **Voltage control deferred** — VCOM and V3P3 voltage-setting registers
(`EPDVCOM`/`EPDVCOMR`, `EPDVDDH`) are documented but not yet wired up.
Enable/disable only for this pass, per explicit scoping decision early in
the session.
---
## Bugs Found and Fixed During Development
| Issue | Problem | Fix |
|---|---|---|
| Dead/incorrect read helper | `max77696_epd_read_reg()` passed the I2C slave address (`0x3c`) as a register address to `regmap_read` | Removed; regmap already knows the slave address from `devm_regmap_init_i2c` |
| Misleading register macros | `DISPLAY_REG`, `VCOM_REG`, `V3P3_REG` were three separate macros all defined as `0x60`, obscuring that they share one register | Replaced with single `EPDCNFG_REG` + three named bitmasks (`EPDCNFG_EPDEN`, `EPDCNFG_VCOMEN`, `EPDCNFG_SSHVDDH`) |
| Unconditional register write in probe | `regmap_set_bits()` called directly in `probe()` permanently enabled all three rails at boot with no way to disable them, and bypassed the regulator framework entirely | Replaced with proper `regulator_desc`/`regulator_ops` registration via `devm_regulator_register()` |
| `regmap_set_bits` masking risk | Using `set_bits` (OR only) on a shared register risks fine, but the broader pattern of independent reads/writes per "register" risked clobbering other rails' bits | Switched to `regmap_update_bits()` semantics (via the regmap helper ops), which only ever touch the specified mask |
| Missing struct / dangling `rdev_get_drvdata` | Ops functions referenced `struct max77696_epd_data` and called `rdev_get_drvdata(rdev)` but the struct was deleted and `driver_data` was never set in `regulator_config` | Re-added struct, allocated via `devm_kzalloc`, set `config.driver_data = data` |
| Wrong field for driver data | `regulator_config.regmap` was being set, expecting it to populate `rdev_get_drvdata()` | Clarified that `.regmap` and `.driver_data` are separate mechanisms; both are now set for their respective purposes (regmap helper ops use `.regmap`; any future custom ops use `.driver_data`) |
| Missing ops/descriptors | `max77696_epd_regs[]` referenced `max77696_epd_vcom_ops` and `max77696_epd_v3p3_ops` before they were written | Resolved by switching to the shared `max77696_epd_regmap_ops` approach — one ops struct now serves all three descriptors |
| Undefined enum/array size | `MAX77696_EPD_NUM_REGS`, `MAX77696_EPD_DISPLAY`, etc. used without declaration | Added explicit `enum { ... }` block before the descriptor array |
| Naming inconsistency | Probe loop referenced `max77696_epd_regulators[]` while the array was declared as `max77696_epd_regs[]` | Standardised on `max77696_epd_regs` throughout |
| DT/I2C naming convention | `compatible = "maxim,max77696_epd"` and i2c device id `"max77696_epd"` used underscores | Changed to hyphenated form (`maxim,max77696-epd`, `max77696-epd`) per Linux DT/i2c naming conventions, relevant for passing `dt-schema` validation when upstreaming |
---
## Current Driver Structure (Final State This Session)
```c
enum { MAX77696_EPD_DISPLAY, MAX77696_EPD_VCOM, MAX77696_EPD_V3P3, MAX77696_EPD_NUM_REGS };
struct max77696_epd_data {
struct regmap *regmap;
};
static const struct regulator_ops max77696_epd_regmap_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
static const struct regulator_desc max77696_epd_regs[MAX77696_EPD_NUM_REGS] = {
[MAX77696_EPD_DISPLAY] = { .name = "DISPLAY", .enable_reg = EPDCNFG_REG, .enable_mask = EPDCNFG_EPDEN, ... },
[MAX77696_EPD_VCOM] = { .name = "VCOM", .enable_reg = EPDCNFG_REG, .enable_mask = EPDCNFG_VCOMEN, ... },
[MAX77696_EPD_V3P3] = { .name = "V3P3", .enable_reg = EPDCNFG_REG, .enable_mask = EPDCNFG_SSHVDDH, ... },
};
```
Probe allocates `max77696_epd_data`, initialises regmap, and loops over the
three descriptors calling `devm_regulator_register()` with both `.driver_data`
and `.regmap` set in `regulator_config`.
---
## Next Steps
1. **Isolated module build** — compile `max77696-epd.o` against the kernel tree
in isolation (`make ... M=drivers/regulator max77696-epd.o`) to catch any
remaining syntax issues before full integration.
2. **Makefile/Kconfig wiring** — add a `CONFIG_REGULATOR_MAX77696_EPD` entry to
`drivers/regulator/Kconfig` (depends on `I2C`, selects `REGMAP_I2C`) and the
corresponding line in `drivers/regulator/Makefile`.
3. **DTS node** — add the `max77696_epd` node (sketched in prior session) with
`regulators { DISPLAY {}; VCOM {}; V3P3 {}; }` subnodes, once the driver
builds cleanly.
4. **Hardware validation** — confirm `regulator_enable()`/`disable()` calls from
userspace (via sysfs `/sys/class/regulator/.../state`) actually toggle the
expected bits, cross-checked against an i2cdump of `0x60`.
5. **Future enhancement** — add VCOM/V3P3 voltage control
(`set_voltage`/`get_voltage` ops) and a `pwrgood`-aware custom `is_enabled`
for DISPLAY, once basic enable/disable is confirmed working on hardware.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
u-boot/test/ath6/fw-2.bin Normal file

Binary file not shown.

BIN
u-boot/test/ath6/fw-3.bin Normal file

Binary file not shown.

BIN
u-boot/test/ath6/otp.bin Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,209 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include "imx6sl.dtsi"
#include "imx6sl-pinfunc.h"
/ {
model = "Amazon Kindle Paperwhite 3 (Wario)";
compatible = "amazon,kindle-pw3", "fsl,imx6sl";
aliases {
mmc1 = &usdhc2;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
chosen {
stdout-path = &uart1;
};
regulators {
compatible = "simple-bus";
emmc_3v3: regulator-emmc-3v3 {
compatible = "regulator-fixed";
regulator-name = "emmc-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio4 17 0>; /* gpio-113 */
enable-active-high;
regulator-always-on;
regulator-boot-on;
};
emmc_1v8: regulator-emmc-1v8 {
compatible = "regulator-fixed";
regulator-name = "emmc-1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio4 23 0>; /* gpio-119 */
enable-active-high;
regulator-always-on;
regulator-boot-on;
};
wifi_pwr: regulator-wifi {
compatible = "regulator-fixed";
regulator-name = "wifi-pwr";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio3 29 0>; /* gpio-93 */
enable-active-high;
};
};
};
&iomuxc {
pinctrl-names = "default";
imx6sl-kindle {
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1
MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1
>;
};
pinctrl_usdhc2: usdhc2grp {
fsl,pins = <
/*
LVE_ENABLED,HYS_ENABLED,PUS_22KOHM_PU,PUE_PULL,
PKE_ENABLED,ODE_DISABLED,SPD_100MHZ,DSE_40OHM,SRE_FAST
*/
MX6SL_PAD_SD2_CLK__SD2_CLK 0x41F071
MX6SL_PAD_SD2_CMD__SD2_CMD 0x41F071
MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x41F071
MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x41F071
MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x41F071
MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x41F071
MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x41F071
MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x41F071
MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x41F071
MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x41F071
/*
LVE_ENABLED,HYS_ENABLED,PUS_100KOHM_PU,PUE_PULL,
PKE_ENABLED,ODE_DISABLED,SPD_100MHZ,DSE_40OHM,SRE_FAST
*/
MX6SL_PAD_SD2_RST__SD2_RESET 0x413071
>;
};
pinctrl_usdhc3: usdhc3grp {
fsl,pins = <
MX6SL_PAD_SD3_CMD__SD3_CMD 0x41f0b1
MX6SL_PAD_SD3_CLK__SD3_CLK 0x41f0b1
MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x41f0b1
MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x41f0b1
MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x41f0b1
MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x41f0b1
>;
};
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1
MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1
>;
};
};
};
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
status = "okay";
};
/* eMMC */
&usdhc2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc2>;
bus-width = <8>;
non-removable;
vqmmc-supply = <&emmc_1v8>;
vmmc-supply = <&emmc_3v3>;
status = "okay";
};
/* WiFi — ath6kl on SDIO */
&usdhc3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc3>;
bus-width = <4>;
non-removable;
vmmc-supply = <&wifi_pwr>;
status = "okay";
};
/*
* EPD power (max77696 internal EPD block) on I2C0.
* Driver: drivers/regulator/max77696-epd.c, compatible "maxim,max77696-epd".
* Touches only the EPD register subset (0x60-0x68, 0xB2-0xB5) — not a
* full MAX77696 MFD driver, since none exists in mainline yet.
*
* RTC at 0x68 is a max77696 internal sub-address, not a separate chip
* (confirmed: not ds1307). Not yet exposed — using SNVS RTC for now.
*/
&i2c1 {
clock-frequency = <100000>;
status = "okay";
max77696_epd: epd-pmic@3c {
compatible = "maxim,max77696-epd";
reg = <0x3c>;
interrupt-parent = <&gpio4>;
interrupts = <20 IRQ_TYPE_LEVEL_LOW>; /* gpio-116 */
/*
* pwrgood-gpios intentionally omitted — driver does not request
* it yet (see max77696-epd-driver-summary.md design decision #4).
* Add once a pwrgood-aware is_enabled for DISPLAY exists:
* pwrgood-gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
*/
regulators {
DISPLAY_reg: DISPLAY {
regulator-name = "DISPLAY";
};
VCOM_reg: VCOM {
regulator-name = "VCOM";
};
V3P3_reg: V3P3 {
regulator-name = "V3P3";
};
};
};
};
/* Touchscreen on I2C1 */
&i2c2 {
clock-frequency = <100000>;
status = "okay";
touchscreen@24 {
compatible = "cypress,cyttsp4-i2c";
reg = <0x24>;
interrupt-parent = <&gpio2>;
interrupts = <24 IRQ_TYPE_EDGE_FALLING>; /* gpio-88, touch_not_used? */
};
};
/* Watchdog — enable so mainline manages it */
&wdog1 {
status = "okay";
};
&gpu_2d {
status = "disabled";
};
&gpu_vg {
status = "disabled";
};

7760
u-boot/test/kernel.config Normal file

File diff suppressed because it is too large Load Diff

BIN
u-boot/test/u-boot.bin Normal file

Binary file not shown.

BIN
u-boot/test/uImage Normal file

Binary file not shown.

BIN
u-boot/test/uboot.img Normal file

Binary file not shown.

BIN
u-boot/test/wario.dtb Normal file

Binary file not shown.

850
u-boot/test/wario_flat.dts Normal file
View File

@@ -0,0 +1,850 @@
/dts-v1/;
/ {
#address-cells = <0x01>;
#size-cells = <0x01>;
model = "Amazon Wario";
compatible = "amazon,wario", "fsl,imx6sl";
chosen {
};
memory {
device_type = "memory";
reg = <0x80000000 0x40000000>;
};
aliases {
ethernet0 = "/soc/aips-bus@02100000/ethernet@02188000";
gpio0 = "/soc/aips-bus@02000000/gpio@0209c000";
gpio1 = "/soc/aips-bus@02000000/gpio@020a0000";
gpio2 = "/soc/aips-bus@02000000/gpio@020a4000";
gpio3 = "/soc/aips-bus@02000000/gpio@020a8000";
gpio4 = "/soc/aips-bus@02000000/gpio@020ac000";
serial0 = "/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000";
serial1 = "/soc/aips-bus@02000000/spba-bus@02000000/serial@02024000";
serial2 = "/soc/aips-bus@02000000/spba-bus@02000000/serial@02034000";
serial3 = "/soc/aips-bus@02000000/spba-bus@02000000/serial@02038000";
serial4 = "/soc/aips-bus@02000000/spba-bus@02000000/serial@02018000";
spi0 = "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02008000";
spi1 = "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@0200c000";
spi2 = "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000";
spi3 = "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02014000";
usbphy0 = "/soc/aips-bus@02000000/usbphy@020c9000";
usbphy1 = "/soc/aips-bus@02000000/usbphy@020ca000";
mmc1 = "/soc/aips-bus@02100000/usdhc@02194000";
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
cpu@0 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <0x00>;
next-level-cache = <0x01>;
operating-points = <0xf32a0 0x137478 0xc15c0 0x11edd8 0x60ae0 0xee098>;
fsl,soc-operating-points = <0xf32a0 0x12b128 0xc15c0 0x11edd8 0x60ae0 0x11edd8>;
clock-latency = <0xee6c>;
clocks = <0x02 0x5f 0x02 0x14 0x02 0x1d 0x02 0x1e 0x02 0x03>;
clock-names = "arm", "pll2_pfd2_396m", "step", "pll1_sw", "pll1_sys";
arm-supply = <0x03>;
pu-supply = <0x04>;
soc-supply = <0x05>;
};
};
interrupt-controller@00a01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <0x03>;
interrupt-controller;
reg = <0xa01000 0x1000 0xa00100 0x100>;
interrupt-parent = <0x06>;
phandle = <0x06>;
};
clocks {
#address-cells = <0x01>;
#size-cells = <0x00>;
ckil {
compatible = "fixed-clock";
#clock-cells = <0x00>;
clock-frequency = <0x8000>;
};
osc {
compatible = "fixed-clock";
#clock-cells = <0x00>;
clock-frequency = <0x16e3600>;
};
};
soc {
#address-cells = <0x01>;
#size-cells = <0x01>;
compatible = "simple-bus";
interrupt-parent = <0x07>;
ranges;
sram@00900000 {
compatible = "mmio-sram";
reg = <0x900000 0x20000>;
clocks = <0x02 0x74>;
};
l2-cache@00a02000 {
compatible = "arm,pl310-cache";
reg = <0xa02000 0x1000>;
interrupts = <0x00 0x5c 0x04>;
cache-unified;
cache-level = <0x02>;
arm,tag-latency = <0x04 0x02 0x03>;
arm,data-latency = <0x04 0x02 0x03>;
phandle = <0x01>;
};
pmu {
compatible = "arm,cortex-a9-pmu";
interrupts = <0x00 0x5e 0x04>;
};
aips-bus@02000000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <0x01>;
#size-cells = <0x01>;
reg = <0x2000000 0x100000>;
ranges;
spba-bus@02000000 {
compatible = "fsl,spba-bus", "simple-bus";
#address-cells = <0x01>;
#size-cells = <0x01>;
reg = <0x2000000 0x40000>;
ranges;
spdif@02004000 {
compatible = "fsl,imx6sl-spdif", "fsl,imx35-spdif";
reg = <0x2004000 0x4000>;
interrupts = <0x00 0x34 0x04>;
dmas = <0x08 0x0e 0x12 0x00 0x08 0x0f 0x12 0x00>;
dma-names = "rx", "tx";
clocks = <0x02 0xa4 0x02 0x02 0x02 0x7a 0x02 0x00 0x02 0x00 0x02 0x00 0x02 0x3f 0x02 0x00 0x02 0x00 0x02 0x86>;
clock-names = "core", "rxtx0", "rxtx1", "rxtx2", "rxtx3", "rxtx4", "rxtx5", "rxtx6", "rxtx7", "spba";
status = "disabled";
};
ecspi@02008000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi";
reg = <0x2008000 0x4000>;
interrupts = <0x00 0x1f 0x04>;
clocks = <0x02 0x60 0x02 0x60>;
clock-names = "ipg", "per";
status = "disabled";
};
ecspi@0200c000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi";
reg = <0x200c000 0x4000>;
interrupts = <0x00 0x20 0x04>;
clocks = <0x02 0x61 0x02 0x61>;
clock-names = "ipg", "per";
status = "disabled";
};
ecspi@02010000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi";
reg = <0x2010000 0x4000>;
interrupts = <0x00 0x21 0x04>;
clocks = <0x02 0x62 0x02 0x62>;
clock-names = "ipg", "per";
status = "disabled";
};
ecspi@02014000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi";
reg = <0x2014000 0x4000>;
interrupts = <0x00 0x22 0x04>;
clocks = <0x02 0x63 0x02 0x63>;
clock-names = "ipg", "per";
status = "disabled";
};
serial@02018000 {
compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart";
reg = <0x2018000 0x4000>;
interrupts = <0x00 0x1e 0x04>;
clocks = <0x02 0x7e 0x02 0x7f>;
clock-names = "ipg", "per";
dmas = <0x08 0x21 0x04 0x00 0x08 0x22 0x04 0x00>;
dma-names = "rx", "tx";
status = "disabled";
};
serial@02020000 {
compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart";
reg = <0x2020000 0x4000>;
interrupts = <0x00 0x1a 0x04>;
clocks = <0x02 0x7e 0x02 0x7f>;
clock-names = "ipg", "per";
dmas = <0x08 0x19 0x04 0x00 0x08 0x1a 0x04 0x00>;
dma-names = "rx", "tx";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0x09>;
};
serial@02024000 {
compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart";
reg = <0x2024000 0x4000>;
interrupts = <0x00 0x1b 0x04>;
clocks = <0x02 0x7e 0x02 0x7f>;
clock-names = "ipg", "per";
dmas = <0x08 0x1b 0x04 0x00 0x08 0x1c 0x04 0x00>;
dma-names = "rx", "tx";
status = "disabled";
};
ssi@02028000 {
#sound-dai-cells = <0x00>;
compatible = "fsl,imx6sl-ssi", "fsl,imx51-ssi";
reg = <0x2028000 0x4000>;
interrupts = <0x00 0x2e 0x04>;
clocks = <0x02 0xa1 0x02 0x7b>;
clock-names = "ipg", "baud";
dmas = <0x08 0x25 0x01 0x00 0x08 0x26 0x01 0x00>;
dma-names = "rx", "tx";
fsl,fifo-depth = <0x0f>;
status = "disabled";
};
ssi@0202c000 {
#sound-dai-cells = <0x00>;
compatible = "fsl,imx6sl-ssi", "fsl,imx51-ssi";
reg = <0x202c000 0x4000>;
interrupts = <0x00 0x2f 0x04>;
clocks = <0x02 0xa2 0x02 0x7c>;
clock-names = "ipg", "baud";
dmas = <0x08 0x29 0x01 0x00 0x08 0x2a 0x01 0x00>;
dma-names = "rx", "tx";
fsl,fifo-depth = <0x0f>;
status = "disabled";
};
ssi@02030000 {
#sound-dai-cells = <0x00>;
compatible = "fsl,imx6sl-ssi", "fsl,imx51-ssi";
reg = <0x2030000 0x4000>;
interrupts = <0x00 0x30 0x04>;
clocks = <0x02 0xa3 0x02 0x7d>;
clock-names = "ipg", "baud";
dmas = <0x08 0x2d 0x01 0x00 0x08 0x2e 0x01 0x00>;
dma-names = "rx", "tx";
fsl,fifo-depth = <0x0f>;
status = "disabled";
};
serial@02034000 {
compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart";
reg = <0x2034000 0x4000>;
interrupts = <0x00 0x1c 0x04>;
clocks = <0x02 0x7e 0x02 0x7f>;
clock-names = "ipg", "per";
dmas = <0x08 0x1d 0x04 0x00 0x08 0x1e 0x04 0x00>;
dma-names = "rx", "tx";
status = "disabled";
};
serial@02038000 {
compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart";
reg = <0x2038000 0x4000>;
interrupts = <0x00 0x1d 0x04>;
clocks = <0x02 0x7e 0x02 0x7f>;
clock-names = "ipg", "per";
dmas = <0x08 0x1f 0x04 0x00 0x08 0x20 0x04 0x00>;
dma-names = "rx", "tx";
status = "disabled";
};
};
pwm@02080000 {
#pwm-cells = <0x02>;
compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
reg = <0x2080000 0x4000>;
interrupts = <0x00 0x53 0x04>;
clocks = <0x02 0x75 0x02 0x75>;
clock-names = "ipg", "per";
};
pwm@02084000 {
#pwm-cells = <0x02>;
compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
reg = <0x2084000 0x4000>;
interrupts = <0x00 0x54 0x04>;
clocks = <0x02 0x76 0x02 0x76>;
clock-names = "ipg", "per";
};
pwm@02088000 {
#pwm-cells = <0x02>;
compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
reg = <0x2088000 0x4000>;
interrupts = <0x00 0x55 0x04>;
clocks = <0x02 0x77 0x02 0x77>;
clock-names = "ipg", "per";
};
pwm@0208c000 {
#pwm-cells = <0x02>;
compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
reg = <0x208c000 0x4000>;
interrupts = <0x00 0x56 0x04>;
clocks = <0x02 0x78 0x02 0x78>;
clock-names = "ipg", "per";
};
gpt@02098000 {
compatible = "fsl,imx6sl-gpt";
reg = <0x2098000 0x4000>;
interrupts = <0x00 0x37 0x04>;
clocks = <0x02 0x67 0x02 0x68>;
clock-names = "ipg", "per";
};
gpio@0209c000 {
compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio";
reg = <0x209c000 0x4000>;
interrupts = <0x00 0x42 0x04 0x00 0x43 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
gpio-ranges = <0x0a 0x00 0x16 0x01 0x0a 0x01 0x14 0x02 0x0a 0x03 0x17 0x01 0x0a 0x04 0x19 0x01 0x0a 0x05 0x18 0x01 0x0a 0x06 0x13 0x01 0x0a 0x07 0x24 0x02 0x0a 0x09 0x2c 0x08 0x0a 0x11 0x26 0x06 0x0a 0x17 0x44 0x04 0x0a 0x1b 0x40 0x04 0x0a 0x1f 0x34 0x01>;
};
gpio@020a0000 {
compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio";
reg = <0x20a0000 0x4000>;
interrupts = <0x00 0x44 0x04 0x00 0x45 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
gpio-ranges = <0x0a 0x00 0x35 0x03 0x0a 0x03 0x48 0x02 0x0a 0x05 0x22 0x02 0x0a 0x07 0x39 0x04 0x0a 0x0b 0x38 0x01 0x0a 0x0c 0x3d 0x03 0x0a 0x0f 0x6b 0x01 0x0a 0x10 0x84 0x02 0x0a 0x12 0x87 0x01 0x0a 0x13 0x86 0x01 0x0a 0x14 0x6c 0x02 0x0a 0x16 0x78 0x01 0x0a 0x17 0x7d 0x07 0x0a 0x1e 0x6e 0x02>;
};
gpio@020a4000 {
compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio";
reg = <0x20a4000 0x4000>;
interrupts = <0x00 0x46 0x04 0x00 0x47 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
gpio-ranges = <0x0a 0x00 0x70 0x08 0x0a 0x08 0x79 0x04 0x0a 0x0c 0x61 0x04 0x0a 0x10 0xa6 0x03 0x0a 0x13 0x55 0x02 0x0a 0x15 0x89 0x02 0x0a 0x17 0x88 0x01 0x0a 0x18 0x5b 0x01 0x0a 0x19 0x63 0x01 0x0a 0x1a 0x5c 0x01 0x0a 0x1b 0x64 0x01 0x0a 0x1c 0x5d 0x01 0x0a 0x1d 0x65 0x01 0x0a 0x1e 0x5e 0x01 0x0a 0x1f 0x66 0x01>;
};
gpio@020a8000 {
compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio";
reg = <0x20a8000 0x4000>;
interrupts = <0x00 0x48 0x04 0x00 0x49 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
gpio-ranges = <0x0a 0x00 0x5f 0x01 0x0a 0x01 0x67 0x01 0x0a 0x02 0x60 0x01 0x0a 0x03 0x68 0x01 0x0a 0x04 0x61 0x01 0x0a 0x05 0x69 0x01 0x0a 0x06 0x62 0x01 0x0a 0x07 0x6a 0x01 0x0a 0x08 0x1c 0x01 0x0a 0x09 0x1b 0x01 0x0a 0x0a 0x1a 0x01 0x0a 0x0b 0x1d 0x01 0x0a 0x0c 0x20 0x01 0x0a 0x0d 0x1f 0x01 0x0a 0x0e 0x1e 0x01 0x0a 0x0f 0x21 0x01 0x0a 0x10 0x54 0x01 0x0a 0x11 0x4f 0x02 0x0a 0x13 0x4e 0x01 0x0a 0x14 0x4c 0x01 0x0a 0x15 0x51 0x02 0x0a 0x17 0x4b 0x01 0x0a 0x18 0x53 0x01 0x0a 0x19 0x4a 0x01 0x0a 0x1a 0x4d 0x01 0x0a 0x1b 0x9f 0x01 0x0a 0x1c 0x9a 0x01 0x0a 0x1d 0x9d 0x01 0x0a 0x1e 0x98 0x01 0x0a 0x1f 0x9c 0x01>;
};
gpio@020ac000 {
compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio";
reg = <0x20ac000 0x4000>;
interrupts = <0x00 0x4a 0x04 0x00 0x4b 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
gpio-ranges = <0x0a 0x00 0x9e 0x01 0x0a 0x01 0x97 0x01 0x0a 0x02 0x9b 0x01 0x0a 0x03 0x99 0x01 0x0a 0x04 0x96 0x01 0x0a 0x05 0x95 0x01 0x0a 0x06 0x90 0x01 0x0a 0x07 0x93 0x01 0x0a 0x08 0x8e 0x01 0x0a 0x09 0x92 0x01 0x0a 0x0a 0x94 0x01 0x0a 0x0b 0x8d 0x01 0x0a 0x0c 0x91 0x01 0x0a 0x0d 0x8f 0x01 0x0a 0x0e 0x8c 0x01 0x0a 0x0f 0x8b 0x01 0x0a 0x10 0xa4 0x02 0x0a 0x12 0xa0 0x01 0x0a 0x13 0xa2 0x01 0x0a 0x14 0xa3 0x01 0x0a 0x15 0xa1 0x01>;
};
kpp@020b8000 {
compatible = "fsl,imx6sl-kpp", "fsl,imx21-kpp";
reg = <0x20b8000 0x4000>;
interrupts = <0x00 0x52 0x04>;
clocks = <0x02 0x00>;
status = "disabled";
};
wdog@020bc000 {
compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt";
reg = <0x20bc000 0x4000>;
interrupts = <0x00 0x50 0x04>;
clocks = <0x02 0x00>;
};
wdog@020c0000 {
compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt";
reg = <0x20c0000 0x4000>;
interrupts = <0x00 0x51 0x04>;
clocks = <0x02 0x00>;
status = "disabled";
};
ccm@020c4000 {
compatible = "fsl,imx6sl-ccm";
reg = <0x20c4000 0x4000>;
interrupts = <0x00 0x57 0x04 0x00 0x58 0x04>;
#clock-cells = <0x01>;
phandle = <0x02>;
};
anatop@020c8000 {
compatible = "fsl,imx6sl-anatop", "fsl,imx6q-anatop", "syscon", "simple-bus";
reg = <0x20c8000 0x1000>;
interrupts = <0x00 0x31 0x04 0x00 0x36 0x04 0x00 0x7f 0x04>;
phandle = <0x0b>;
regulator-1p1 {
compatible = "fsl,anatop-regulator";
regulator-name = "vdd1p1";
regulator-min-microvolt = "", "\f5";
regulator-max-microvolt = <0x14fb18>;
regulator-always-on;
anatop-reg-offset = <0x110>;
anatop-vol-bit-shift = <0x08>;
anatop-vol-bit-width = <0x05>;
anatop-min-bit-val = <0x04>;
anatop-min-voltage = "", "\f5";
anatop-max-voltage = <0x14fb18>;
};
regulator-3p0 {
compatible = "fsl,anatop-regulator";
regulator-name = "vdd3p0";
regulator-min-microvolt = <0x2ab980>;
regulator-max-microvolt = <0x3010b0>;
regulator-always-on;
anatop-reg-offset = <0x120>;
anatop-vol-bit-shift = <0x08>;
anatop-vol-bit-width = <0x05>;
anatop-min-bit-val = <0x00>;
anatop-min-voltage = <0x280de8>;
anatop-max-voltage = <0x33e140>;
};
regulator-2p5 {
compatible = "fsl,anatop-regulator";
regulator-name = "vdd2p5";
regulator-min-microvolt = <0x200b20>;
regulator-max-microvolt = <0x2b7cd0>;
regulator-always-on;
anatop-reg-offset = <0x130>;
anatop-vol-bit-shift = <0x08>;
anatop-vol-bit-width = <0x05>;
anatop-min-bit-val = <0x00>;
anatop-min-voltage = <0x200b20>;
anatop-max-voltage = <0x2b7cd0>;
};
regulator-vddcore {
compatible = "fsl,anatop-regulator";
regulator-name = "vddarm";
regulator-min-microvolt = <0xb1008>;
regulator-max-microvolt = <0x162010>;
regulator-always-on;
anatop-reg-offset = <0x140>;
anatop-vol-bit-shift = <0x00>;
anatop-vol-bit-width = <0x05>;
anatop-delay-reg-offset = <0x170>;
anatop-delay-bit-shift = <0x18>;
anatop-delay-bit-width = <0x02>;
anatop-min-bit-val = <0x01>;
anatop-min-voltage = <0xb1008>;
anatop-max-voltage = <0x162010>;
phandle = <0x03>;
};
regulator-vddpu {
compatible = "fsl,anatop-regulator";
regulator-name = "vddpu";
regulator-min-microvolt = <0xb1008>;
regulator-max-microvolt = <0x162010>;
regulator-always-on;
anatop-reg-offset = <0x140>;
anatop-vol-bit-shift = <0x09>;
anatop-vol-bit-width = <0x05>;
anatop-delay-reg-offset = <0x170>;
anatop-delay-bit-shift = <0x1a>;
anatop-delay-bit-width = <0x02>;
anatop-min-bit-val = <0x01>;
anatop-min-voltage = <0xb1008>;
anatop-max-voltage = <0x162010>;
phandle = <0x04>;
};
regulator-vddsoc {
compatible = "fsl,anatop-regulator";
regulator-name = "vddsoc";
regulator-min-microvolt = <0xb1008>;
regulator-max-microvolt = <0x162010>;
regulator-always-on;
anatop-reg-offset = <0x140>;
anatop-vol-bit-shift = <0x12>;
anatop-vol-bit-width = <0x05>;
anatop-delay-reg-offset = <0x170>;
anatop-delay-bit-shift = <0x1c>;
anatop-delay-bit-width = <0x02>;
anatop-min-bit-val = <0x01>;
anatop-min-voltage = <0xb1008>;
anatop-max-voltage = <0x162010>;
phandle = <0x05>;
};
};
tempmon {
compatible = "fsl,imx6q-tempmon";
interrupts = <0x00 0x31 0x04>;
fsl,tempmon = <0x0b>;
fsl,tempmon-data = <0x0c>;
clocks = <0x02 0x05>;
};
usbphy@020c9000 {
compatible = "fsl,imx6sl-usbphy", "fsl,imx23-usbphy";
reg = <0x20c9000 0x1000>;
interrupts = <0x00 0x2c 0x04>;
clocks = <0x02 0x0a>;
fsl,anatop = <0x0b>;
phandle = <0x0e>;
};
usbphy@020ca000 {
compatible = "fsl,imx6sl-usbphy", "fsl,imx23-usbphy";
reg = <0x20ca000 0x1000>;
interrupts = <0x00 0x2d 0x04>;
clocks = <0x02 0x0b>;
fsl,anatop = <0x0b>;
phandle = <0x10>;
};
snvs@020cc000 {
compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd";
reg = <0x20cc000 0x4000>;
phandle = <0x0d>;
snvs-rtc-lp {
compatible = "fsl,sec-v4.0-mon-rtc-lp";
regmap = <0x0d>;
offset = <0x34>;
interrupts = <0x00 0x13 0x04 0x00 0x14 0x04>;
};
snvs-poweroff {
compatible = "syscon-poweroff";
regmap = <0x0d>;
offset = <0x38>;
mask = <0x60>;
status = "disabled";
};
};
epit@020d0000 {
reg = <0x20d0000 0x4000>;
interrupts = <0x00 0x38 0x04>;
};
epit@020d4000 {
reg = <0x20d4000 0x4000>;
interrupts = <0x00 0x39 0x04>;
};
src@020d8000 {
compatible = "fsl,imx6sl-src", "fsl,imx51-src";
reg = <0x20d8000 0x4000>;
interrupts = <0x00 0x5b 0x04 0x00 0x60 0x04>;
#reset-cells = <0x01>;
};
gpc@020dc000 {
compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc";
reg = <0x20dc000 0x4000>;
interrupt-controller;
#interrupt-cells = <0x03>;
interrupts = <0x00 0x59 0x04>;
interrupt-parent = <0x06>;
pu-supply = <0x04>;
clocks = <0x02 0x69 0x02 0x50>;
#power-domain-cells = <0x01>;
phandle = <0x07>;
};
iomuxc-gpr@020e0000 {
compatible = "fsl,imx6sl-iomuxc-gpr", "fsl,imx6q-iomuxc-gpr", "syscon";
reg = <0x20e0000 0x38>;
phandle = <0x13>;
};
iomuxc@020e0000 {
compatible = "fsl,imx6sl-iomuxc";
reg = <0x20e0000 0x4000>;
pinctrl-names = "default";
phandle = <0x0a>;
wario {
uart1grp {
fsl,pins = <0x298 0x5a0 0x7fc 0x00 0x00 0x1b0b1 0x29c 0x5a4 0x00 0x00 0x00 0x1b0b1>;
phandle = <0x09>;
};
usdhc2grp {
fsl,pins = <0x254 0x55c 0x00 0x00 0x00 0x41f071 0x258 0x560 0x00 0x00 0x00 0x41f071 0x25c 0x564 0x00 0x00 0x00 0x41f071 0x260 0x568 0x00 0x00 0x00 0x41f071 0x264 0x56c 0x00 0x00 0x00 0x41f071 0x268 0x570 0x00 0x00 0x00 0x41f071 0x26c 0x574 0x00 0x00 0x00 0x41f071 0x270 0x578 0x00 0x00 0x00 0x41f071 0x274 0x57c 0x00 0x00 0x00 0x41f071 0x278 0x580 0x00 0x00 0x00 0x41f071 0x27c 0x584 0x00 0x00 0x00 0x413071>;
phandle = <0x11>;
};
};
};
csi@020e4000 {
reg = <0x20e4000 0x4000>;
interrupts = <0x00 0x07 0x04>;
};
spdc@020e8000 {
reg = <0x20e8000 0x4000>;
interrupts = <0x00 0x06 0x04>;
};
sdma@020ec000 {
compatible = "fsl,imx6sl-sdma", "fsl,imx6q-sdma";
reg = <0x20ec000 0x4000>;
interrupts = <0x00 0x02 0x04>;
clocks = <0x02 0x79 0x02 0x79>;
clock-names = "ipg", "ahb";
#dma-cells = <0x03>;
fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin";
phandle = <0x08>;
};
pxp@020f0000 {
reg = <0x20f0000 0x4000>;
interrupts = <0x00 0x62 0x04>;
};
epdc@020f4000 {
reg = <0x20f4000 0x4000>;
interrupts = <0x00 0x61 0x04>;
};
lcdif@020f8000 {
compatible = "fsl,imx6sl-lcdif", "fsl,imx28-lcdif";
reg = <0x20f8000 0x4000>;
interrupts = <0x00 0x27 0x04>;
clocks = <0x02 0x72 0x02 0x71 0x02 0x00>;
clock-names = "pix", "axi", "disp_axi";
status = "disabled";
};
dcp@020fc000 {
compatible = "fsl,imx6sl-dcp", "fsl,imx28-dcp";
reg = <0x20fc000 0x4000>;
interrupts = <0x00 0x63 0x04 0x00 0x64 0x04 0x00 0x65 0x04>;
};
};
aips-bus@02100000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <0x01>;
#size-cells = <0x01>;
reg = <0x2100000 0x100000>;
ranges;
usb@02184000 {
compatible = "fsl,imx6sl-usb", "fsl,imx27-usb";
reg = <0x2184000 0x200>;
interrupts = <0x00 0x2b 0x04>;
clocks = <0x02 0x80>;
fsl,usbphy = <0x0e>;
fsl,usbmisc = <0x0f 0x00>;
ahb-burst-config = <0x00>;
tx-burst-size-dword = <0x10>;
rx-burst-size-dword = <0x10>;
status = "okay";
pinctrl-names = "default";
disable-over-current;
dr_mode = "peripheral";
};
usb@02184200 {
compatible = "fsl,imx6sl-usb", "fsl,imx27-usb";
reg = <0x2184200 0x200>;
interrupts = <0x00 0x2a 0x04>;
clocks = <0x02 0x80>;
fsl,usbphy = <0x10>;
fsl,usbmisc = <0x0f 0x01>;
ahb-burst-config = <0x00>;
tx-burst-size-dword = <0x10>;
rx-burst-size-dword = <0x10>;
status = "disabled";
};
usb@02184400 {
compatible = "fsl,imx6sl-usb", "fsl,imx27-usb";
reg = <0x2184400 0x200>;
interrupts = <0x00 0x28 0x04>;
clocks = <0x02 0x80>;
fsl,usbmisc = <0x0f 0x02>;
dr_mode = "host";
ahb-burst-config = <0x00>;
tx-burst-size-dword = <0x10>;
rx-burst-size-dword = <0x10>;
status = "disabled";
};
usbmisc@02184800 {
#index-cells = <0x01>;
compatible = "fsl,imx6sl-usbmisc", "fsl,imx6q-usbmisc";
reg = <0x2184800 0x200>;
clocks = <0x02 0x80>;
phandle = <0x0f>;
};
ethernet@02188000 {
compatible = "fsl,imx6sl-fec", "fsl,imx25-fec";
reg = <0x2188000 0x4000>;
interrupts = <0x00 0x72 0x04>;
clocks = <0x02 0x87 0x02 0x11>;
clock-names = "ipg", "ahb";
status = "disabled";
};
usdhc@02190000 {
compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
reg = <0x2190000 0x4000>;
interrupts = <0x00 0x16 0x04>;
clocks = <0x02 0x81 0x02 0x81 0x02 0x81>;
clock-names = "ipg", "ahb", "per";
bus-width = <0x04>;
status = "disabled";
};
usdhc@02194000 {
compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
reg = <0x2194000 0x4000>;
interrupts = <0x00 0x17 0x04>;
clocks = <0x02 0x82 0x02 0x82 0x02 0x82>;
clock-names = "ipg", "ahb", "per";
bus-width = <0x08>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0x11>;
vqmmc-supply = <0x12>;
non-removable;
};
usdhc@02198000 {
compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
reg = <0x2198000 0x4000>;
interrupts = <0x00 0x18 0x04>;
clocks = <0x02 0x83 0x02 0x83 0x02 0x83>;
clock-names = "ipg", "ahb", "per";
bus-width = <0x04>;
status = "disabled";
};
usdhc@0219c000 {
compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
reg = <0x219c000 0x4000>;
interrupts = <0x00 0x19 0x04>;
clocks = <0x02 0x84 0x02 0x84 0x02 0x84>;
clock-names = "ipg", "ahb", "per";
bus-width = <0x04>;
status = "disabled";
};
i2c@021a0000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c";
reg = <0x21a0000 0x4000>;
interrupts = <0x00 0x24 0x04>;
clocks = <0x02 0x6a>;
status = "disabled";
};
i2c@021a4000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c";
reg = <0x21a4000 0x4000>;
interrupts = <0x00 0x25 0x04>;
clocks = <0x02 0x6b>;
status = "disabled";
};
i2c@021a8000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c";
reg = <0x21a8000 0x4000>;
interrupts = <0x00 0x26 0x04>;
clocks = <0x02 0x6c>;
status = "disabled";
};
mmdc@021b0000 {
compatible = "fsl,imx6sl-mmdc", "fsl,imx6q-mmdc";
reg = <0x21b0000 0x4000>;
};
rngb@021b4000 {
reg = <0x21b4000 0x4000>;
interrupts = <0x00 0x05 0x04>;
};
weim@021b8000 {
#address-cells = <0x02>;
#size-cells = <0x01>;
reg = <0x21b8000 0x4000>;
interrupts = <0x00 0x0e 0x04>;
fsl,weim-cs-gpr = <0x13>;
status = "disabled";
};
ocotp@021bc000 {
compatible = "fsl,imx6sl-ocotp", "syscon";
reg = <0x21bc000 0x4000>;
clocks = <0x02 0x6d>;
phandle = <0x0c>;
};
audmux@021d8000 {
compatible = "fsl,imx6sl-audmux", "fsl,imx31-audmux";
reg = <0x21d8000 0x4000>;
status = "disabled";
};
};
};
regulators {
compatible = "simple-bus";
#address-cells = <0x01>;
#size-cells = <0x00>;
sd2_vmmc {
compatible = "regulator-fixed";
regulator-name = "eMMC-VCCQ";
regulator-min-microvolt = <0x1b7740>;
regulator-max-microvolt = <0x1b7740>;
regulator-boot-on;
phandle = <0x12>;
};
};
};

BIN
working/config.gz Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,170 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include "imx6sl.dtsi"
#include "imx6sl-pinfunc.h"
/ {
model = "Amazon Kindle Paperwhite 3 (Wario)";
compatible = "amazon,kindle-pw3", "fsl,imx6sl";
aliases {
mmc1 = &usdhc2;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
chosen {
stdout-path = &uart1;
};
regulators {
compatible = "simple-bus";
emmc_3v3: regulator-emmc-3v3 {
compatible = "regulator-fixed";
regulator-name = "emmc-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio4 17 0>; /* gpio-113 */
enable-active-high;
regulator-always-on;
regulator-boot-on;
};
emmc_1v8: regulator-emmc-1v8 {
compatible = "regulator-fixed";
regulator-name = "emmc-1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio4 23 0>; /* gpio-119 */
enable-active-high;
regulator-always-on;
regulator-boot-on;
};
wifi_pwr: regulator-wifi {
compatible = "regulator-fixed";
regulator-name = "wifi-pwr";
gpio = <&gpio3 29 0>; /* gpio-93 */
enable-active-high;
};
};
};
&iomuxc {
pinctrl-names = "default";
imx6sl-kindle {
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1
MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1
>;
};
pinctrl_usdhc2: usdhc2grp {
fsl,pins = <
/*
LVE_ENABLED,HYS_ENABLED,PUS_22KOHM_PU,PUE_PULL,
PKE_ENABLED,ODE_DISABLED,SPD_100MHZ,DSE_40OHM,SRE_FAST
*/
MX6SL_PAD_SD2_CLK__SD2_CLK 0x41F071
MX6SL_PAD_SD2_CMD__SD2_CMD 0x41F071
MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x41F071
MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x41F071
MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x41F071
MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x41F071
MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x41F071
MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x41F071
MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x41F071
MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x41F071
/*
LVE_ENABLED,HYS_ENABLED,PUS_100KOHM_PU,PUE_PULL,
PKE_ENABLED,ODE_DISABLED,SPD_100MHZ,DSE_40OHM,SRE_FAST
*/
MX6SL_PAD_SD2_RST__SD2_RESET 0x413071
>;
};
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1
MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1
>;
};
};
};
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
status = "okay";
};
/* eMMC */
&usdhc2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc2>;
bus-width = <8>;
non-removable;
vqmmc-supply = <&emmc_1v8>;
vmmc-supply = <&emmc_3v3>;
status = "okay";
};
/* WiFi — ath6kl on SDIO */
&usdhc3 {
bus-width = <4>;
vmmc-supply = <&wifi_pwr>;
non-removable;
status = "disabled";
};
/* PMIC + EPD power on I2C0 */
&i2c1 {
clock-frequency = <100000>;
status = "okay";
max77696: pmic@3c {
compatible = "maxim,max77696";
reg = <0x3c>;
interrupt-parent = <&gpio4>;
interrupts = <20 IRQ_TYPE_LEVEL_LOW>; /* gpio-116 */
};
epd_pmic: max17135@48 {
compatible = "maxim,max17135";
reg = <0x34>;
};
};
/* Touchscreen on I2C1 */
&i2c2 {
clock-frequency = <100000>;
status = "okay";
touchscreen@24 {
compatible = "cypress,cyttsp4-i2c";
reg = <0x24>;
interrupt-parent = <&gpio2>;
interrupts = <24 IRQ_TYPE_EDGE_FALLING>; /* gpio-88, touch_not_used? */
};
};
/* Watchdog — enable so mainline manages it */
&wdog1 {
status = "disabled";
};
&gpu_2d {
status = "disabled";
};
&gpu_vg {
status = "disabled";
};

7760
working/kernel.config Normal file

File diff suppressed because it is too large Load Diff

BIN
working/u-boot.bin Normal file

Binary file not shown.

BIN
working/uImage Normal file

Binary file not shown.