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

Commit 2614dc66 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'msm-next' of git://people.freedesktop.org/~robclark/linux into drm-next

* 'msm-next' of git://people.freedesktop.org/~robclark/linux:
  drm/omap: Don't dereference list head when the connectors list is empty
  drm/msm/mdp: add timeout for irq wait
  drm/msm: validate flags, etc
  drm/msm: use componentised device support
  drm/msm: add chip-id param
  drm/msm: crank down gpu when inactive
  drm/msm: spin helper
  drm/msm: add hang_debug module param
  drm/msm: hdmi audio support
parents d9961b22 06fb220b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ msm-y := \
	adreno/adreno_gpu.o \
	adreno/a3xx_gpu.o \
	hdmi/hdmi.o \
	hdmi/hdmi_audio.o \
	hdmi/hdmi_bridge.o \
	hdmi/hdmi_connector.o \
	hdmi/hdmi_i2c.o \
+79 −26
Original line number Diff line number Diff line
@@ -35,7 +35,11 @@
	 A3XX_INT0_CP_AHB_ERROR_HALT |     \
	 A3XX_INT0_UCHE_OOB_ACCESS)

static struct platform_device *a3xx_pdev;

static bool hang_debug = false;
MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
module_param_named(hang_debug, hang_debug, bool, 0600);
static void a3xx_dump(struct msm_gpu *gpu);

static void a3xx_me_init(struct msm_gpu *gpu)
{
@@ -291,6 +295,9 @@ static int a3xx_hw_init(struct msm_gpu *gpu)

static void a3xx_recover(struct msm_gpu *gpu)
{
	/* dump registers before resetting gpu, if enabled: */
	if (hang_debug)
		a3xx_dump(gpu);
	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);
	gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);
	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);
@@ -311,27 +318,18 @@ static void a3xx_destroy(struct msm_gpu *gpu)
		ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl);
#endif

	put_device(&a3xx_gpu->pdev->dev);
	kfree(a3xx_gpu);
}

static void a3xx_idle(struct msm_gpu *gpu)
{
	unsigned long t;

	/* wait for ringbuffer to drain: */
	adreno_idle(gpu);

	t = jiffies + ADRENO_IDLE_TIMEOUT;

	/* then wait for GPU to finish: */
	do {
		uint32_t rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS);
		if (!(rbbm_status & A3XX_RBBM_STATUS_GPU_BUSY))
			return;
	} while(time_before(jiffies, t));

	DRM_ERROR("timeout waiting for %s to idle!\n", gpu->name);
	if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) &
			A3XX_RBBM_STATUS_GPU_BUSY)))
		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);

	/* TODO maybe we need to reset GPU here to recover from hang? */
}
@@ -352,7 +350,6 @@ static irqreturn_t a3xx_irq(struct msm_gpu *gpu)
	return IRQ_HANDLED;
}

#ifdef CONFIG_DEBUG_FS
static const unsigned int a3xx_registers[] = {
	0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,
	0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,
@@ -392,11 +389,18 @@ static const unsigned int a3xx_registers[] = {
	0x303c, 0x303c, 0x305e, 0x305f,
};

#ifdef CONFIG_DEBUG_FS
static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
{
	struct drm_device *dev = gpu->dev;
	int i;

	adreno_show(gpu, m);

	mutex_lock(&dev->struct_mutex);

	gpu->funcs->pm_resume(gpu);

	seq_printf(m, "status:   %08x\n",
			gpu_read(gpu, REG_A3XX_RBBM_STATUS));

@@ -412,9 +416,36 @@ static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
			seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
		}
	}

	gpu->funcs->pm_suspend(gpu);

	mutex_unlock(&dev->struct_mutex);
}
#endif

/* would be nice to not have to duplicate the _show() stuff with printk(): */
static void a3xx_dump(struct msm_gpu *gpu)
{
	int i;

	adreno_dump(gpu);
	printk("status:   %08x\n",
			gpu_read(gpu, REG_A3XX_RBBM_STATUS));

	/* dump these out in a form that can be parsed by demsm: */
	printk("IO:region %s 00000000 00020000\n", gpu->name);
	for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) {
		uint32_t start = a3xx_registers[i];
		uint32_t end   = a3xx_registers[i+1];
		uint32_t addr;

		for (addr = start; addr <= end; addr++) {
			uint32_t val = gpu_read(gpu, addr);
			printk("IO:R %08x %08x\n", addr<<2, val);
		}
	}
}

