* [PATCH 0/2] drm/panel: add Ilitek ILI7836A panel driver
@ 2026-08-08 19:01 Aaron Kling via B4 Relay
2026-08-08 19:01 ` [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver Aaron Kling via B4 Relay
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Aaron Kling via B4 Relay @ 2026-08-08 19:01 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, Aaron Kling
Add support for the Ilitek ILI7836A DDIC.
This depends on the Retroid Pocket dt series [0] for the vendor prefix
patch. That series depends on the AYN dt series [1] to apply cleanly.
[0] https://lore.kernel.org/linux-arm-msm/20260808-rp-qcs8550-v1-0-a5a365ba3dc5@gmail.com/
[1] https://lore.kernel.org/linux-arm-msm/20260727-ayn-qcs8550-v9-0-e3db456e10e5@gmail.com/
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
---
Aaron Kling (2):
dt-bindings: display: panel: add Ilitek ILI7836A OLED driver
drm/panel: add Ilitek ILI7836A panel driver
.../bindings/display/panel/ilitek,ili7836a.yaml | 58 ++++
drivers/gpu/drm/panel/Kconfig | 11 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-ilitek-ili7836a.c | 297 +++++++++++++++++++++
4 files changed, 367 insertions(+)
---
base-commit: 6b8c8af514d739d0335f5579b585e02babe8a727
change-id: 20260808-ili7836a-36f44911bcfd
prerequisite-change-id: 20260217-ayn-qcs8550-16c07b63de26:v9
prerequisite-patch-id: 17ba304f7a8a08cc78f98e198db9c51f4786a22c
prerequisite-patch-id: 21873631f5dcdb9bbbdb5c20c3f5e9816cc405f9
prerequisite-patch-id: bf7b5dea0097cbbdf04929a4246d1fc65c607ea8
prerequisite-patch-id: d7f546eddc96a4f31a1e681abddbc96bd68abb32
prerequisite-patch-id: d40d784ad8efbb1204c024408be2067725a06cf2
prerequisite-patch-id: 25bbd55199a8250a912ef542b31f43dd5ccdbc90
prerequisite-change-id: 20260808-rp-qcs8550-85c84760f6f3:v1
prerequisite-patch-id: 17ba304f7a8a08cc78f98e198db9c51f4786a22c
prerequisite-patch-id: 21873631f5dcdb9bbbdb5c20c3f5e9816cc405f9
prerequisite-patch-id: bf7b5dea0097cbbdf04929a4246d1fc65c607ea8
prerequisite-patch-id: d7f546eddc96a4f31a1e681abddbc96bd68abb32
prerequisite-patch-id: d40d784ad8efbb1204c024408be2067725a06cf2
prerequisite-patch-id: 25bbd55199a8250a912ef542b31f43dd5ccdbc90
prerequisite-patch-id: c79dacb2a8ca1298387bc9bc4a543de97c670a50
prerequisite-patch-id: 9c058fb9b13442f5434b8aaa2f1907eff1b43684
prerequisite-patch-id: c13130099b60aa7c412181e99070718eb2c68ecd
prerequisite-patch-id: d0dad3c4fa9c4b98e6cc53bbd0874df9113ab5f6
Best regards,
--
Aaron Kling <webgeek1234@gmail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver 2026-08-08 19:01 [PATCH 0/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay @ 2026-08-08 19:01 ` Aaron Kling via B4 Relay 2026-08-08 19:06 ` sashiko-bot 2026-08-19 8:36 ` Krzysztof Kozlowski 2026-08-08 19:01 ` [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay 2026-08-31 14:29 ` [PATCH 0/2] " Neil Armstrong 2 siblings, 2 replies; 8+ messages in thread From: Aaron Kling via B4 Relay @ 2026-08-08 19:01 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel, Aaron Kling From: Aaron Kling <webgeek1234@gmail.com> The Ilitek ILI7836A OLED driver is a single chip solution for MIPI-DSI. This is used for the Retroid Pocket Nova panel. Signed-off-by: Aaron Kling <webgeek1234@gmail.com> --- .../bindings/display/panel/ilitek,ili7836a.yaml | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili7836a.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili7836a.yaml new file mode 100644 index 0000000000000..962cf257ed8d3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili7836a.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/ilitek,ili7836a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ilitek ILI7836A-based OLED panels + +maintainers: + - Neil Armstrong <neil.armstrong@linaro.org> + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - const: retroidpocket,nova-panel + - const: ilitek,ili7836a + + reg: + maxItems: 1 + description: DSI virtual channel + + vddio-supply: true + avdd-supply: true + + backlight: true + port: true + reset-gpios: true + rotation: true + +required: + - compatible + - reg + - vddio-supply + - avdd-supply + - reset-gpios + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + dsi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "retroidpocket,nova-panel", "ilitek,ili7836a"; + reg = <0>; + vddio-supply = <&vdd_disp_1v8>; + avdd-supply = <&vdd_disp2_2v8>; + reset-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>; + }; + }; + +... -- 2.54.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver 2026-08-08 19:01 ` [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver Aaron Kling via B4 Relay @ 2026-08-08 19:06 ` sashiko-bot 2026-08-19 8:36 ` Krzysztof Kozlowski 1 sibling, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-08-08 19:06 UTC (permalink / raw) To: Aaron Kling; +Cc: robh, conor+dt, devicetree, dri-devel Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] The vendor prefix `retroidpocket` used in the new compatible string is not documented in `vendor-prefixes.yaml`. -- --- Patch [1]: [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver --- commit aacb89a0d4e50af14a474c3071ac0dce394b199e Author: Aaron Kling <webgeek1234@gmail.com> dt-bindings: display: panel: add Ilitek ILI7836A OLED driver This commit introduces a new device tree binding for the Ilitek ILI7836A OLED driver. It documents the properties and compatible strings required for the MIPI-DSI display used on the Retroid Pocket Nova. > diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili7836a.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili7836a.yaml > new file mode 100644 > index 0000000000000..962cf257ed8d3 > --- /dev/null > +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili7836a.yaml [ ... ] > +properties: > + compatible: > + items: > + - const: retroidpocket,nova-panel [Severity: Low] Is the retroidpocket vendor prefix documented in vendor-prefixes.yaml? Adding a compatible string with an undocumented vendor prefix will cause a build warning when running make dt_binding_check. > + - const: ilitek,ili7836a > + > + reg: [ ... ] -- Sashiko AI review · https://sashiko.dev/#/patchset/20260808-ili7836a-v1-0-07a7becc5636@gmail.com?part=1 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver 2026-08-08 19:01 ` [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver Aaron Kling via B4 Relay 2026-08-08 19:06 ` sashiko-bot @ 2026-08-19 8:36 ` Krzysztof Kozlowski 1 sibling, 0 replies; 8+ messages in thread From: Krzysztof Kozlowski @ 2026-08-19 8:36 UTC (permalink / raw) To: Aaron Kling Cc: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley, dri-devel, devicetree, linux-kernel On Sat, Aug 08, 2026 at 02:01:14PM -0500, Aaron Kling wrote: > The Ilitek ILI7836A OLED driver is a single chip solution for MIPI-DSI. > This is used for the Retroid Pocket Nova panel. > > Signed-off-by: Aaron Kling <webgeek1234@gmail.com> > --- > .../bindings/display/panel/ilitek,ili7836a.yaml | 58 ++++++++++++++++++++++ > 1 file changed, 58 insertions(+) Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> Best regards, Krzysztof ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver 2026-08-08 19:01 [PATCH 0/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay 2026-08-08 19:01 ` [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver Aaron Kling via B4 Relay @ 2026-08-08 19:01 ` Aaron Kling via B4 Relay 2026-08-08 19:16 ` sashiko-bot 2026-08-10 9:58 ` Neil Armstrong 2026-08-31 14:29 ` [PATCH 0/2] " Neil Armstrong 2 siblings, 2 replies; 8+ messages in thread From: Aaron Kling via B4 Relay @ 2026-08-08 19:01 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel, Aaron Kling From: Aaron Kling <webgeek1234@gmail.com> This is a DDIC which can be used in various panels. The first supported panel is the one used in the Retroid Pocket Nova. Signed-off-by: Aaron Kling <webgeek1234@gmail.com> --- drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-ilitek-ili7836a.c | 297 ++++++++++++++++++++++++++ 3 files changed, 309 insertions(+) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index cbdf7b8f7f7af..792d6b92798d9 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -298,6 +298,17 @@ config DRM_PANEL_ILITEK_ILI7807S If M is selected the module will be called panel-ilitek-ili7807s. +config DRM_PANEL_ILITEK_ILI7836A + tristate "Ilitek ILI7836A-based panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for panels based on the + Ilitek ILI7836A DDIC. + + If M is selected the module will be called panel-ilitek-ili7836a. + config DRM_PANEL_ILITEK_IL9322 tristate "Ilitek ILI9322 320x240 QVGA panels" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 3b523cf378330..be96f4e8112da 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7807S) += panel-ilitek-ili7807s.o +obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7836A) += panel-ilitek-ili7836a.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9488) += panel-ilitek-ili9488.o diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c b/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c new file mode 100644 index 0000000000000..f6331129dadf2 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_connector.h> +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_of.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +#include <video/mipi_display.h> + +static const struct regulator_bulk_data ili7836a_supplies[] = { + { .supply = "vddio", }, + { .supply = "avdd", }, +}; + +struct ili7836a_panel { + struct drm_panel panel; + struct drm_connector *connector; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; + struct ili7836a_desc *desc; + enum drm_panel_orientation orientation; +}; + +struct ili7836a_desc { + unsigned int width_mm; + unsigned int height_mm; + unsigned int bpc; + + const struct drm_display_mode *modes; + unsigned int num_modes; +}; + +static inline struct ili7836a_panel *to_ili7836a_panel(struct drm_panel *panel) +{ + return container_of(panel, struct ili7836a_panel, panel); +} + +static void ili7836a_reset(struct ili7836a_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(20); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); +} + +static int ili7836a_on(struct ili7836a_panel *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x62); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa4, 0x38); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x23); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x85, 0x15); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x20); + + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x22); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x01); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x00); + + return dsi_ctx.accum_err; +} + +static int ili7836a_disable(struct drm_panel *panel) +{ + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + + return dsi_ctx.accum_err; +} + +static int ili7836a_prepare(struct drm_panel *panel) +{ + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ili7836a_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + ili7836a_reset(ctx); + + ret = ili7836a_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ili7836a_supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int ili7836a_unprepare(struct drm_panel *panel) +{ + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ili7836a_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode nova_modes[] = { + { + /* 120Hz */ + .clock = (1280 + 12 + 2 + 8) * (960 + 12 + 2 + 24) * 120 / 1000, + .hdisplay = 1280, + .hsync_start = 1280 + 12, + .hsync_end = 1280 + 12 + 2, + .htotal = 1280 + 12 + 2 + 8, + .vdisplay = 960, + .vsync_start = 960 + 12, + .vsync_end = 960 + 12 + 2, + .vtotal = 960 + 12 + 2 + 24, + } +}; + +static struct ili7836a_desc nova_desc = { + .modes = nova_modes, + .num_modes = ARRAY_SIZE(nova_modes), + .width_mm = 91, + .height_mm = 68, + .bpc = 8, +}; + +static int ili7836a_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); + + return drm_connector_helper_get_modes_fixed(connector, ctx->desc->modes); +} + +static enum drm_panel_orientation ili7836a_get_orientation(struct drm_panel *panel) +{ + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); + + return ctx->orientation; +} + +static const struct drm_panel_funcs ili7836a_panel_funcs = { + .prepare = ili7836a_prepare, + .unprepare = ili7836a_unprepare, + .disable = ili7836a_disable, + .get_modes = ili7836a_get_modes, + .get_orientation = ili7836a_get_orientation, +}; + +static int ili7836a_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static const struct backlight_ops ili7836a_bl_ops = { + .update_status = ili7836a_bl_update_status, +}; + +static struct backlight_device * +ili7836a_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 3445, + .max_brightness = 3445, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &ili7836a_bl_ops, &props); +} + +static int ili7836a_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct ili7836a_panel *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, + &ili7836a_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ctx->desc = (struct ili7836a_desc *)of_device_get_match_data(dev); + if (!ctx->desc) + return -ENODEV; + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(ili7836a_supplies), + ili7836a_supplies, + &ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation); + if (ret < 0) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); + return ret; + } + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE | + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; + + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = ili7836a_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + ret = devm_drm_panel_add(dev, &ctx->panel); + if (ret) + return ret; + + return devm_mipi_dsi_attach(dev, dsi); +} + +static const struct of_device_id ili7836a_of_match[] = { + { .compatible = "retroidpocket,nova-panel", .data = &nova_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ili7836a_of_match); + +static struct mipi_dsi_driver ili7836a_driver = { + .probe = ili7836a_probe, + .driver = { + .name = "panel-ili7836a-amoled", + .of_match_table = ili7836a_of_match, + }, +}; +module_mipi_dsi_driver(ili7836a_driver); + +MODULE_DESCRIPTION("DRM driver for ILI7836A DSI panels"); +MODULE_LICENSE("GPL"); -- 2.54.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver 2026-08-08 19:01 ` [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay @ 2026-08-08 19:16 ` sashiko-bot 2026-08-10 9:58 ` Neil Armstrong 1 sibling, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-08-08 19:16 UTC (permalink / raw) To: Aaron Kling; +Cc: dri-devel, conor+dt, robh, devicetree Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] Unbalanced panel operations due to missing .enable callback - [High] Unsafe backlight DSI transmissions without panel power state validation - [High] Data race on `dsi->mode_flags` between backlight updates and panel state changes - [Medium] Early return in backlight update callback leaks DSI mode state - [Medium] The get_modes callback ignores descriptor physical attributes and multiple modes -- --- Patch [2]: [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver --- commit 1ef963af27698ad0874d830a6b469bf1d540bc0b Author: Aaron Kling <webgeek1234@gmail.com> Subject: drm/panel: add Ilitek ILI7836A panel driver This commit introduces a new DRM panel driver for the Ilitek ILI7836A DDIC, initially supporting the Retroid Pocket Nova panel. > diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c b/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c > new file mode 100644 > --- /dev/null > +++ b/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c [ ... ] > +static int ili7836a_get_modes(struct drm_panel *panel, > + struct drm_connector *connector) > +{ > + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); > + > + return drm_connector_helper_get_modes_fixed(connector, ctx->desc->modes); > +} [Severity: Medium] Does this ignore the physical dimensions and color depth defined in nova_desc? The descriptor explicitly defines width_mm, height_mm, and bpc, but drm_connector_helper_get_modes_fixed() only extracts a single fixed mode without populating the connector's physical size or color format information. Additionally, the num_modes property in the descriptor appears to be ignored. > +static enum drm_panel_orientation ili7836a_get_orientation(struct drm_panel *panel) > +{ > + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); > + > + return ctx->orientation; > +} > + > +static const struct drm_panel_funcs ili7836a_panel_funcs = { > + .prepare = ili7836a_prepare, > + .unprepare = ili7836a_unprepare, > + .disable = ili7836a_disable, > + .get_modes = ili7836a_get_modes, > + .get_orientation = ili7836a_get_orientation, > +}; [Severity: High] Will this leave the panel permanently black after certain display power management transitions? The driver implements the .disable callback which sends DCS sleep commands, but it omits the corresponding .enable callback. Since drm_panel_enable() will be a no-op, the panel may remain in sleep mode without a full power cycle. > + > +static int ili7836a_bl_update_status(struct backlight_device *bl) > +{ > + struct mipi_dsi_device *dsi = bl_get_data(bl); > + u16 brightness = backlight_get_brightness(bl); > + int ret; > + > + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; > + > + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); [Severity: High] Can this cause DSI host transmission timeouts if called while the panel is powered down? The backlight device is accessible via sysfs independently of the panel's DRM state. Writing to the brightness attribute while the panel regulators are disabled would execute DCS writes on an unpowered DSI bus. [Severity: High] Is there a data race on dsi->mode_flags here? Backlight updates can execute concurrently via sysfs while the DRM subsystem invokes panel enable/disable operations. Since the mode_flags bitmask is modified using non-atomic bitwise operations, a read-modify-write race could occur between this function and the DRM ioctl paths: ili7836a_on() { ... ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; } ili7836a_disable() { ... ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; } > + if (ret < 0) > + return ret; [Severity: Medium] If mipi_dsi_dcs_set_display_brightness_large() fails, does this early return permanently clear the MIPI_DSI_MODE_LPM bit? The error path exits before restoring the mode_flags, which might disrupt subsequent DSI communication. > + > + dsi->mode_flags |= MIPI_DSI_MODE_LPM; > + > + return 0; > +} -- Sashiko AI review · https://sashiko.dev/#/patchset/20260808-ili7836a-v1-0-07a7becc5636@gmail.com?part=2 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver 2026-08-08 19:01 ` [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay 2026-08-08 19:16 ` sashiko-bot @ 2026-08-10 9:58 ` Neil Armstrong 1 sibling, 0 replies; 8+ messages in thread From: Neil Armstrong @ 2026-08-10 9:58 UTC (permalink / raw) To: webgeek1234, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel On 8/8/26 21:01, Aaron Kling via B4 Relay wrote: > From: Aaron Kling <webgeek1234@gmail.com> > > This is a DDIC which can be used in various panels. The first > supported panel is the one used in the Retroid Pocket Nova. > > Signed-off-by: Aaron Kling <webgeek1234@gmail.com> > --- > drivers/gpu/drm/panel/Kconfig | 11 + > drivers/gpu/drm/panel/Makefile | 1 + > drivers/gpu/drm/panel/panel-ilitek-ili7836a.c | 297 ++++++++++++++++++++++++++ > 3 files changed, 309 insertions(+) > > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig > index cbdf7b8f7f7af..792d6b92798d9 100644 > --- a/drivers/gpu/drm/panel/Kconfig > +++ b/drivers/gpu/drm/panel/Kconfig > @@ -298,6 +298,17 @@ config DRM_PANEL_ILITEK_ILI7807S > > If M is selected the module will be called panel-ilitek-ili7807s. > > +config DRM_PANEL_ILITEK_ILI7836A > + tristate "Ilitek ILI7836A-based panels" > + depends on OF > + depends on DRM_MIPI_DSI > + depends on BACKLIGHT_CLASS_DEVICE > + help > + Say Y if you want to enable support for panels based on the > + Ilitek ILI7836A DDIC. > + > + If M is selected the module will be called panel-ilitek-ili7836a. > + > config DRM_PANEL_ILITEK_IL9322 > tristate "Ilitek ILI9322 320x240 QVGA panels" > depends on OF && SPI > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile > index 3b523cf378330..be96f4e8112da 100644 > --- a/drivers/gpu/drm/panel/Makefile > +++ b/drivers/gpu/drm/panel/Makefile > @@ -29,6 +29,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o > obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o > obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o > obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7807S) += panel-ilitek-ili7807s.o > +obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7836A) += panel-ilitek-ili7836a.o > obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o > obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o > obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9488) += panel-ilitek-ili9488.o > diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c b/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c > new file mode 100644 > index 0000000000000..f6331129dadf2 > --- /dev/null > +++ b/drivers/gpu/drm/panel/panel-ilitek-ili7836a.c > @@ -0,0 +1,297 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#include <linux/backlight.h> > +#include <linux/delay.h> > +#include <linux/gpio/consumer.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/regulator/consumer.h> > + > +#include <drm/drm_connector.h> > +#include <drm/drm_crtc.h> > +#include <drm/drm_mipi_dsi.h> > +#include <drm/drm_modes.h> > +#include <drm/drm_of.h> > +#include <drm/drm_panel.h> > +#include <drm/drm_probe_helper.h> > + > +#include <video/mipi_display.h> > + > +static const struct regulator_bulk_data ili7836a_supplies[] = { > + { .supply = "vddio", }, > + { .supply = "avdd", }, > +}; > + > +struct ili7836a_panel { > + struct drm_panel panel; > + struct drm_connector *connector; > + struct mipi_dsi_device *dsi; > + struct regulator_bulk_data *supplies; > + struct gpio_desc *reset_gpio; > + struct ili7836a_desc *desc; > + enum drm_panel_orientation orientation; > +}; > + > +struct ili7836a_desc { > + unsigned int width_mm; > + unsigned int height_mm; > + unsigned int bpc; > + > + const struct drm_display_mode *modes; > + unsigned int num_modes; > +}; > + > +static inline struct ili7836a_panel *to_ili7836a_panel(struct drm_panel *panel) > +{ > + return container_of(panel, struct ili7836a_panel, panel); > +} > + > +static void ili7836a_reset(struct ili7836a_panel *ctx) > +{ > + gpiod_set_value_cansleep(ctx->reset_gpio, 0); > + msleep(20); > + gpiod_set_value_cansleep(ctx->reset_gpio, 1); > + msleep(20); > + gpiod_set_value_cansleep(ctx->reset_gpio, 0); > + msleep(20); > +} > + > +static int ili7836a_on(struct ili7836a_panel *ctx) > +{ > + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; > + > + ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; > + > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x08); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x62); > + > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x21); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa4, 0x38); > + > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x23); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x85, 0x15); > + > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x00); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x00); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x20); > + > + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); > + mipi_dsi_msleep(&dsi_ctx, 120); > + > + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); > + mipi_dsi_msleep(&dsi_ctx, 20); > + > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x22); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x01); > + > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0xa5, 0x00); > + > + return dsi_ctx.accum_err; > +} > + > +static int ili7836a_disable(struct drm_panel *panel) > +{ > + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); > + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; > + > + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; > + > + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); > + mipi_dsi_msleep(&dsi_ctx, 20); > + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); > + mipi_dsi_msleep(&dsi_ctx, 120); > + > + return dsi_ctx.accum_err; > +} > + > +static int ili7836a_prepare(struct drm_panel *panel) > +{ > + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); > + struct device *dev = &ctx->dsi->dev; > + int ret; > + > + ret = regulator_bulk_enable(ARRAY_SIZE(ili7836a_supplies), ctx->supplies); > + if (ret < 0) { > + dev_err(dev, "Failed to enable regulators: %d\n", ret); > + return ret; > + } > + > + ili7836a_reset(ctx); > + > + ret = ili7836a_on(ctx); > + if (ret < 0) { > + dev_err(dev, "Failed to initialize panel: %d\n", ret); > + gpiod_set_value_cansleep(ctx->reset_gpio, 1); > + regulator_bulk_disable(ARRAY_SIZE(ili7836a_supplies), ctx->supplies); > + return ret; > + } > + > + return 0; > +} > + > +static int ili7836a_unprepare(struct drm_panel *panel) > +{ > + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); > + > + gpiod_set_value_cansleep(ctx->reset_gpio, 1); > + regulator_bulk_disable(ARRAY_SIZE(ili7836a_supplies), ctx->supplies); > + > + return 0; > +} > + > +static const struct drm_display_mode nova_modes[] = { > + { > + /* 120Hz */ > + .clock = (1280 + 12 + 2 + 8) * (960 + 12 + 2 + 24) * 120 / 1000, > + .hdisplay = 1280, > + .hsync_start = 1280 + 12, > + .hsync_end = 1280 + 12 + 2, > + .htotal = 1280 + 12 + 2 + 8, > + .vdisplay = 960, > + .vsync_start = 960 + 12, > + .vsync_end = 960 + 12 + 2, > + .vtotal = 960 + 12 + 2 + 24, > + } > +}; > + > +static struct ili7836a_desc nova_desc = { > + .modes = nova_modes, > + .num_modes = ARRAY_SIZE(nova_modes), > + .width_mm = 91, > + .height_mm = 68, > + .bpc = 8, > +}; > + > +static int ili7836a_get_modes(struct drm_panel *panel, > + struct drm_connector *connector) > +{ > + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); > + > + return drm_connector_helper_get_modes_fixed(connector, ctx->desc->modes); > +} > + > +static enum drm_panel_orientation ili7836a_get_orientation(struct drm_panel *panel) > +{ > + struct ili7836a_panel *ctx = to_ili7836a_panel(panel); > + > + return ctx->orientation; > +} > + > +static const struct drm_panel_funcs ili7836a_panel_funcs = { > + .prepare = ili7836a_prepare, > + .unprepare = ili7836a_unprepare, > + .disable = ili7836a_disable, > + .get_modes = ili7836a_get_modes, > + .get_orientation = ili7836a_get_orientation, > +}; > + > +static int ili7836a_bl_update_status(struct backlight_device *bl) > +{ > + struct mipi_dsi_device *dsi = bl_get_data(bl); > + u16 brightness = backlight_get_brightness(bl); > + int ret; > + > + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; > + > + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); > + if (ret < 0) > + return ret; > + > + dsi->mode_flags |= MIPI_DSI_MODE_LPM; > + > + return 0; > +} > + > +static const struct backlight_ops ili7836a_bl_ops = { > + .update_status = ili7836a_bl_update_status, > +}; > + > +static struct backlight_device * > +ili7836a_create_backlight(struct mipi_dsi_device *dsi) > +{ > + struct device *dev = &dsi->dev; > + const struct backlight_properties props = { > + .type = BACKLIGHT_RAW, > + .brightness = 3445, > + .max_brightness = 3445, > + }; > + > + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, > + &ili7836a_bl_ops, &props); > +} > + > +static int ili7836a_probe(struct mipi_dsi_device *dsi) > +{ > + struct device *dev = &dsi->dev; > + struct ili7836a_panel *ctx; > + int ret; > + > + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, > + &ili7836a_panel_funcs, > + DRM_MODE_CONNECTOR_DSI); > + if (IS_ERR(ctx)) > + return PTR_ERR(ctx); > + > + ctx->desc = (struct ili7836a_desc *)of_device_get_match_data(dev); > + if (!ctx->desc) > + return -ENODEV; > + > + ret = devm_regulator_bulk_get_const(dev, > + ARRAY_SIZE(ili7836a_supplies), > + ili7836a_supplies, > + &ctx->supplies); > + if (ret < 0) > + return dev_err_probe(dev, ret, "Failed to get regulators\n"); > + > + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); > + if (IS_ERR(ctx->reset_gpio)) > + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), > + "Failed to get reset-gpios\n"); > + > + ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation); > + if (ret < 0) { > + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); > + return ret; > + } > + > + ctx->dsi = dsi; > + mipi_dsi_set_drvdata(dsi, ctx); > + > + dsi->lanes = 4; > + dsi->format = MIPI_DSI_FMT_RGB888; > + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE | > + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; > + > + ctx->panel.prepare_prev_first = true; > + > + ctx->panel.backlight = ili7836a_create_backlight(dsi); > + if (IS_ERR(ctx->panel.backlight)) > + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), > + "Failed to create backlight\n"); > + > + ret = devm_drm_panel_add(dev, &ctx->panel); > + if (ret) > + return ret; > + > + return devm_mipi_dsi_attach(dev, dsi); > +} > + > +static const struct of_device_id ili7836a_of_match[] = { > + { .compatible = "retroidpocket,nova-panel", .data = &nova_desc }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, ili7836a_of_match); > + > +static struct mipi_dsi_driver ili7836a_driver = { > + .probe = ili7836a_probe, > + .driver = { > + .name = "panel-ili7836a-amoled", > + .of_match_table = ili7836a_of_match, > + }, > +}; > +module_mipi_dsi_driver(ili7836a_driver); > + > +MODULE_DESCRIPTION("DRM driver for ILI7836A DSI panels"); > +MODULE_LICENSE("GPL"); > Looks good Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> Thanks, Neil ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/2] drm/panel: add Ilitek ILI7836A panel driver 2026-08-08 19:01 [PATCH 0/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay 2026-08-08 19:01 ` [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver Aaron Kling via B4 Relay 2026-08-08 19:01 ` [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay @ 2026-08-31 14:29 ` Neil Armstrong 2 siblings, 0 replies; 8+ messages in thread From: Neil Armstrong @ 2026-08-31 14:29 UTC (permalink / raw) To: Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Aaron Kling Cc: dri-devel, devicetree, linux-kernel Hi, On Sat, 08 Aug 2026 14:01:13 -0500, Aaron Kling wrote: > Add support for the Ilitek ILI7836A DDIC. > > This depends on the Retroid Pocket dt series [0] for the vendor prefix > patch. That series depends on the AYN dt series [1] to apply cleanly. > > [0] https://lore.kernel.org/linux-arm-msm/20260808-rp-qcs8550-v1-0-a5a365ba3dc5@gmail.com/ > [1] https://lore.kernel.org/linux-arm-msm/20260727-ayn-qcs8550-v9-0-e3db456e10e5@gmail.com/ > > [...] Thanks, Applied to https://gitlab.freedesktop.org/drm/misc/kernel.git (drm-misc-next) [1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver https://gitlab.freedesktop.org/drm/misc/kernel/-/commit/1b59be32378e9ff5e9d1fc1168e46362701c751b [2/2] drm/panel: add Ilitek ILI7836A panel driver https://gitlab.freedesktop.org/drm/misc/kernel/-/commit/8a78143d94bbc9ed471d57599563bee0757493f4 -- Neil ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-31 14:29 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-08 19:01 [PATCH 0/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay 2026-08-08 19:01 ` [PATCH 1/2] dt-bindings: display: panel: add Ilitek ILI7836A OLED driver Aaron Kling via B4 Relay 2026-08-08 19:06 ` sashiko-bot 2026-08-19 8:36 ` Krzysztof Kozlowski 2026-08-08 19:01 ` [PATCH 2/2] drm/panel: add Ilitek ILI7836A panel driver Aaron Kling via B4 Relay 2026-08-08 19:16 ` sashiko-bot 2026-08-10 9:58 ` Neil Armstrong 2026-08-31 14:29 ` [PATCH 0/2] " Neil Armstrong
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).