Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bef2c7bd authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm/tegra/for-4.3-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next

drm/tegra: Changes for v4.3-rc1

There are a bunch of non-critical fixes here that I've collected over
the past few months, but the biggest part is Tegra210 support, in the
DC, DSI and SOR/HDMI drivers.

Also this finally restores DPMS with atomic mode-setting, something
that has been broken since the conversion and which I had originally
expected to take far less longer to fix.

* tag 'drm/tegra/for-4.3-rc1' of git://anongit.freedesktop.org/tegra/linux: (41 commits)
  drm/tegra: sor: Add HDMI support
  drm/tegra: sor: Add Tegra210 eDP support
  drm/tegra: dc: Implement atomic DPMS
  drm/tegra: sor: Restore DPMS
  drm/tegra: dsi: Restore DPMS
  drm/tegra: hdmi: Restore DPMS
  drm/tegra: rgb: Restore DPMS
  drm/tegra: sor: Use DRM debugfs infrastructure for CRC
  drm/tegra: sor: Write correct head state registers
  drm/tegra: sor: Constify display mode
  drm/tegra: sor: Reset the correct debugfs fields
  drm/tegra: sor: Set minor after debugfs initialization
  drm/tegra: sor: Provide error messages in probe
  drm/tegra: sor: Rename registers for consistency
  drm/tegra: dpaux: Disable interrupt when detached
  drm/tegra: dpaux: Configure pads as I2C by default
  drm/tegra: dpaux: Provide error message in probe
  drm/tegra: dsi: Add Tegra210 support
  drm/tegra: dsi: Add Tegra132 support
  drm/tegra: dsi: Add Tegra124 support
  ...
parents 3ff8e509 459cc2c6
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -197,9 +197,11 @@ of the following host1x client modules:
- sor: serial output resource
- sor: serial output resource


  Required properties:
  Required properties:
  - compatible: For Tegra124, must contain "nvidia,tegra124-sor".  Otherwise,
  - compatible: Should be:
    must contain '"nvidia,<chip>-sor", "nvidia,tegra124-sor"', where <chip>
    - "nvidia,tegra124-sor": for Tegra124 and Tegra132
    is tegra132.
    - "nvidia,tegra132-sor": for Tegra132
    - "nvidia,tegra210-sor": for Tegra210
    - "nvidia,tegra210-sor1": for Tegra210
  - reg: Physical base address and length of the controller's registers.
  - reg: Physical base address and length of the controller's registers.
  - interrupts: The interrupt outputs from the controller.
  - interrupts: The interrupt outputs from the controller.
  - clocks: Must contain an entry for each entry in clock-names.
  - clocks: Must contain an entry for each entry in clock-names.
+185 −109
Original line number Original line Diff line number Diff line
@@ -76,6 +76,14 @@ to_tegra_plane_state(struct drm_plane_state *state)
	return NULL;
	return NULL;
}
}


static void tegra_dc_stats_reset(struct tegra_dc_stats *stats)
{
	stats->frames = 0;
	stats->vblank = 0;
	stats->underflow = 0;
	stats->overflow = 0;
}

/*
/*
 * Reads the active copy of a register. This takes the dc->lock spinlock to
 * Reads the active copy of a register. This takes the dc->lock spinlock to
 * prevent races with the VBLANK processing which also needs access to the
 * prevent races with the VBLANK processing which also needs access to the
@@ -759,7 +767,6 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
	/* position the cursor */
	/* position the cursor */
	value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff);
	value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff);
	tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
	tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);

}
}


static void tegra_cursor_atomic_disable(struct drm_plane *plane,
static void tegra_cursor_atomic_disable(struct drm_plane *plane,
@@ -809,9 +816,11 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);


	/*
	/*
	 * We'll treat the cursor as an overlay plane with index 6 here so
	 * This index is kind of fake. The cursor isn't a regular plane, but
	 * that the update and activation request bits in DC_CMD_STATE_CONTROL
	 * its update and activation request bits in DC_CMD_STATE_CONTROL do
	 * match up.
	 * use the same programming. Setting this fake index here allows the
	 * code in tegra_add_plane_state() to do the right thing without the
	 * need to special-casing the cursor plane.
	 */
	 */
	plane->index = 6;
	plane->index = 6;


@@ -1015,6 +1024,8 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
		crtc->state = &state->base;
		crtc->state = &state->base;
		crtc->state->crtc = crtc;
		crtc->state->crtc = crtc;
	}
	}

	drm_crtc_vblank_reset(crtc);
}
}


