Skip to content

Commit 5b1b66a

Browse files
drm: rp1: rp1-dpi: Add interlaced modes and PIO program to fix VSYNC
Implement interlaced modes by wobbling the base pointer and VFP width for every field. This results in correct pixels but incorrect VSYNC. Now use PIO to generate a fixed-up VSYNC by sampling DE and HSYNC. This requires DPI's DE output to be mapped to GPIO1, which we check. When DE is not exposed, the internal fixup is disabled. VSYNC/GPIO2 becomes a modified signal, designed to help an external device or PIO program synthesize CSYNC or VSYNC. Signed-off-by: Nick Hollinghurst <[email protected]>
1 parent 53a924f commit 5b1b66a

File tree

5 files changed

+424
-48
lines changed

5 files changed

+424
-48
lines changed

drivers/gpu/drm/rp1/rp1-dpi/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22

3-
drm-rp1-dpi-y := rp1_dpi.o rp1_dpi_hw.o rp1_dpi_cfg.o
3+
drm-rp1-dpi-y := rp1_dpi.o rp1_dpi_hw.o rp1_dpi_cfg.o rp1_dpi_pio.o
44

55
obj-$(CONFIG_DRM_RP1_DPI) += drm-rp1-dpi.o

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe,
8080
if (dpi->dpi_running &&
8181
fb->format->format != dpi->cur_fmt) {
8282
rp1dpi_hw_stop(dpi);
83+
rp1dpi_pio_stop(dpi);
8384
dpi->dpi_running = false;
8485
}
8586
if (!dpi->dpi_running) {
@@ -88,6 +89,7 @@ static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe,
8889
dpi->bus_fmt,
8990
dpi->de_inv,
9091
&pipe->crtc.state->mode);
92+
rp1dpi_pio_start(dpi, &pipe->crtc.state->mode);
9193
dpi->dpi_running = true;
9294
}
9395
dpi->cur_fmt = fb->format->format;
@@ -187,6 +189,7 @@ static void rp1dpi_pipe_disable(struct drm_simple_display_pipe *pipe)
187189
drm_crtc_vblank_off(&pipe->crtc);
188190
if (dpi->dpi_running) {
189191
rp1dpi_hw_stop(dpi);
192+
rp1dpi_pio_stop(dpi);
190193
dpi->dpi_running = false;
191194
}
192195
clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]);
@@ -236,6 +239,7 @@ static void rp1dpi_stopall(struct drm_device *drm)
236239
if (dpi->dpi_running || rp1dpi_hw_busy(dpi)) {
237240
rp1dpi_hw_stop(dpi);
238241
clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]);
242+
rp1dpi_pio_stop(dpi);
239243
dpi->dpi_running = false;
240244
}
241245
rp1dpi_vidout_poweroff(dpi);
@@ -273,7 +277,7 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
273277
struct rp1_dpi *dpi;
274278
struct drm_bridge *bridge = NULL;
275279
struct drm_panel *panel;
276-
int i, ret;
280+
int i, j, ret;
277281

278282
dev_info(dev, __func__);
279283
ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 0, 0,
@@ -295,6 +299,7 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
295299
return ret;
296300
}
297301
dpi->pdev = pdev;
302+
spin_lock_init(&dpi->hw_lock);
298303

299304
dpi->bus_fmt = default_bus_fmt;
300305
ret = of_property_read_u32(dev->of_node, "default_bus_fmt", &dpi->bus_fmt);
@@ -332,6 +337,33 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
332337
if (ret)
333338
goto done_err;
334339

