From d2c80ce3603d4872586f50574f592e21e643f50b Mon Sep 17 00:00:00 2001 From: Daniel Maslowski Date: Thu, 22 Aug 2024 23:07:35 +0200 Subject: [PATCH 1/5] add list of generic names Taken from the DT spec: https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter2-devicetree-basics.rst#generic-names-recommendation --- app/generic-names.json | 104 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 app/generic-names.json diff --git a/app/generic-names.json b/app/generic-names.json new file mode 100644 index 0000000..dbb07c3 --- /dev/null +++ b/app/generic-names.json @@ -0,0 +1,104 @@ +[ + "adc", + "accelerometer", + "air-pollution-sensor", + "atm", + "audio-codec", + "audio-controller", + "backlight", + "bluetooth", + "bus", + "cache-controller", + "camera", + "can", + "charger", + "clock", + "clock-controller", + "co2-sensor", + "compact-flash", + "cpu", + "cpus", + "crypto", + "disk", + "display", + "dma-controller", + "dsi", + "dsp", + "eeprom", + "efuse", + "endpoint", + "ethernet", + "ethernet-phy", + "fdc", + "flash", + "gnss", + "gpio", + "gpu", + "gyrometer", + "hdmi", + "hwlock", + "i2c", + "i2c-mux", + "ide", + "interrupt-controller", + "iommu", + "isa", + "keyboard", + "key", + "keys", + "lcd-controller", + "led", + "leds", + "led-controller", + "light-sensor", + "lora", + "magnetometer", + "mailbox", + "mdio", + "memory", + "memory-controller", + "mmc", + "mmc-slot", + "mouse", + "nand-controller", + "nvram", + "oscillator", + "parallel", + "pc-card", + "pci", + "pcie", + "phy", + "pinctrl", + "pmic", + "pmu", + "port", + "ports", + "power-monitor", + "pwm", + "regulator", + "reset-controller", + "rng", + "rtc", + "sata", + "scsi", + "serial", + "sound", + "spi", + "spmi", + "sram-controller", + "ssi-controller", + "syscon", + "temperature-sensor", + "timer", + "touchscreen", + "tpm", + "ufshc", + "usb", + "usb-hub", + "usb-phy", + "vibrator", + "video-codec", + "vme", + "watchdog", + "wifi" +] From 077694b8b07b8b1cb5aafd7e6c85f67580b33394 Mon Sep 17 00:00:00 2001 From: Daniel Maslowski Date: Thu, 22 Aug 2024 00:43:39 +0200 Subject: [PATCH 2/5] add preliminary list of device tree compat DB --- app/compat-db.json | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 app/compat-db.json diff --git a/app/compat-db.json b/app/compat-db.json new file mode 100644 index 0000000..76f96c1 --- /dev/null +++ b/app/compat-db.json @@ -0,0 +1,42 @@ +{ + "brcm,bcm2835-aux-clock": { + "category": "binding", + "path": "clock/brcm,bcm2835-aux-clock.txt" + }, + "brcm,bcm2835-aux-uart": { + "category": "binding", + "path": "serial/brcm,bcm2835-aux-uart.txt" + }, + "brcm,bcm2835-pwm": { + "category": "binding", + "path": "pwm/pwm-bcm2835.yaml" + }, + "brcm,bcm2835-spi": { + "category": "binding", + "path": "spi/brcm,bcm2835-spi.txt" + }, + "brcm,bcm2835-thermal": { + "category": "binding", + "path": "thermal/brcm,bcm2835-thermal.yaml" + }, + "brcm,bcm2835-vchiq": { + "category": "binding", + "path": "soc/bcm/brcm,bcm2835-vchiq.yaml" + }, + "arm,cortex-a7": { + "category": "binding", + "path": "arm/cpus.yaml" + }, + "brcm,bcm2835-cprman": { + "category": "binding", + "path": "clock/brcm,bcm2835-cprman.txt" + }, + "raspberrypi,bcm2835-firmware": { + "category": "binding", + "path": "arm/bcm/raspberrypi,bcm2835-firmware.yaml" + }, + "spidev": { + "category": "docs", + "path": "spi/spidev.html" + } +} From 9d9dfdac95eb082ddfd59dd112881bcb1ffc463d Mon Sep 17 00:00:00 2001 From: Daniel Maslowski Date: Thu, 22 Aug 2024 00:42:26 +0200 Subject: [PATCH 3/5] DTNode: migrate to styled-jsx and render compat string and status lib: split up exposed properties and add status --- app/DTNode.tsx | 142 ++++++++++++++++++++++++++++++++++++++++--------- app/lib.ts | 9 +++- 2 files changed, 126 insertions(+), 25 deletions(-) diff --git a/app/DTNode.tsx b/app/DTNode.tsx index 5cdf221..2813e65 100644 --- a/app/DTNode.tsx +++ b/app/DTNode.tsx @@ -1,16 +1,122 @@ import { memo, useState } from "react"; import { Handle, NodeProps, Position } from "reactflow"; +import compatDb from "./compat-db.json"; -const style = { - // wordWrap: "break-word", - whiteSpace: "pre-wrap" as "pre-wrap", // This is weird, TypoScripto... - padding: 4, - border: "2px solid", - background: "#0c0c0c", - color: "#fff", - width: 150, - fontSize: 11, - fontFamily: "Fira Code", +type DTStatus = "okay" | "disabled"; + +type DotColor = "blue" | "red"; + +const getDotColor = (status?: DTStatus): DotColor | null => { + switch(status) { + case "okay": return "blue"; + case "disabled": return "red"; + default: return null; + } +} + +export const Dot: FC<{ status?: DTStatus }> = ({ status }) => { + if (!status) { + return null; + } + const color = getDotColor(status); + return ( +
+ +
+ ); +}; + +const docsbaseUrl = "https://docs.kernel.org" +const dtBaseUrl = "https://www.kernel.org/doc/Documentation/devicetree/bindings"; + +type DocsCategory = "binding" | "docs"; + +type DocsEntry = { + category: DocsCategory; + path: string; +}; + +const getBaseUrl = (category: DocsCategory): string => { + switch(category) { + case "binding": return dtBaseUrl; + case "docs": return docsbaseUrl; + } +}; + +const getDocUrl = (compat: string) => { + const res = compat.split(";").find((c) => !!compatDb[c]); + if (!res) { + return null; + } + const d = compatDb[res]; + const baseUrl = getBaseUrl(d.category); + return `${baseUrl}/${d.path}`; +} + +const Compat: FC<{ compat?: string; }> = ({ compat }) => { + if (!compat) { + return null; + } + const docUrl = getDocUrl(compat); + + if (!docUrl) { + return compat; + } + + return ( + + {compat} + + + ); +}; + +export const DataNode: FC<{ data: object; status?: DTStatus }> = ({ + data, + status, +}) => { + if (!data) { + return null; + } + + return ( +
+ {data.label} + {data.baseAddr} + + + +
+ ); }; const DTNode = ({ @@ -19,13 +125,7 @@ const DTNode = ({ targetPosition = Position.Top, sourcePosition = Position.Bottom }: NodeProps) => { - const [hovered, setHovered] = useState(false); - - const hoverOn = () => setHovered(true); - const hoverOff = () => setHovered(false); - - const borderColor = hovered ? "#987987" : "#789789"; - const borderStyle = hovered ? "dotted" : "solid"; + const { status, ...nData } = data; return ( <> -
- {data?.label} -
+ { const clks = getProp(n, "clocks"); const cnames = getStringProp(n, "clock-names"); const compat = getStringProp(n, "compatible"); + const status = getStringProp(n, "status"); return { name, ...(phandle ? { phandle: phandle[0] } : null), @@ -89,6 +91,7 @@ const transformNode = (n: DTNode): DTNode => { ...(clks ? { clks } : null), ...(cnames ? { cnames } : null), ...(compat ? { compat } : null), + ...(status ? { status } : null), }; }; @@ -150,7 +153,11 @@ export const getNodesEdges = (tree: DTNode) => { y: baseY + d * NODE_HEIGHT, }, data: { - label: `${name}\n${baseAddr}\n${n.size}`, + label: name, + baseAddr, + size: n.size, + compat: n.compat, + status: n.status, }, }); let offset = baseX; From 1ca1262ac3415dcb3bbf7f375cca5d120d952f36 Mon Sep 17 00:00:00 2001 From: Daniel Maslowski Date: Tue, 20 Aug 2024 17:29:42 +0200 Subject: [PATCH 4/5] DTNode: add Storybook story --- app/DTNode.stories.tsx | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 app/DTNode.stories.tsx diff --git a/app/DTNode.stories.tsx b/app/DTNode.stories.tsx new file mode 100644 index 0000000..1b12cf8 --- /dev/null +++ b/app/DTNode.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { fn } from '@storybook/test'; +import { DataNode } from './DTNode'; + +const meta = { + title: 'App/DTNode', + component: DataNode, + argTypes: { + data: { + label: { control: 'text' }, + baseAddr: {}, + compat: {}, + }, + status: { control: 'radio', options: ['okay', 'disabled'] }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Simple: Story = { + args: { + data: { + label: "UART", + baseAddr: "0x0c00_0000", + }, + status: "okay", + }, +}; + +export const WithCompat: Story = { + args: { + data: { + label: "firmware", + compat: "raspberrypi,bcm2835-firmware", + }, + }, +}; From dcf6916d5e677ebf4ace547b6e4c93dd0a3c2af4 Mon Sep 17 00:00:00 2001 From: Daniel Maslowski Date: Thu, 22 Aug 2024 23:01:45 +0200 Subject: [PATCH 5/5] WIP --- app/DTNode.stories.tsx | 3 +- app/DTNode.tsx | 74 ++++++++++++++++++++++++------------------ app/compat-db.json | 8 +++++ app/lib.ts | 28 ++++++++++++---- 4 files changed, 74 insertions(+), 39 deletions(-) diff --git a/app/DTNode.stories.tsx b/app/DTNode.stories.tsx index 1b12cf8..cf422c4 100644 --- a/app/DTNode.stories.tsx +++ b/app/DTNode.stories.tsx @@ -11,7 +11,7 @@ const meta = { baseAddr: {}, compat: {}, }, - status: { control: 'radio', options: ['okay', 'disabled'] }, + status: { control: 'radio', options: ['okay', 'disabled', undefined] }, }, } satisfies Meta; @@ -23,6 +23,7 @@ export const Simple: Story = { data: { label: "UART", baseAddr: "0x0c00_0000", + compat: "ns16550a", }, status: "okay", }, diff --git a/app/DTNode.tsx b/app/DTNode.tsx index 2813e65..89b081a 100644 --- a/app/DTNode.tsx +++ b/app/DTNode.tsx @@ -1,31 +1,26 @@ import { memo, useState } from "react"; import { Handle, NodeProps, Position } from "reactflow"; import compatDb from "./compat-db.json"; +import genericNames from "./generic-names.json"; type DTStatus = "okay" | "disabled"; -type DotColor = "blue" | "red"; - -const getDotColor = (status?: DTStatus): DotColor | null => { - switch(status) { - case "okay": return "blue"; - case "disabled": return "red"; - default: return null; - } -} +const dotColors: Record = { + okay: "blue", + disabled: "red" +}; export const Dot: FC<{ status?: DTStatus }> = ({ status }) => { if (!status) { return null; } - const color = getDotColor(status); + const color = dotColors[status]; return ( -
+
@@ -33,10 +28,12 @@ export const Dot: FC<{ status?: DTStatus }> = ({ status }) => { ); }; -const docsbaseUrl = "https://docs.kernel.org" +const docsBaseUrl = "https://docs.kernel.org" +const drvBaseUrl = "https://elixir.bootlin.com/linux/HEAD/source/drivers"; +//const drvBaseUrl = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers"; const dtBaseUrl = "https://www.kernel.org/doc/Documentation/devicetree/bindings"; -type DocsCategory = "binding" | "docs"; +type DocsCategory = "binding" | "docs" | "driver"; type DocsEntry = { category: DocsCategory; @@ -46,7 +43,8 @@ type DocsEntry = { const getBaseUrl = (category: DocsCategory): string => { switch(category) { case "binding": return dtBaseUrl; - case "docs": return docsbaseUrl; + case "docs": return docsBaseUrl; + case "driver": return drvBaseUrl; } }; @@ -87,33 +85,47 @@ export const DataNode: FC<{ data: object; status?: DTStatus }> = ({ data, status, }) => { - if (!data) { - return null; - } - + const extraClass = genericNames.includes(data.label) ? "generic" : ""; return (
- {data.label} - {data.baseAddr} - - +
{data.label}
+
+ {data.model} + {data.baseAddr} + + + {data.extra} +
); diff --git a/app/compat-db.json b/app/compat-db.json index 76f96c1..2c86eb1 100644 --- a/app/compat-db.json +++ b/app/compat-db.json @@ -27,6 +27,10 @@ "category": "binding", "path": "arm/cpus.yaml" }, + "arm,cortex-a7-pmu": { + "category": "binding", + "path": "arm/pmu.yaml" + }, "brcm,bcm2835-cprman": { "category": "binding", "path": "clock/brcm,bcm2835-cprman.txt" @@ -38,5 +42,9 @@ "spidev": { "category": "docs", "path": "spi/spidev.html" + }, + "brcm,bcm2835-audio": { + "category": "driver", + "path": "staging/vc04_services/bcm2835-audio/bcm2835.c" } } diff --git a/app/lib.ts b/app/lib.ts index 174baac..31617d3 100644 --- a/app/lib.ts +++ b/app/lib.ts @@ -66,6 +66,17 @@ const getPropStr = (n: DTNode, pname: string): string | null => { return p ? p.join(", ") : null; }; +const getExtra = (n: DTNode) => { + if (n.name === "aliases" | n.name === "chosen") { + const ps = n.props.map((p) => { + const [k, v] = p; + return `${k}=${u8ArrToStr(v)}`; + }); + return ps.join("\n"); + } + return null; +}; + // transform a node's props into numbers and strings, omitting many const transformNode = (n: DTNode): DTNode => { const name = n.name || "root"; @@ -81,6 +92,8 @@ const transformNode = (n: DTNode): DTNode => { const cnames = getStringProp(n, "clock-names"); const compat = getStringProp(n, "compatible"); const status = getStringProp(n, "status"); + const model = getStringProp(n, "model"); + const extra = getExtra(n); return { name, ...(phandle ? { phandle: phandle[0] } : null), @@ -92,6 +105,8 @@ const transformNode = (n: DTNode): DTNode => { ...(cnames ? { cnames } : null), ...(compat ? { compat } : null), ...(status ? { status } : null), + ...(model ? { model } : null), + extra, }; }; @@ -103,7 +118,7 @@ export const transform = (n: DTNode, id: string = "10000") => { } }; -const NODE_WIDTH = 160; +const NODE_WIDTH = 260; const NODE_HEIGHT = 80; const weightedNode = (node: DTNode): DTNode => { @@ -142,22 +157,21 @@ export const getNodesEdges = (tree: DTNode) => { const nodes: TransformedNode[] = []; const edges: TransformedEdge[] = []; const rec = (n: DTNode, d: number = 1, baseX: number = 0, baseY: number = 0) => { - const [name, addr] = n.name.split("@"); + const { id, name, ...data } = n; + const [label, addr] = name.split("@"); const baseAddr = transformAddr(addr); nodes.push({ - id: n.id, + id, type: NodeType.custom, position: { x: baseX + n.size * NODE_WIDTH / 2, y: baseY + d * NODE_HEIGHT, }, data: { - label: name, + label, baseAddr, - size: n.size, - compat: n.compat, - status: n.status, + ...data, }, }); let offset = baseX;