static struct drm_crtc_state *
static struct drm_crtc_state *
@@ -1052,90 +1063,6 @@ static const struct drm_crtc_funcs tegra_crtc_funcs = {
	.atomic_destroy_state = tegra_crtc_atomic_destroy_state,
	.atomic_destroy_state = tegra_crtc_atomic_destroy_state,
};
};


static void tegra_dc_stop(struct tegra_dc *dc)
{
	u32 value;

	/* stop the display controller */
	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
	value &= ~DISP_CTRL_MODE_MASK;
	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);

	tegra_dc_commit(dc);
}

static bool tegra_dc_idle(struct tegra_dc *dc)
{
	u32 value;

	value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);

	return (value & DISP_CTRL_MODE_MASK) == 0;
}

static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
{
	timeout = jiffies + msecs_to_jiffies(timeout);

	while (time_before(jiffies, timeout)) {
		if (tegra_dc_idle(dc))
			return 0;

		usleep_range(1000, 2000);
	}

	dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
	return -ETIMEDOUT;
}

static void tegra_crtc_disable(struct drm_crtc *crtc)
{
	struct tegra_dc *dc = to_tegra_dc(crtc);
	u32 value;

	if (!tegra_dc_idle(dc)) {
		tegra_dc_stop(dc);

		/*
		 * Ignore the return value, there isn't anything useful to do
		 * in case this fails.
		 */
		tegra_dc_wait_idle(dc, 100);
	}

	/*
	 * This should really be part of the RGB encoder driver, but clearing
	 * these bits has the side-effect of stopping the display controller.
	 * When that happens no VBLANK interrupts will be raised. At the same
	 * time the encoder is disabled before the display controller, so the
	 * above code is always going to timeout waiting for the controller
	 * to go idle.
	 *
	 * Given the close coupling between the RGB encoder and the display
	 * controller doing it here is still kind of okay. None of the other
	 * encoder drivers require these bits to be cleared.
	 *
	 * XXX: Perhaps given that the display controller is switched off at
	 * this point anyway maybe clearing these bits isn't even useful for
	 * the RGB encoder?
	 */
	if (dc->rgb) {
		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
		value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
			   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
	}

	drm_crtc_vblank_off(crtc);
}

static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
				  const struct drm_display_mode *mode,
				  struct drm_display_mode *adjusted)
{
	return true;
}

static int tegra_dc_set_timings(struct tegra_dc *dc,
static int tegra_dc_set_timings(struct tegra_dc *dc,
				struct drm_display_mode *mode)
				struct drm_display_mode *mode)
{
{
@@ -1229,7 +1156,85 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,
	tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
	tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
}
}


static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
static void tegra_dc_stop(struct tegra_dc *dc)
{
	u32 value;

	/* stop the display controller */
	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
	value &= ~DISP_CTRL_MODE_MASK;
	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);

	tegra_dc_commit(dc);
}

static bool tegra_dc_idle(struct tegra_dc *dc)
{
	u32 value;

	value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);

	return (value & DISP_CTRL_MODE_MASK) == 0;
}

static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
{
	timeout = jiffies + msecs_to_jiffies(timeout);

	while (time_before(jiffies, timeout)) {
		if (tegra_dc_idle(dc))
			return 0;

		usleep_range(1000, 2000);
	}

	dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
	return -ETIMEDOUT;
}