340+
/* Check if PIO can snoop on or override DPI's GPIO1 */
341+
dpi->gpio1_used = false;
342+
for (i = 0; !dpi->gpio1_used; i++) {
343+
u32 p = 0;
344+
const char *str = NULL;
345+
struct device_node *np1 = of_parse_phandle(dev->of_node, "pinctrl-0", i);
346+
347+
if (!np1)
348+
break;
349+
350+
if (!of_property_read_string(np1, "function", &str) && !strcmp(str, "dpi")) {
351+
for (j = 0; !dpi->gpio1_used; j++) {
352+
if (of_property_read_string_index(np1, "pins", j, &str))
353+
break;
354+
if (!strcmp(str, "gpio1"))
355+
dpi->gpio1_used = true;
356+
}
357+
for (j = 0; !dpi->gpio1_used; j++) {
358+
if (of_property_read_u32_index(np1, "brcm,pins", j, &p))
359+
break;
360+
if (p == 1)
361+
dpi->gpio1_used = true;
362+
}
363+
}
364+
of_node_put(np1);
365+
}
366+
335367
/* Now we have all our resources, finish driver initialization */
336368
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
337369
init_completion(&dpi->finished);

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ struct rp1_dpi {
4646
bool de_inv, clk_inv;
4747
bool dpi_running, pipe_enabled;
4848
struct completion finished;
49+
50+
/* Experimental stuff for interlace follows */
51+
struct rp1_pio_client *pio;
52+
bool gpio1_used;
53+
bool pio_stole_gpio2;
54+
55+
spinlock_t hw_lock; /* the following are used in line-match ISR */
56+
dma_addr_t last_dma_addr;
57+
u32 last_stride;
58+
u32 shorter_front_porch;
59+
bool interlaced;
60+
bool lower_field_flag;
4961
};
5062

5163
/* ---------------------------------------------------------------------- */
@@ -67,3 +79,9 @@ void rp1dpi_hw_vblank_ctrl(struct rp1_dpi *dpi, int enable);
6779

6880
void rp1dpi_vidout_setup(struct rp1_dpi *dpi, bool drive_negedge);
6981
void rp1dpi_vidout_poweroff(struct rp1_dpi *dpi);
82+
83+
/* ---------------------------------------------------------------------- */
84+
/* PIO control -- we need PIO to generate VSync (from DE) when interlaced */
85+
86+
int rp1dpi_pio_start(struct rp1_dpi *dpi, const struct drm_display_mode *mode);
87+
void rp1dpi_pio_stop(struct rp1_dpi *dpi);

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c

Lines changed: 147 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -354,42 +354,26 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
354354
u32 in_format, u32 bus_format, bool de_inv,
355355
struct drm_display_mode const *mode)
356356
{
357-
u32 shift, imask, omask, rgbsz;
357+
u32 shift, imask, omask, rgbsz, vctrl;
358358
int i;
359359

360-
pr_info("%s: in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d %dkHz %cH%cV%cD%cC",
361-
__func__, in_format, in_format >> 8, in_format >> 16, in_format >> 24, bus_format,
362-
mode->hdisplay, mode->vdisplay,
363-
mode->htotal, mode->vtotal,
364-
mode->clock,
365-
(mode->flags & DRM_MODE_FLAG_NHSYNC) ? '-' : '+',
366-
(mode->flags & DRM_MODE_FLAG_NVSYNC) ? '-' : '+',
367-
de_inv ? '-' : '+',
368-
dpi->clk_inv ? '-' : '+');
360+
drm_info(&dpi->drm,
361+
"in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d%s %dkHz %cH%cV%cD%cC",
362+
in_format, in_format >> 8, in_format >> 16, in_format >> 24, bus_format,
363+
mode->hdisplay, mode->vdisplay,
364+
mode->htotal, mode->vtotal,
365+
(mode->flags & DRM_MODE_FLAG_INTERLACE) ? "i" : "",
366+
mode->clock,
367+
(mode->flags & DRM_MODE_FLAG_NHSYNC) ? '-' : '+',
368+
(mode->flags & DRM_MODE_FLAG_NVSYNC) ? '-' : '+',
369+
de_inv ? '-' : '+',
370+
dpi->clk_inv ? '-' : '+');
369371

370372
/*
371373
* Configure all DPI/DMA block registers, except base address.
372374
* DMA will not actually start until a FB base address is specified
373375
* using rp1dpi_hw_update().
374376
*/
375-
rp1dpi_hw_write(dpi, DPI_DMA_VISIBLE_AREA,
376-
BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) |
377-
BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1));
378-
379-
rp1dpi_hw_write(dpi, DPI_DMA_SYNC_WIDTH,
380-
BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) |
381-
BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1));
382-
383-
/* In these registers, "back porch" time includes sync width */
384-
rp1dpi_hw_write(dpi, DPI_DMA_BACK_PORCH,
385-
BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) |
386-
BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1));
387-
388-
rp1dpi_hw_write(dpi, DPI_DMA_FRONT_PORCH,
389-
BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) |
390-
BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1));
391-
392-
/* Input to output pixel format conversion */
393377
for (i = 0; i < ARRAY_SIZE(my_formats); ++i) {
394378
if (my_formats[i].format == in_format)
395379
break;
@@ -417,6 +401,80 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
417401
BITS(DPI_DMA_QOS_LLEV, 0x8) |
418402
BITS(DPI_DMA_QOS_LQOS, 0x7));
419403