static const struct adreno_gpu_funcs funcs = {
	.base = {
		.get_param = adreno_get_param,
@@ -439,7 +470,8 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
	struct a3xx_gpu *a3xx_gpu = NULL;
	struct adreno_gpu *adreno_gpu;
	struct msm_gpu *gpu;
	struct platform_device *pdev = a3xx_pdev;
	struct msm_drm_private *priv = dev->dev_private;
	struct platform_device *pdev = priv->gpu_pdev;
	struct adreno_platform_config *config;
	int ret;

@@ -460,7 +492,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
	adreno_gpu = &a3xx_gpu->base;
	gpu = &adreno_gpu->base;

	get_device(&pdev->dev);
	a3xx_gpu->pdev = pdev;

	gpu->fast_rate = config->fast_rate;
@@ -522,17 +553,24 @@ fail:
#  include <mach/kgsl.h>
#endif

static int a3xx_probe(struct platform_device *pdev)
static void set_gpu_pdev(struct drm_device *dev,
		struct platform_device *pdev)
{
	struct msm_drm_private *priv = dev->dev_private;
	priv->gpu_pdev = pdev;
}

static int a3xx_bind(struct device *dev, struct device *master, void *data)
{
	static struct adreno_platform_config config = {};
#ifdef CONFIG_OF
	struct device_node *child, *node = pdev->dev.of_node;
	struct device_node *child, *node = dev->of_node;
	u32 val;
	int ret;

	ret = of_property_read_u32(node, "qcom,chipid", &val);
	if (ret) {
		dev_err(&pdev->dev, "could not find chipid: %d\n", ret);
		dev_err(dev, "could not find chipid: %d\n", ret);
		return ret;
	}

@@ -548,7 +586,7 @@ static int a3xx_probe(struct platform_device *pdev)
			for_each_child_of_node(child, pwrlvl) {
				ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val);
				if (ret) {
					dev_err(&pdev->dev, "could not find gpu-freq: %d\n", ret);
					dev_err(dev, "could not find gpu-freq: %d\n", ret);
					return ret;
				}
				config.fast_rate = max(config.fast_rate, val);
@@ -558,12 +596,12 @@ static int a3xx_probe(struct platform_device *pdev)
	}

	if (!config.fast_rate) {
		dev_err(&pdev->dev, "could not find clk rates\n");
		dev_err(dev, "could not find clk rates\n");
		return -ENXIO;
	}

#else
	struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
	struct kgsl_device_platform_data *pdata = dev->platform_data;
	uint32_t version = socinfo_get_version();
	if (cpu_is_apq8064ab()) {
		config.fast_rate = 450000000;
@@ -609,14 +647,30 @@ static int a3xx_probe(struct platform_device *pdev)
	config.bus_scale_table = pdata->bus_scale_table;
#  endif
#endif
	pdev->dev.platform_data = &config;
	a3xx_pdev = pdev;
	dev->platform_data = &config;
	set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
	return 0;
}

static void a3xx_unbind(struct device *dev, struct device *master,
		void *data)
{
	set_gpu_pdev(dev_get_drvdata(master), NULL);
}

static const struct component_ops a3xx_ops = {
		.bind   = a3xx_bind,
		.unbind = a3xx_unbind,
};

static int a3xx_probe(struct platform_device *pdev)
{
	return component_add(&pdev->dev, &a3xx_ops);
}

static int a3xx_remove(struct platform_device *pdev)
{
	a3xx_pdev = NULL;
	component_del(&pdev->dev, &a3xx_ops);
	return 0;
}

@@ -624,7 +678,6 @@ static const struct of_device_id dt_match[] = {
	{ .compatible = "qcom,kgsl-3d0" },
	{}
};
MODULE_DEVICE_TABLE(of, dt_match);

static struct platform_driver a3xx_driver = {
	.probe = a3xx_probe,
+39 −26
Original line number Diff line number Diff line
@@ -73,6 +73,12 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
	case MSM_PARAM_GMEM_SIZE:
		*value = adreno_gpu->gmem;
		return 0;
	case MSM_PARAM_CHIP_ID:
		*value = adreno_gpu->rev.patchid |
				(adreno_gpu->rev.minor << 8) |
				(adreno_gpu->rev.major << 16) |
				(adreno_gpu->rev.core << 24);
		return 0;
	default:
		DBG("%s: invalid param: %u", gpu->name, param);
		return -EINVAL;
@@ -225,18 +231,10 @@ void adreno_flush(struct msm_gpu *gpu)
void adreno_idle(struct msm_gpu *gpu)
{
	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
	uint32_t rptr, wptr = get_wptr(gpu->rb);
	unsigned long t;

	t = jiffies + ADRENO_IDLE_TIMEOUT;

	/* then wait for CP to drain ringbuffer: */
	do {
		rptr = adreno_gpu->memptrs->rptr;
		if (rptr == wptr)
			return;
	} while(time_before(jiffies, t));
	uint32_t wptr = get_wptr(gpu->rb);

	/* wait for CP to drain ringbuffer: */
	if (spin_until(adreno_gpu->memptrs->rptr == wptr))
		DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);

	/* TODO maybe we need to reset GPU here to recover from hang? */
@@ -260,22 +258,37 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
}
#endif

void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
/* would be nice to not have to duplicate the _show() stuff with printk(): */
void adreno_dump(struct msm_gpu *gpu)
{
	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);

	printk("revision: %d (%d.%d.%d.%d)\n",
			adreno_gpu->info->revn, adreno_gpu->rev.core,
			adreno_gpu->rev.major, adreno_gpu->rev.minor,
			adreno_gpu->rev.patchid);

	printk("fence:    %d/%d\n", adreno_gpu->memptrs->fence,
			gpu->submitted_fence);
	printk("rptr:     %d\n", adreno_gpu->memptrs->rptr);
	printk("wptr:     %d\n", adreno_gpu->memptrs->wptr);
	printk("rb wptr:  %d\n", get_wptr(gpu->rb));

}

static uint32_t ring_freewords(struct msm_gpu *gpu)
{
	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
	uint32_t freedwords;
	unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
	do {
	uint32_t size = gpu->rb->size / 4;
	uint32_t wptr = get_wptr(gpu->rb);
	uint32_t rptr = adreno_gpu->memptrs->rptr;
		freedwords = (rptr + (size - 1) - wptr) % size;
	return (rptr + (size - 1) - wptr) % size;
}

		if (time_after(jiffies, t)) {
void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
{
	if (spin_until(ring_freewords(gpu) >= ndwords))
		DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
			break;
		}
	} while(freedwords < ndwords);
}

static const char *iommu_ports[] = {
+15 −1
Original line number Diff line number Diff line
@@ -76,7 +76,20 @@ struct adreno_platform_config {
#endif
};

#define ADRENO_IDLE_TIMEOUT (20 * 1000)
#define ADRENO_IDLE_TIMEOUT msecs_to_jiffies(1000)

#define spin_until(X) ({                                   \
	int __ret = -ETIMEDOUT;                            \
	unsigned long __t = jiffies + ADRENO_IDLE_TIMEOUT; \
	do {                                               \
		if (X) {                                   \
			__ret = 0;                         \
			break;                             \
		}                                          \
	} while (time_before(jiffies, __t));               \
	__ret;                                             \
})