static void tegra_crtc_disable(struct drm_crtc *crtc)
{
	struct tegra_dc *dc = to_tegra_dc(crtc);
	u32 value;

	if (!tegra_dc_idle(dc)) {
		tegra_dc_stop(dc);

		/*
		 * Ignore the return value, there isn't anything useful to do
		 * in case this fails.
		 */
		tegra_dc_wait_idle(dc, 100);
	}

	/*
	 * This should really be part of the RGB encoder driver, but clearing
	 * these bits has the side-effect of stopping the display controller.
	 * When that happens no VBLANK interrupts will be raised. At the same
	 * time the encoder is disabled before the display controller, so the
	 * above code is always going to timeout waiting for the controller
	 * to go idle.
	 *
	 * Given the close coupling between the RGB encoder and the display
	 * controller doing it here is still kind of okay. None of the other
	 * encoder drivers require these bits to be cleared.
	 *
	 * XXX: Perhaps given that the display controller is switched off at
	 * this point anyway maybe clearing these bits isn't even useful for
	 * the RGB encoder?
	 */
	if (dc->rgb) {
		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
		value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
			   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
	}

	tegra_dc_stats_reset(&dc->stats);
	drm_crtc_vblank_off(crtc);
}

static void tegra_crtc_enable(struct drm_crtc *crtc)
{
{
	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
	struct tegra_dc_state *state = to_dc_state(crtc->state);
	struct tegra_dc_state *state = to_dc_state(crtc->state);
@@ -1259,15 +1264,7 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);


	tegra_dc_commit(dc);
	tegra_dc_commit(dc);
}

static void tegra_crtc_prepare(struct drm_crtc *crtc)
{
	drm_crtc_vblank_off(crtc);
}


static void tegra_crtc_commit(struct drm_crtc *crtc)
{
	drm_crtc_vblank_on(crtc);
	drm_crtc_vblank_on(crtc);
}
}


@@ -1304,10 +1301,7 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,


static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
	.disable = tegra_crtc_disable,
	.disable = tegra_crtc_disable,
	.mode_fixup = tegra_crtc_mode_fixup,
	.enable = tegra_crtc_enable,
	.mode_set_nofb = tegra_crtc_mode_set_nofb,
	.prepare = tegra_crtc_prepare,
	.commit = tegra_crtc_commit,
	.atomic_check = tegra_crtc_atomic_check,
	.atomic_check = tegra_crtc_atomic_check,
	.atomic_begin = tegra_crtc_atomic_begin,
	.atomic_begin = tegra_crtc_atomic_begin,
	.atomic_flush = tegra_crtc_atomic_flush,
	.atomic_flush = tegra_crtc_atomic_flush,
@@ -1325,6 +1319,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
		/*
		/*
		dev_dbg(dc->dev, "%s(): frame end\n", __func__);
		dev_dbg(dc->dev, "%s(): frame end\n", __func__);
		*/
		*/
		dc->stats.frames++;
	}
	}


	if (status & VBLANK_INT) {
	if (status & VBLANK_INT) {
@@ -1333,12 +1328,21 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
		*/
		*/
		drm_crtc_handle_vblank(&dc->base);
		drm_crtc_handle_vblank(&dc->base);
		tegra_dc_finish_page_flip(dc);
		tegra_dc_finish_page_flip(dc);
		dc->stats.vblank++;
	}
	}


	if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
	if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
		/*
		/*
		dev_dbg(dc->dev, "%s(): underflow\n", __func__);
		dev_dbg(dc->dev, "%s(): underflow\n", __func__);
		*/
		*/
		dc->stats.underflow++;
	}

	if (status & (WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT)) {
		/*
		dev_dbg(dc->dev, "%s(): overflow\n", __func__);
		*/
		dc->stats.overflow++;
	}
	}


	return IRQ_HANDLED;
	return IRQ_HANDLED;