404+
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
405+
rp1dpi_hw_write(dpi, DPI_DMA_VISIBLE_AREA,
406+
BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) |
407+
BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1));
408+
409+
rp1dpi_hw_write(dpi, DPI_DMA_SYNC_WIDTH,
410+
BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) |
411+
BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1));
412+
413+
/* In these registers, "back porch" time includes sync width */
414+
rp1dpi_hw_write(dpi, DPI_DMA_BACK_PORCH,
415+
BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) |
416+
BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1));
417+
418+
rp1dpi_hw_write(dpi, DPI_DMA_FRONT_PORCH,
419+
BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) |
420+
BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1));
421+
422+
vctrl = BITS(DPI_DMA_CONTROL_VSYNC_POL, !!(mode->flags & DRM_MODE_FLAG_NVSYNC)) |
423+
BITS(DPI_DMA_CONTROL_VBP_EN, (mode->vtotal != mode->vsync_start)) |
424+
BITS(DPI_DMA_CONTROL_VFP_EN, (mode->vsync_start != mode->vdisplay)) |
425+
BITS(DPI_DMA_CONTROL_VSYNC_EN, (mode->vsync_end != mode->vsync_start));
426+
427+
dpi->interlaced = false;
428+
} else {
429+
/*
430+
* Experimental interlace support
431+
*
432+
* RP1 DPI hardware wasn't designed to support interlace, but lets us change
433+
* both the VFP line count and the next DMA address while running. That allows
434+
* pixel data to be correctly timed for interlace, but VSYNC remains wrong.
435+
*
436+
* It is necessary to use external hardware (such as PIO) to regenerate VSYNC
437+
* based on HSYNC, DE (which *must* both be mapped to GPIOs 1, 3 respectively).
438+
* This driver includes a PIO program to do that, when DE is enabled.
439+
*
440+
* An alternative fixup is to synthesize CSYNC from HSYNC and modified-VSYNC.
441+
* We don't implement that here, but to facilitate it, DPI's VSYNC is replaced
442+
* by a "helper signal" that pulses low for 1 or 2 scan-lines, starting 2.5 or
443+
* 3.0 scan-lines before the vertical datum "0v".
444+
*/
445+
int vact = mode->vdisplay >> 1; /* visible lines per field. Can't do half-lines */
446+
int vtot0 = mode->vtotal >> 1; /* vtotal should always be odd when interlaced. */
447+
int vfp0 = (mode->vsync_start >= mode->vdisplay + 7) ?
448+
((mode->vsync_start - mode->vdisplay - 5) >> 1) : 1;
449+
int vbp = max(0, vtot0 - vact - vfp0);
450+
451+
rp1dpi_hw_write(dpi, DPI_DMA_VISIBLE_AREA,
452+
BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, vact - 1) |
453+
BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1));
454+
455+
rp1dpi_hw_write(dpi, DPI_DMA_SYNC_WIDTH,
456+
BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, vtot0 - 2) |
457+
BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1));
458+
459+
rp1dpi_hw_write(dpi, DPI_DMA_BACK_PORCH,
460+
BITS(DPI_DMA_BACK_PORCH_ROWSM1, vbp - 1) |
461+
BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1));
462+
463+
dpi->shorter_front_porch =
464+
BITS(DPI_DMA_FRONT_PORCH_ROWSM1, vfp0 - 1) |
465+
BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1);
466+
rp1dpi_hw_write(dpi, DPI_DMA_FRONT_PORCH, dpi->shorter_front_porch);
467+
468+
vctrl = BITS(DPI_DMA_CONTROL_VSYNC_POL, 0) |
469+
BITS(DPI_DMA_CONTROL_VBP_EN, (vbp > 0)) |
470+
BITS(DPI_DMA_CONTROL_VFP_EN, 1) |
471+
BITS(DPI_DMA_CONTROL_VSYNC_EN, 1);
472+
473+
dpi->interlaced = true;
474+
}
475+
dpi->lower_field_flag = false;
476+
dpi->last_dma_addr = 0;
477+
420478
rp1dpi_hw_write(dpi, DPI_DMA_IRQ_FLAGS, -1);
421479
rp1dpi_hw_vblank_ctrl(dpi, 1);
422480