static inline bool adreno_is_a3xx(struct adreno_gpu *gpu)
{
@@ -114,6 +127,7 @@ void adreno_idle(struct msm_gpu *gpu);
#ifdef CONFIG_DEBUG_FS
void adreno_show(struct msm_gpu *gpu, struct seq_file *m);
#endif
void adreno_dump(struct msm_gpu *gpu);
void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords);

int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
+36 −14
Original line number Diff line number Diff line
@@ -17,8 +17,6 @@

#include "hdmi.h"

static struct platform_device *hdmi_pdev;

void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
{
	uint32_t ctrl = 0;
@@ -67,7 +65,7 @@ void hdmi_destroy(struct kref *kref)
	if (hdmi->i2c)
		hdmi_i2c_destroy(hdmi->i2c);

	put_device(&hdmi->pdev->dev);
	platform_set_drvdata(hdmi->pdev, NULL);
}

/* initialize connector */
@@ -75,7 +73,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
{
	struct hdmi *hdmi = NULL;
	struct msm_drm_private *priv = dev->dev_private;
	struct platform_device *pdev = hdmi_pdev;
	struct platform_device *pdev = priv->hdmi_pdev;
	struct hdmi_platform_config *config;
	int i, ret;

@@ -95,13 +93,13 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)

	kref_init(&hdmi->refcount);

	get_device(&pdev->dev);

	hdmi->dev = dev;
	hdmi->pdev = pdev;
	hdmi->config = config;
	hdmi->encoder = encoder;

	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);

	/* not sure about which phy maps to which msm.. probably I miss some */
	if (config->phy_init)
		hdmi->phy = config->phy_init(hdmi);