@@ -1348,6 +1352,14 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
{
{
	struct drm_info_node *node = s->private;
	struct drm_info_node *node = s->private;
	struct tegra_dc *dc = node->info_ent->data;
	struct tegra_dc *dc = node->info_ent->data;
	int err = 0;

	drm_modeset_lock_crtc(&dc->base, NULL);

	if (!dc->base.state->active) {
		err = -EBUSY;
		goto unlock;
	}


#define DUMP_REG(name)						\
#define DUMP_REG(name)						\
	seq_printf(s, "%-40s %#05x %08x\n", #name, name,	\
	seq_printf(s, "%-40s %#05x %08x\n", #name, name,	\
@@ -1568,11 +1580,59 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)


#undef DUMP_REG
#undef DUMP_REG


unlock:
	drm_modeset_unlock_crtc(&dc->base);
	return err;
}

static int tegra_dc_show_crc(struct seq_file *s, void *data)
{
	struct drm_info_node *node = s->private;
	struct tegra_dc *dc = node->info_ent->data;
	int err = 0;
	u32 value;

	drm_modeset_lock_crtc(&dc->base, NULL);

	if (!dc->base.state->active) {
		err = -EBUSY;
		goto unlock;
	}

	value = DC_COM_CRC_CONTROL_ACTIVE_DATA | DC_COM_CRC_CONTROL_ENABLE;
	tegra_dc_writel(dc, value, DC_COM_CRC_CONTROL);
	tegra_dc_commit(dc);

	drm_crtc_wait_one_vblank(&dc->base);
	drm_crtc_wait_one_vblank(&dc->base);

	value = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM);
	seq_printf(s, "%08x\n", value);

	tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL);

unlock:
	drm_modeset_unlock_crtc(&dc->base);
	return err;
}

static int tegra_dc_show_stats(struct seq_file *s, void *data)
{
	struct drm_info_node *node = s->private;
	struct tegra_dc *dc = node->info_ent->data;

	seq_printf(s, "frames: %lu\n", dc->stats.frames);
	seq_printf(s, "vblank: %lu\n", dc->stats.vblank);
	seq_printf(s, "underflow: %lu\n", dc->stats.underflow);
	seq_printf(s, "overflow: %lu\n", dc->stats.overflow);

	return 0;
	return 0;
}
}


static struct drm_info_list debugfs_files[] = {
static struct drm_info_list debugfs_files[] = {
	{ "regs", tegra_dc_show_regs, 0, NULL },
	{ "regs", tegra_dc_show_regs, 0, NULL },
	{ "crc", tegra_dc_show_crc, 0, NULL },
	{ "stats", tegra_dc_show_stats, 0, NULL },
};
};


static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor)
static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor)
@@ -1718,7 +1778,8 @@ static int tegra_dc_init(struct host1x_client *client)
		tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
		tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
	}
	}


	value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
	value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
		WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
	tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
	tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);


	value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
	value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
@@ -1734,15 +1795,19 @@ static int tegra_dc_init(struct host1x_client *client)
		WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
		WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
	tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
	tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);


	value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
	value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
		WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
	tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
	tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);


	value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
	value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
		WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
	tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
	tegra_dc_writel(dc, value, DC_CMD_INT_MASK);


	if (dc->soc->supports_border_color)
	if (dc->soc->supports_border_color)
		tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
		tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);


	tegra_dc_stats_reset(&dc->stats);

	return 0;
	return 0;


cleanup:
cleanup:
@@ -1828,8 +1893,20 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
	.has_powergate = true,
	.has_powergate = true,
};
};


static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
	.supports_border_color = false,
	.supports_interlacing = true,
	.supports_cursor = true,
	.supports_block_linear = true,
	.pitch_align = 64,
	.has_powergate = true,
};