@@ -425,49 +483,64 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
425483
pr_warn("%s: Unexpectedly busy at start!", __func__);
426484

427485
rp1dpi_hw_write(dpi, DPI_DMA_CONTROL,
486+
vctrl |
428487
BITS(DPI_DMA_CONTROL_ARM, !i) |
429488
BITS(DPI_DMA_CONTROL_AUTO_REPEAT, 1) |
430489
BITS(DPI_DMA_CONTROL_HIGH_WATER, 448) |
431490
BITS(DPI_DMA_CONTROL_DEN_POL, de_inv) |
432491
BITS(DPI_DMA_CONTROL_HSYNC_POL, !!(mode->flags & DRM_MODE_FLAG_NHSYNC)) |
433-
BITS(DPI_DMA_CONTROL_VSYNC_POL, !!(mode->flags & DRM_MODE_FLAG_NVSYNC)) |
434-
BITS(DPI_DMA_CONTROL_COLORM, 0) |
435-
BITS(DPI_DMA_CONTROL_SHUTDN, 0) |
436492
BITS(DPI_DMA_CONTROL_HBP_EN, (mode->htotal != mode->hsync_end)) |
437493
BITS(DPI_DMA_CONTROL_HFP_EN, (mode->hsync_start != mode->hdisplay)) |
438-
BITS(DPI_DMA_CONTROL_VBP_EN, (mode->vtotal != mode->vsync_end)) |
439-
BITS(DPI_DMA_CONTROL_VFP_EN, (mode->vsync_start != mode->vdisplay)) |
440-
BITS(DPI_DMA_CONTROL_HSYNC_EN, (mode->hsync_end != mode->hsync_start)) |
441-
BITS(DPI_DMA_CONTROL_VSYNC_EN, (mode->vsync_end != mode->vsync_start)));
494+
BITS(DPI_DMA_CONTROL_HSYNC_EN, (mode->hsync_end != mode->hsync_start)));
442495
}
443496

444497
void rp1dpi_hw_update(struct rp1_dpi *dpi, dma_addr_t addr, u32 offset, u32 stride)
445498
{
446-
u64 a = addr + offset;
499+
unsigned long flags;
500+
501+
spin_lock_irqsave(&dpi->hw_lock, flags);
447502

448503
/*
449504
* Update STRIDE, DMAH and DMAL only. When called after rp1dpi_hw_setup(),
450505
* DMA starts immediately; if already running, the buffer will flip at
451-
* the next vertical sync event.
506+
* the next vertical sync event. In interlaced mode, we need to adjust
507+
* the address and stride to display only the current field, saving
508+
* the original address (so it can be flipped for subsequent fields).
452509
*/
510+
addr += offset;
511+
dpi->last_dma_addr = addr;
512+
dpi->last_stride = stride;
513+
if (dpi->interlaced) {
514+
if (dpi->lower_field_flag)
515+
addr += stride;
516+
stride *= 2;
517+
}
453518
rp1dpi_hw_write(dpi, DPI_DMA_DMA_STRIDE, stride);
454-
rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_H, a >> 32);
455-
rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu);
519+
rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_H, addr >> 32);
520+
rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_L, addr & 0xFFFFFFFFu);
521+
522+
spin_unlock_irqrestore(&dpi->hw_lock, flags);
456523
}
457524