@@ -228,6 +226,8 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
	priv->bridges[priv->num_bridges++]       = hdmi->bridge;
	priv->connectors[priv->num_connectors++] = hdmi->connector;

	platform_set_drvdata(pdev, hdmi);

	return hdmi;

fail:
@@ -249,17 +249,24 @@ fail:

#include <linux/of_gpio.h>

static int hdmi_dev_probe(struct platform_device *pdev)
static void set_hdmi_pdev(struct drm_device *dev,
		struct platform_device *pdev)
{
	struct msm_drm_private *priv = dev->dev_private;
	priv->hdmi_pdev = pdev;
}

static int hdmi_bind(struct device *dev, struct device *master, void *data)
{
	static struct hdmi_platform_config config = {};
#ifdef CONFIG_OF
	struct device_node *of_node = pdev->dev.of_node;
	struct device_node *of_node = dev->of_node;

	int get_gpio(const char *name)
	{
		int gpio = of_get_named_gpio(of_node, name, 0);
		if (gpio < 0) {
			dev_err(&pdev->dev, "failed to get gpio: %s (%d)\n",
			dev_err(dev, "failed to get gpio: %s (%d)\n",
					name, gpio);
			gpio = -1;
		}
@@ -305,7 +312,7 @@ static int hdmi_dev_probe(struct platform_device *pdev)
		config.ddc_data_gpio = 71;
		config.hpd_gpio      = 72;
		config.mux_en_gpio   = -1;
		config.mux_sel_gpio  = 13 + NR_GPIO_IRQS;
		config.mux_sel_gpio  = -1;
	} else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
		static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
		config.phy_init      = hdmi_phy_8960_init;
@@ -336,14 +343,30 @@ static int hdmi_dev_probe(struct platform_device *pdev)
		config.mux_sel_gpio  = -1;
	}
#endif
	pdev->dev.platform_data = &config;
	hdmi_pdev = pdev;
	dev->platform_data = &config;
	set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev));
	return 0;
}

static void hdmi_unbind(struct device *dev, struct device *master,
		void *data)
{
	set_hdmi_pdev(dev_get_drvdata(master), NULL);
}

static const struct component_ops hdmi_ops = {
		.bind   = hdmi_bind,
		.unbind = hdmi_unbind,
};

static int hdmi_dev_probe(struct platform_device *pdev)
{
	return component_add(&pdev->dev, &hdmi_ops);
}

static int hdmi_dev_remove(struct platform_device *pdev)
{
	hdmi_pdev = NULL;
	component_del(&pdev->dev, &hdmi_ops);
	return 0;
}

@@ -351,7 +374,6 @@ static const struct of_device_id dt_match[] = {
	{ .compatible = "qcom,hdmi-tx" },
	{}
};
MODULE_DEVICE_TABLE(of, dt_match);

static struct platform_driver hdmi_driver = {
	.probe = hdmi_dev_probe,
Loading