static const struct of_device_id tegra_dc_of_match[] = {
static const struct of_device_id tegra_dc_of_match[] = {
	{
	{
		.compatible = "nvidia,tegra210-dc",
		.data = &tegra210_dc_soc_info,
	}, {
		.compatible = "nvidia,tegra124-dc",
		.compatible = "nvidia,tegra124-dc",
		.data = &tegra124_dc_soc_info,
		.data = &tegra124_dc_soc_info,
	}, {
	}, {
@@ -1959,6 +2036,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
		return -ENXIO;
		return -ENXIO;
	}
	}


	dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
	if (!dc->syncpt)
		dev_warn(&pdev->dev, "failed to allocate syncpoint\n");

	INIT_LIST_HEAD(&dc->client.list);
	INIT_LIST_HEAD(&dc->client.list);
	dc->client.ops = &dc_client_ops;
	dc->client.ops = &dc_client_ops;
	dc->client.dev = &pdev->dev;
	dc->client.dev = &pdev->dev;
@@ -1976,10 +2057,6 @@ static int tegra_dc_probe(struct platform_device *pdev)
		return err;
		return err;
	}
	}


	dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
	if (!dc->syncpt)
		dev_warn(&pdev->dev, "failed to allocate syncpoint\n");

	platform_set_drvdata(pdev, dc);
	platform_set_drvdata(pdev, dc);


	return 0;
	return 0;
