683 lines
22 KiB
Diff
683 lines
22 KiB
Diff
From 9db79f3a51c97e0cfcde1b25299e8db9ee3d64ab Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Wed, 14 Sep 2016 19:21:29 +0100
|
|
Subject: [PATCH 1/4] drm/vc4: Fall back to using an EDID probe in the absence
|
|
of a GPIO.
|
|
|
|
On Pi0/1/2, we use an external GPIO line for hotplug detection, since
|
|
the HDMI_HOTPLUG register isn't connected to anything. However, with
|
|
the Pi3 the HPD GPIO line has moved off to a GPIO expander that will
|
|
be tricky to get to (the firmware is constantly polling the expander
|
|
using i2c0, so we'll need to coordinate with it).
|
|
|
|
As a stop-gap, if we don't have a GPIO line, use an EDID probe to
|
|
detect connection. Fixes HDMI display on the pi3.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 3 +++
|
|
1 file changed, 3 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
index 4452f36..5adc0c7 100644
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
@@ -174,6 +174,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
|
return connector_status_disconnected;
|
|
}
|
|
|
|
+ if (drm_probe_ddc(vc4->hdmi->ddc))
|
|
+ return connector_status_connected;
|
|
+
|
|
if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
|
|
return connector_status_connected;
|
|
else
|
|
--
|
|
2.9.3
|
|
|
|
From 7b4c39f34fbbdfe0cd0e626686ee01ab96601598 Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Fri, 16 Sep 2016 10:59:45 +0100
|
|
Subject: [PATCH 2/4] drm/vc4: Enable limited range RGB output on HDMI with CEA
|
|
modes.
|
|
|
|
Fixes broken grayscale ramps on many HDMI monitors, where large areas
|
|
at the ends of the ramp would all appear as black or white.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 31 +++++++++++++++++++++++++++++--
|
|
drivers/gpu/drm/vc4/vc4_regs.h | 9 ++++++++-
|
|
2 files changed, 37 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
index 5adc0c7..5df4e74 100644
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
@@ -276,6 +276,7 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|
struct drm_display_mode *unadjusted_mode,
|
|
struct drm_display_mode *mode)
|
|
{
|
|
+ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
|
struct drm_device *dev = encoder->dev;
|
|
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
|
bool debug_dump_regs = false;
|
|
@@ -291,6 +292,7 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|
u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
|
|
VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
|
|
VC4_HDMI_VERTB_VBP));
|
|
+ u32 csc_ctl;
|
|
|
|
if (debug_dump_regs) {
|
|
DRM_INFO("HDMI regs before:\n");
|
|
@@ -329,9 +331,34 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|
(vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
|
|
(hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
|
|
|
|
+ csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
|
|
+ VC4_HD_CSC_CTL_ORDER);
|
|
+
|
|
+ if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
|
|
+ /* CEA VICs other than #1 requre limited range RGB
|
|
+ * output. Apply a colorspace conversion to squash
|
|
+ * 0-255 down to 16-235. The matrix here is:
|
|
+ *
|
|
+ * [ 0 0 0.8594 16]
|
|
+ * [ 0 0.8594 0 16]
|
|
+ * [ 0.8594 0 0 16]
|
|
+ * [ 0 0 0 1]
|
|
+ */
|
|
+ csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
|
|
+ csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
|
|
+ csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
|
|
+ VC4_HD_CSC_CTL_MODE);
|
|
+
|
|
+ HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000);
|
|
+ HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0);
|
|
+ HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000);
|
|
+ HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
|
|
+ HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
|
|
+ HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
|
|
+ }
|
|
+
|
|
/* The RGB order applies even when CSC is disabled. */
|
|
- HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
|
|
- VC4_HD_CSC_CTL_ORDER));
|
|
+ HD_WRITE(VC4_HD_CSC_CTL, csc_ctl);
|
|
|
|
HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
|
|
|
|
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
|
|
index 160942a..9ecd6ff 100644
|
|
--- a/drivers/gpu/drm/vc4/vc4_regs.h
|
|
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
|
|
@@ -528,10 +528,17 @@
|
|
# define VC4_HD_CSC_CTL_MODE_SHIFT 2
|
|
# define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB 0
|
|
# define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB 1
|
|
-# define VC4_HD_CSC_CTL_MODE_CUSTOM 2
|
|
+# define VC4_HD_CSC_CTL_MODE_CUSTOM 3
|
|
# define VC4_HD_CSC_CTL_RGB2YCC BIT(1)
|
|
# define VC4_HD_CSC_CTL_ENABLE BIT(0)
|
|
|
|
+#define VC4_HD_CSC_12_11 0x044
|
|
+#define VC4_HD_CSC_14_13 0x048
|
|
+#define VC4_HD_CSC_22_21 0x04c
|
|
+#define VC4_HD_CSC_24_23 0x050
|
|
+#define VC4_HD_CSC_32_31 0x054
|
|
+#define VC4_HD_CSC_34_33 0x058
|
|
+
|
|
#define VC4_HD_FRAME_COUNT 0x068
|
|
|
|
/* HVS display list information. */
|
|
--
|
|
2.9.3
|
|
|
|
From f379f5432e4b74e3d1d894ce2fefbe1b8a3c24fd Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Wed, 28 Sep 2016 19:20:44 -0700
|
|
Subject: [PATCH 4/4] drm/vc4: Increase timeout for HDMI_SCHEDULER_CONTROL
|
|
changes.
|
|
|
|
Fixes occasional debug spew at boot when connected directly through
|
|
HDMI, and probably confusing the HDMI state machine when we go trying
|
|
to poke registers for the enable sequence too soon.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
index 5df4e74..9a6883d 100644
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
@@ -399,7 +399,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
|
VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
|
|
|
ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
|
|
- VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1);
|
|
+ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
|
|
WARN_ONCE(ret, "Timeout waiting for "
|
|
"VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
|
|
} else {
|
|
@@ -411,7 +411,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
|
~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
|
|
|
ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
|
|
- VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1);
|
|
+ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
|
|
WARN_ONCE(ret, "Timeout waiting for "
|
|
"!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
|
|
}
|
|
--
|
|
2.9.3
|
|
|
|
From bd712d14886c37eb804036b2ac3036df79d33476 Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Thu, 29 Sep 2016 15:34:43 -0700
|
|
Subject: [PATCH] drm/vc4: Set up the AVI and SPD infoframes.
|
|
|
|
Fixes a purple bar on the left side of the screen with my Dell
|
|
2408WFP. It will also be required for supporting the double-clocked
|
|
video modes.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 136 +++++++++++++++++++++++++++++++++++++++--
|
|
drivers/gpu/drm/vc4/vc4_regs.h | 5 ++
|
|
2 files changed, 136 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
index 9a6883d..f722334 100644
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
@@ -62,6 +62,8 @@ struct vc4_hdmi {
|
|
struct vc4_hdmi_encoder {
|
|
struct vc4_encoder base;
|
|
bool hdmi_monitor;
|
|
+ bool limited_rgb_range;
|
|
+ bool rgb_range_selectable;
|
|
};
|
|
|
|
static inline struct vc4_hdmi_encoder *
|
|
@@ -205,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
|
|
return -ENODEV;
|
|
|
|
vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
|
+
|
|
+ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
|
|
+ vc4_encoder->rgb_range_selectable =
|
|
+ drm_rgb_quant_range_selectable(edid);
|
|
+ }
|
|
+
|
|
drm_mode_connector_update_edid_property(connector, edid);
|
|
ret = drm_add_edid_modes(connector, edid);
|
|
|
|
@@ -272,6 +280,117 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = {
|
|
.destroy = vc4_hdmi_encoder_destroy,
|
|
};
|
|
|
|
+static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
|
|
+ enum hdmi_infoframe_type type)
|
|
+{
|
|
+ struct drm_device *dev = encoder->dev;
|
|
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
|
+ u32 packet_id = type - 0x80;
|
|
+
|
|
+ HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
|
|
+ HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
|
|
+
|
|
+ return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
|
|
+ BIT(packet_id)), 100);
|
|
+}
|
|
+
|
|
+static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
|
+ union hdmi_infoframe *frame)
|
|
+{
|
|
+ struct drm_device *dev = encoder->dev;
|
|
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
|
+ u32 packet_id = frame->any.type - 0x80;
|
|
+ u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
|
|
+ uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
|
|
+ ssize_t len, i;
|
|
+ int ret;
|
|
+
|
|
+ WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
|
|
+ VC4_HDMI_RAM_PACKET_ENABLE),
|
|
+ "Packet RAM has to be on to store the packet.");
|
|
+
|
|
+ len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
|
|
+ if (len < 0)
|
|
+ return;
|
|
+
|
|
+ ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
|
|
+ if (ret) {
|
|
+ DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < len; i += 7) {
|
|
+ HDMI_WRITE(packet_reg,
|
|
+ buffer[i + 0] << 0 |
|
|
+ buffer[i + 1] << 8 |
|
|
+ buffer[i + 2] << 16);
|
|
+ packet_reg += 4;
|
|
+
|
|
+ HDMI_WRITE(packet_reg,
|
|
+ buffer[i + 3] << 0 |
|
|
+ buffer[i + 4] << 8 |
|
|
+ buffer[i + 5] << 16 |
|
|
+ buffer[i + 6] << 24);
|
|
+ packet_reg += 4;
|
|
+ }
|
|
+
|
|
+ HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
|
|
+ HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
|
|
+ ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
|
|
+ BIT(packet_id)), 100);
|
|
+ if (ret)
|
|
+ DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
|
|
+}
|
|
+
|
|
+static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
|
|
+{
|
|
+ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
|
+ struct drm_crtc *crtc = encoder->crtc;
|
|
+ const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
|
+ union hdmi_infoframe frame;
|
|
+ int ret;
|
|
+
|
|
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
|
|
+ if (ret < 0) {
|
|
+ DRM_ERROR("couldn't fill AVI infoframe\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (vc4_encoder->rgb_range_selectable) {
|
|
+ if (vc4_encoder->limited_rgb_range) {
|
|
+ frame.avi.quantization_range =
|
|
+ HDMI_QUANTIZATION_RANGE_LIMITED;
|
|
+ } else {
|
|
+ frame.avi.quantization_range =
|
|
+ HDMI_QUANTIZATION_RANGE_FULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ vc4_hdmi_write_infoframe(encoder, &frame);
|
|
+}
|
|
+
|
|
+static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
|
|
+{
|
|
+ union hdmi_infoframe frame;
|
|
+ int ret;
|
|
+
|
|
+ ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
|
|
+ if (ret < 0) {
|
|
+ DRM_ERROR("couldn't fill SPD infoframe\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ frame.spd.sdi = HDMI_SPD_SDI_PC;
|
|
+
|
|
+ vc4_hdmi_write_infoframe(encoder, &frame);
|
|
+}
|
|
+
|
|
+static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
|
|
+{
|
|
+ vc4_hdmi_set_avi_infoframe(encoder);
|
|
+ vc4_hdmi_set_spd_infoframe(encoder);
|
|
+}
|
|
+
|
|
static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|
struct drm_display_mode *unadjusted_mode,
|
|
struct drm_display_mode *mode)
|
|
@@ -336,8 +455,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|
|
|
if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
|
|
/* CEA VICs other than #1 requre limited range RGB
|
|
- * output. Apply a colorspace conversion to squash
|
|
- * 0-255 down to 16-235. The matrix here is:
|
|
+ * output unless overridden by an AVI infoframe.
|
|
+ * Apply a colorspace conversion to squash 0-255 down
|
|
+ * to 16-235. The matrix here is:
|
|
*
|
|
* [ 0 0 0.8594 16]
|
|
* [ 0 0.8594 0 16]
|
|
@@ -355,6 +475,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|
HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
|
|
HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
|
|
HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
|
|
+ vc4_encoder->limited_rgb_range = true;
|
|
+ } else {
|
|
+ vc4_encoder->limited_rgb_range = false;
|
|
}
|
|
|
|
/* The RGB order applies even when CSC is disabled. */
|
|
@@ -373,6 +496,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
|
|
struct drm_device *dev = encoder->dev;
|
|
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
|
|
|
+ HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
|
|
+
|
|
HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
|
|
HD_WRITE(VC4_HD_VID_CTL,
|
|
HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
|
|
@@ -425,9 +550,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
|
HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
|
|
VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
|
|
|
|
- /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set
|
|
- * up the infoframe.
|
|
- */
|
|
+ HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
|
|
+ VC4_HDMI_RAM_PACKET_ENABLE);
|
|
+
|
|
+ vc4_hdmi_set_infoframes(encoder);
|
|
|
|
drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
|
|
drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
|
|
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
|
|
index 9ecd6ff..a4b5370 100644
|
|
--- a/drivers/gpu/drm/vc4/vc4_regs.h
|
|
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
|
|
@@ -438,6 +438,8 @@
|
|
#define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0
|
|
# define VC4_HDMI_RAM_PACKET_ENABLE BIT(16)
|
|
|
|
+#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4
|
|
+
|
|
#define VC4_HDMI_HORZA 0x0c4
|
|
# define VC4_HDMI_HORZA_VPOS BIT(14)
|
|
# define VC4_HDMI_HORZA_HPOS BIT(13)
|
|
@@ -499,6 +501,9 @@
|
|
|
|
#define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
|
|
|
|
+#define VC4_HDMI_GCP_0 0x400
|
|
+#define VC4_HDMI_PACKET_STRIDE 0x24
|
|
+
|
|
#define VC4_HD_M_CTL 0x00c
|
|
# define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
|
|
# define VC4_HD_M_RAM_STANDBY (3 << 4)
|
|
--
|
|
2.9.3
|
|
|
|
From c4e634ce412d97f0e61223b2a5b3f8f9600cd4dc Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Fri, 30 Sep 2016 10:07:27 -0700
|
|
Subject: clk: bcm2835: Clamp the PLL's requested rate to the hardware limits.
|
|
|
|
Fixes setting low-resolution video modes on HDMI. Now the PLLH_PIX
|
|
divider adjusts itself until the PLLH is within bounds.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 11 ++++-------
|
|
1 file changed, 4 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index b68bf57..8c7763f 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -502,8 +502,12 @@ static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate,
|
|
static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|
unsigned long *parent_rate)
|
|
{
|
|
+ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
|
|
+ const struct bcm2835_pll_data *data = pll->data;
|
|
u32 ndiv, fdiv;
|
|
|
|
+ rate = clamp(rate, data->min_rate, data->max_rate);
|
|
+
|
|
bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv);
|
|
|
|
return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1);
|
|
@@ -608,13 +612,6 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
|
|
u32 ana[4];
|
|
int i;
|
|
|
|
- if (rate < data->min_rate || rate > data->max_rate) {
|
|
- dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n",
|
|
- clk_hw_get_name(hw), rate,
|
|
- data->min_rate, data->max_rate);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
if (rate > data->max_fb_rate) {
|
|
use_fb_prediv = true;
|
|
rate /= 2;
|
|
--
|
|
cgit v0.12
|
|
|
|
From e69fdcca836f0b81a2260b69429c8622a80ea891 Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Wed, 1 Jun 2016 12:05:33 -0700
|
|
Subject: clk: bcm2835: Mark the VPU clock as critical
|
|
|
|
The VPU clock is also the clock for our AXI bus, so we really can't
|
|
disable it. This might have happened during boot if, for example,
|
|
uart1 (aux_uart clock) probed and was then disabled before the other
|
|
consumers of the VPU clock had probed.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
Acked-by: Martin Sperl <kernel@martin.sperl.org>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 5 ++++-
|
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index 7a79708..d9db03c 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -443,6 +443,8 @@ struct bcm2835_clock_data {
|
|
/* Number of fractional bits in the divider */
|
|
u32 frac_bits;
|
|
|
|
+ u32 flags;
|
|
+
|
|
bool is_vpu_clock;
|
|
bool is_mash_clock;
|
|
};
|
|
@@ -1230,7 +1232,7 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
|
init.parent_names = parents;
|
|
init.num_parents = data->num_mux_parents;
|
|
init.name = data->name;
|
|
- init.flags = CLK_IGNORE_UNUSED;
|
|
+ init.flags = data->flags | CLK_IGNORE_UNUSED;
|
|
|
|
if (data->is_vpu_clock) {
|
|
init.ops = &bcm2835_vpu_clock_clk_ops;
|
|
@@ -1649,6 +1651,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
|
.div_reg = CM_VPUDIV,
|
|
.int_bits = 12,
|
|
.frac_bits = 8,
|
|
+ .flags = CLK_IS_CRITICAL,
|
|
.is_vpu_clock = true),
|
|
|
|
/* clocks with per parent mux */
|
|
--
|
|
cgit v0.12
|
|
|
|
From eddcbe8398fc7103fccd22aa6df6917caf0123bf Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Wed, 1 Jun 2016 12:05:34 -0700
|
|
Subject: clk: bcm2835: Mark GPIO clocks enabled at boot as critical
|
|
|
|
These divide off of PLLD_PER and are used for the ethernet and wifi
|
|
PHYs source PLLs. Neither of them is currently represented by a phy
|
|
device that would grab the clock for us.
|
|
|
|
This keeps other drivers from killing the networking PHYs when they
|
|
disable their own clocks and trigger PLLD_PER's refcount going to 0.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
Acked-by: Martin Sperl <kernel@martin.sperl.org>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 10 +++++++++-
|
|
1 file changed, 9 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index d9db03c..400615b 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -1239,6 +1239,12 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
|
} else {
|
|
init.ops = &bcm2835_clock_clk_ops;
|
|
init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
|
|
+
|
|
+ /* If the clock wasn't actually enabled at boot, it's not
|
|
+ * critical.
|
|
+ */
|
|
+ if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE))
|
|
+ init.flags &= ~CLK_IS_CRITICAL;
|
|
}
|
|
|
|
clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL);
|
|
@@ -1708,13 +1714,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
|
.div_reg = CM_GP1DIV,
|
|
.int_bits = 12,
|
|
.frac_bits = 12,
|
|
+ .flags = CLK_IS_CRITICAL,
|
|
.is_mash_clock = true),
|
|
[BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
|
|
.name = "gp2",
|
|
.ctl_reg = CM_GP2CTL,
|
|
.div_reg = CM_GP2DIV,
|
|
.int_bits = 12,
|
|
- .frac_bits = 12),
|
|
+ .frac_bits = 12,
|
|
+ .flags = CLK_IS_CRITICAL),
|
|
|
|
/* HDMI state machine */
|
|
[BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
|
|
--
|
|
cgit v0.12
|
|
|
|
From 9e400c5cc5c105e35216ac59a346f20cdd7613be Mon Sep 17 00:00:00 2001
|
|
From: Eric Anholt <eric@anholt.net>
|
|
Date: Wed, 1 Jun 2016 12:05:35 -0700
|
|
Subject: clk: bcm2835: Mark the CM SDRAM clock's parent as critical
|
|
|
|
While the SDRAM is being driven by its dedicated PLL most of the time,
|
|
there is a little loop running in the firmware that periodically turns
|
|
on the CM SDRAM clock (using its pre-initialized parent) and switches
|
|
SDRAM to using the CM clock to do PVT recalibration.
|
|
|
|
This avoids system hangs if we choose SDRAM's parent for some other
|
|
clock, then disable that clock.
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
Acked-by: Martin Sperl <kernel@martin.sperl.org>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 25 +++++++++++++++++++++++++
|
|
1 file changed, 25 insertions(+)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index 400615b..c6420b3 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -36,6 +36,7 @@
|
|
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/clkdev.h>
|
|
+#include <linux/clk.h>
|
|
#include <linux/clk/bcm2835.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/module.h>
|
|
@@ -1801,6 +1802,25 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
|
.ctl_reg = CM_PERIICTL),
|
|
};
|
|
|
|
+/*
|
|
+ * Permanently take a reference on the parent of the SDRAM clock.
|
|
+ *
|
|
+ * While the SDRAM is being driven by its dedicated PLL most of the
|
|
+ * time, there is a little loop running in the firmware that
|
|
+ * periodically switches the SDRAM to using our CM clock to do PVT
|
|
+ * recalibration, with the assumption that the previously configured
|
|
+ * SDRAM parent is still enabled and running.
|
|
+ */
|
|
+static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
|
|
+{
|
|
+ struct clk *parent = clk_get_parent(sdc);
|
|
+
|
|
+ if (IS_ERR(parent))
|
|
+ return PTR_ERR(parent);
|
|
+
|
|
+ return clk_prepare_enable(parent);
|
|
+}
|
|
+
|
|
static int bcm2835_clk_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
@@ -1810,6 +1830,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
|
const struct bcm2835_clk_desc *desc;
|
|
const size_t asize = ARRAY_SIZE(clk_desc_array);
|
|
size_t i;
|
|
+ int ret;
|
|
|
|
cprman = devm_kzalloc(dev,
|
|
sizeof(*cprman) + asize * sizeof(*clks),
|
|
@@ -1840,6 +1861,10 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
|
clks[i] = desc->clk_register(cprman, desc->data);
|
|
}
|
|
|
|
+ ret = bcm2835_mark_sdc_parent_critical(clks[BCM2835_CLOCK_SDRAM]);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
|
|
&cprman->onecell);
|
|
}
|
|
--
|
|
cgit v0.12
|
|
|
|
From 30772942cc1095c3129eecfa182e2c568e566b9d Mon Sep 17 00:00:00 2001
|
|
From: Dan Carpenter <dan.carpenter@oracle.com>
|
|
Date: Thu, 13 Oct 2016 11:54:31 +0300
|
|
Subject: [PATCH] drm/vc4: Fix a couple error codes in vc4_cl_lookup_bos()
|
|
|
|
If the allocation fails the current code returns success. If
|
|
copy_from_user() fails it returns the number of bytes remaining instead
|
|
of -EFAULT.
|
|
|
|
Fixes: d5b1a78a772f ("drm/vc4: Add support for drawing 3D frames.")
|
|
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_gem.c | 9 +++++----
|
|
1 file changed, 5 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
|
|
index ae1609e..4050540 100644
|
|
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
|
@@ -548,14 +548,15 @@ vc4_cl_lookup_bos(struct drm_device *dev,
|
|
|
|
handles = drm_malloc_ab(exec->bo_count, sizeof(uint32_t));
|
|
if (!handles) {
|
|
+ ret = -ENOMEM;
|
|
DRM_ERROR("Failed to allocate incoming GEM handles\n");
|
|
goto fail;
|
|
}
|
|
|
|
- ret = copy_from_user(handles,
|
|
- (void __user *)(uintptr_t)args->bo_handles,
|
|
- exec->bo_count * sizeof(uint32_t));
|
|
- if (ret) {
|
|
+ if (copy_from_user(handles,
|
|
+ (void __user *)(uintptr_t)args->bo_handles,
|
|
+ exec->bo_count * sizeof(uint32_t))) {
|
|
+ ret = -EFAULT;
|
|
DRM_ERROR("Failed to copy in GEM handles\n");
|
|
goto fail;
|
|
}
|
|
--
|
|
2.9.3
|
|
|