458525
void rp1dpi_hw_stop(struct rp1_dpi *dpi)
459526
{
460527
u32 ctrl;
528+
unsigned long flags;
461529

462530
/*
463-
* Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for
464-
* the current and any queued frame to end. "Force drain" flags are not used,
465-
* as they seem to prevent DMA from re-starting properly; it's safer to wait.
531+
* Stop DMA by turning off Auto-Repeat (and disable S/W field-flip),
532+
* then wait up to 100ms for the current and any queued frame to end.
533+
* (There is a "force drain" flag, but it can leave DPI in a broken
534+
* state which prevents it from restarting; it's safer to wait.)
466535
*/
536+
spin_lock_irqsave(&dpi->hw_lock, flags);
537+
dpi->last_dma_addr = 0;
467538
reinit_completion(&dpi->finished);
468539
ctrl = rp1dpi_hw_read(dpi, DPI_DMA_CONTROL);
469540
ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK);
470541
rp1dpi_hw_write(dpi, DPI_DMA_CONTROL, ctrl);
542+
spin_unlock_irqrestore(&dpi->hw_lock, flags);
543+
471544
if (!wait_for_completion_timeout(&dpi->finished, HZ / 10))
472545
drm_err(&dpi->drm, "%s: timed out waiting for idle\n", __func__);
473546
rp1dpi_hw_write(dpi, DPI_DMA_IRQ_EN, 0);
@@ -476,10 +549,11 @@ void rp1dpi_hw_stop(struct rp1_dpi *dpi)
476549
void rp1dpi_hw_vblank_ctrl(struct rp1_dpi *dpi, int enable)
477550
{
478551
rp1dpi_hw_write(dpi, DPI_DMA_IRQ_EN,
479-
BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1) |
480-
BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1) |
481-
BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) |
482-
BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 4095));
552+
BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1) |
553+
BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1) |
554+
BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) |
555+
BITS(DPI_DMA_IRQ_EN_MATCH, dpi->interlaced) |
556+
BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 32));
483557
}
484558

485559
irqreturn_t rp1dpi_hw_isr(int irq, void *dev)
@@ -498,7 +572,34 @@ irqreturn_t rp1dpi_hw_isr(int irq, void *dev)
498572
drm_crtc_handle_vblank(&dpi->pipe.crtc);
499573
if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK)
500574
complete(&dpi->finished);
575+
576+
/*
577+
* Added for interlace support: We use this mid-frame interrupt to
578+
* wobble the VFP between fields, re-submitting the next-buffer address
579+
* with an offset to display the opposite field. NB: rp1dpi_hw_update()
580+
* may be called at any time, before or after, so locking is needed.
581+
* H/W Auto-update is no longer needed (unless this IRQ is lost).
582+
*/
583+
if ((u & DPI_DMA_IRQ_FLAGS_MATCH_MASK) && dpi->interlaced) {
584+
unsigned long flags;
585+
dma_addr_t a;
586+
587+
spin_lock_irqsave(&dpi->hw_lock, flags);
588+
dpi->lower_field_flag = !dpi->lower_field_flag;
589+
rp1dpi_hw_write(dpi, DPI_DMA_FRONT_PORCH,
590+
dpi->shorter_front_porch +
591+
BITS(DPI_DMA_FRONT_PORCH_ROWSM1, dpi->lower_field_flag));
592+
a = dpi->last_dma_addr;
593+
if (a) {
594+
if (dpi->lower_field_flag)
595+
a += dpi->last_stride;
596+
rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_H, a >> 32);
597+
rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu);
598+
}
599+
spin_unlock_irqrestore(&dpi->hw_lock, flags);
600+
}
501601
}
502602
}
603+
503604
return u ? IRQ_HANDLED : IRQ_NONE;
504605
}

0 commit comments

Comments
 (0)