@@ -2018,7 +2095,6 @@ static int tegra_dc_remove(struct platform_device *pdev)
struct platform_driver tegra_dc_driver = {
struct platform_driver tegra_dc_driver = {
	.driver = {
	.driver = {
		.name = "tegra-dc",
		.name = "tegra-dc",
		.owner = THIS_MODULE,
		.of_match_table = tegra_dc_of_match,
		.of_match_table = tegra_dc_of_match,
	},
	},
	.probe = tegra_dc_probe,
	.probe = tegra_dc_probe,
+21 −3
Original line number Original line Diff line number Diff line
@@ -86,6 +86,11 @@
#define DC_CMD_REG_ACT_CONTROL			0x043
#define DC_CMD_REG_ACT_CONTROL			0x043


#define DC_COM_CRC_CONTROL			0x300
#define DC_COM_CRC_CONTROL			0x300
#define  DC_COM_CRC_CONTROL_ALWAYS (1 << 3)
#define  DC_COM_CRC_CONTROL_FULL_FRAME  (0 << 2)
#define  DC_COM_CRC_CONTROL_ACTIVE_DATA (1 << 2)
#define  DC_COM_CRC_CONTROL_WAIT (1 << 1)
#define  DC_COM_CRC_CONTROL_ENABLE (1 << 0)
#define DC_COM_CRC_CHECKSUM			0x301
#define DC_COM_CRC_CHECKSUM			0x301
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
@@ -114,15 +119,17 @@
#define DC_COM_CRC_CHECKSUM_LATCHED		0x329
#define DC_COM_CRC_CHECKSUM_LATCHED		0x329


#define DC_DISP_DISP_SIGNAL_OPTIONS0		0x400
#define DC_DISP_DISP_SIGNAL_OPTIONS0		0x400
#define H_PULSE_0_ENABLE (1 <<  8)
#define H_PULSE0_ENABLE (1 <<  8)
#define H_PULSE_1_ENABLE (1 << 10)
#define H_PULSE1_ENABLE (1 << 10)
#define H_PULSE_2_ENABLE (1 << 12)
#define H_PULSE2_ENABLE (1 << 12)


#define DC_DISP_DISP_SIGNAL_OPTIONS1		0x401
#define DC_DISP_DISP_SIGNAL_OPTIONS1		0x401


#define DC_DISP_DISP_WIN_OPTIONS		0x402
#define DC_DISP_DISP_WIN_OPTIONS		0x402
#define HDMI_ENABLE	(1 << 30)
#define HDMI_ENABLE	(1 << 30)
#define DSI_ENABLE	(1 << 29)
#define DSI_ENABLE	(1 << 29)
#define SOR1_TIMING_CYA	(1 << 27)
#define SOR1_ENABLE	(1 << 26)
#define SOR_ENABLE	(1 << 25)
#define SOR_ENABLE	(1 << 25)
#define CURSOR_ENABLE	(1 << 16)
#define CURSOR_ENABLE	(1 << 16)


@@ -242,9 +249,20 @@
#define BASE_COLOR_SIZE565     (6 << 0)
#define BASE_COLOR_SIZE565     (6 << 0)
#define BASE_COLOR_SIZE332     (7 << 0)
#define BASE_COLOR_SIZE332     (7 << 0)
#define BASE_COLOR_SIZE888     (8 << 0)
#define BASE_COLOR_SIZE888     (8 << 0)
#define DITHER_CONTROL_MASK    (3 << 8)
#define DITHER_CONTROL_DISABLE (0 << 8)
#define DITHER_CONTROL_DISABLE (0 << 8)
#define DITHER_CONTROL_ORDERED (2 << 8)
#define DITHER_CONTROL_ORDERED (2 << 8)
#define DITHER_CONTROL_ERRDIFF (3 << 8)
#define DITHER_CONTROL_ERRDIFF (3 << 8)
#define BASE_COLOR_SIZE_MASK   (0xf << 0)
#define BASE_COLOR_SIZE_666    (0 << 0)
#define BASE_COLOR_SIZE_111    (1 << 0)
#define BASE_COLOR_SIZE_222    (2 << 0)
#define BASE_COLOR_SIZE_333    (3 << 0)
#define BASE_COLOR_SIZE_444    (4 << 0)
#define BASE_COLOR_SIZE_555    (5 << 0)
#define BASE_COLOR_SIZE_565    (6 << 0)
#define BASE_COLOR_SIZE_332    (7 << 0)
#define BASE_COLOR_SIZE_888    (8 << 0)


#define DC_DISP_SHIFT_CLOCK_OPTIONS		0x431
#define DC_DISP_SHIFT_CLOCK_OPTIONS		0x431
#define  SC1_H_QUALIFIER_NONE	(1 << 16)
#define  SC1_H_QUALIFIER_NONE	(1 << 16)
+56 −7
Original line number Original line Diff line number Diff line
@@ -294,26 +294,41 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
	}
	}


	dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
	dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
	if (IS_ERR(dpaux->rst))
	if (IS_ERR(dpaux->rst)) {
		dev_err(&pdev->dev, "failed to get reset control: %ld\n",
			PTR_ERR(dpaux->rst));
		return PTR_ERR(dpaux->rst);
		return PTR_ERR(dpaux->rst);
	}


	dpaux->clk = devm_clk_get(&pdev->dev, NULL);
	dpaux->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(dpaux->clk))
	if (IS_ERR(dpaux->clk)) {
		dev_err(&pdev->dev, "failed to get module clock: %ld\n",
			PTR_ERR(dpaux->clk));
		return PTR_ERR(dpaux->clk);
		return PTR_ERR(dpaux->clk);
	}


	err = clk_prepare_enable(dpaux->clk);
	err = clk_prepare_enable(dpaux->clk);
	if (err < 0)
	if (err < 0) {
		dev_err(&pdev->dev, "failed to enable module clock: %d\n",
			err);
		return err;
		return err;
	}


	reset_control_deassert(dpaux->rst);
	reset_control_deassert(dpaux->rst);


	dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent");
	dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent");
	if (IS_ERR(dpaux->clk_parent))
	if (IS_ERR(dpaux->clk_parent)) {
		dev_err(&pdev->dev, "failed to get parent clock: %ld\n",
			PTR_ERR(dpaux->clk_parent));
		return PTR_ERR(dpaux->clk_parent);
		return PTR_ERR(dpaux->clk_parent);
	}


	err = clk_prepare_enable(dpaux->clk_parent);
	err = clk_prepare_enable(dpaux->clk_parent);
	if (err < 0)
	if (err < 0) {
		dev_err(&pdev->dev, "failed to enable parent clock: %d\n",
			err);
		return err;
		return err;
	}


	err = clk_set_rate(dpaux->clk_parent, 270000000);
	err = clk_set_rate(dpaux->clk_parent, 270000000);
	if (err < 0) {
	if (err < 0) {
@@ -323,8 +338,11 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
	}
	}


	dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd");
	dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd");
	if (IS_ERR(dpaux->vdd))
	if (IS_ERR(dpaux->vdd)) {
		dev_err(&pdev->dev, "failed to get VDD supply: %ld\n",
			PTR_ERR(dpaux->vdd));
		return PTR_ERR(dpaux->vdd);
		return PTR_ERR(dpaux->vdd);
	}


	err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0,
	err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0,
			       dev_name(dpaux->dev), dpaux);
			       dev_name(dpaux->dev), dpaux);
@@ -334,6 +352,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
		return err;
		return err;
	}
	}


	disable_irq(dpaux->irq);

	dpaux->aux.transfer = tegra_dpaux_transfer;
	dpaux->aux.transfer = tegra_dpaux_transfer;
	dpaux->aux.dev = &pdev->dev;
	dpaux->aux.dev = &pdev->dev;


@@ -341,6 +361,24 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
	if (err < 0)
	if (err < 0)
		return err;
		return err;


	/*
	 * Assume that by default the DPAUX/I2C pads will be used for HDMI,
	 * so power them up and configure them in I2C mode.
	 *
	 * The DPAUX code paths reconfigure the pads in AUX mode, but there
	 * is no possibility to perform the I2C mode configuration in the
	 * HDMI path.
	 */
	value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
	value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
	tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);

	value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_PADCTL);
	value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV |
		DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
		DPAUX_HYBRID_PADCTL_MODE_I2C;
	tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);

	/* enable and clear all interrupts */
	/* enable and clear all interrupts */
	value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT |
	value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT |
		DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT;
		DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT;
@@ -359,6 +397,12 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
static int tegra_dpaux_remove(struct platform_device *pdev)
static int tegra_dpaux_remove(struct platform_device *pdev)
{
{
	struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
	struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
	u32 value;

	/* make sure pads are powered down when not in use */
	value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
	value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
	tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);


	drm_dp_aux_unregister(&dpaux->aux);
	drm_dp_aux_unregister(&dpaux->aux);


@@ -376,6 +420,7 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
}
}


static const struct of_device_id tegra_dpaux_of_match[] = {
static const struct of_device_id tegra_dpaux_of_match[] = {
	{ .compatible = "nvidia,tegra210-dpaux", },
	{ .compatible = "nvidia,tegra124-dpaux", },
	{ .compatible = "nvidia,tegra124-dpaux", },
	{ },
	{ },
};
};
@@ -425,8 +470,10 @@ int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
		enum drm_connector_status status;
		enum drm_connector_status status;


		status = tegra_dpaux_detect(dpaux);
		status = tegra_dpaux_detect(dpaux);
		if (status == connector_status_connected)
		if (status == connector_status_connected) {
			enable_irq(dpaux->irq);
			return 0;
			return 0;
		}


		usleep_range(1000, 2000);
		usleep_range(1000, 2000);
	}
	}
@@ -439,6 +486,8 @@ int tegra_dpaux_detach(struct tegra_dpaux *dpaux)
	unsigned long timeout;
	unsigned long timeout;
	int err;
	int err;


	disable_irq(dpaux->irq);

	err = regulator_disable(dpaux->vdd);
	err = regulator_disable(dpaux->vdd);
	if (err < 0)
	if (err < 0)
		return err;
		return err;
+2 −0
Original line number Original line Diff line number Diff line
@@ -57,6 +57,8 @@
#define DPAUX_DP_AUX_CONFIG 0x45
#define DPAUX_DP_AUX_CONFIG 0x45


#define DPAUX_HYBRID_PADCTL 0x49
#define DPAUX_HYBRID_PADCTL 0x49
#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV (1 << 15)
#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV (1 << 14)
#define DPAUX_HYBRID_PADCTL_AUX_CMH(x) (((x) & 0x3) << 12)
#define DPAUX_HYBRID_PADCTL_AUX_CMH(x) (((x) & 0x3) << 12)
#define DPAUX_HYBRID_PADCTL_AUX_DRVZ(x) (((x) & 0x7) << 8)
#define DPAUX_HYBRID_PADCTL_AUX_DRVZ(x) (((x) & 0x7) << 8)
#define DPAUX_HYBRID_PADCTL_AUX_DRVI(x) (((x) & 0x3f) << 2)
#define DPAUX_HYBRID_PADCTL_AUX_DRVI(x) (((x) & 0x3f) << 2)
Loading