Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 14/16] drivers: acpi: iort: replace rid map type with type mask
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>

IORT tables provide data that allow the kernel to carry out
device ID mappings between endpoints and system components
(eg interrupt controllers, IOMMUs). When the mapping for a
given device ID is carried out, the translation mechanism
is done on a per-subsystem basis rather than a component
subtype (ie the IOMMU kernel layer will look for mappings
from a device to all IORT node types corresponding to IOMMU
components), therefore the corresponding mapping API should
work on a range (ie mask) of IORT node types corresponding
to a common set of components (eg IOMMUs) rather than a
specific node type.

Upgrade the IORT iort_node_map_rid() API to work with a
type mask instead of a single node type so that it can
be used for mappings that span multiple components types
(ie IOMMUs).

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/acpi/arm64/iort.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 4708806..62057c6 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -26,6 +26,9 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+#define IORT_TYPE_MASK(type)	(1 << (type))
+#define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
+
 struct iort_its_msi_chip {
 	struct list_head	list;
 	struct fwnode_handle	*fw_node;
@@ -317,7 +320,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
 
 static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
 						u32 rid_in, u32 *rid_out,
-						u8 type)
+						u8 type_mask)
 {
 	u32 rid = rid_in;
 
@@ -326,7 +329,7 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
 		struct acpi_iort_id_mapping *map;
 		int i;
 
-		if (node->type == type) {
+		if (IORT_TYPE_MASK(node->type) & type_mask) {
 			if (rid_out)
 				*rid_out = rid;
 			return node;
@@ -399,7 +402,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 	if (!node)
 		return req_id;
 
-	iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
+	iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE);
 	return dev_id;
 }
 
@@ -421,7 +424,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
 	if (!node)
 		return -ENXIO;
 
-	node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
+	node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE);
 	if (!node)
 		return -ENXIO;
 
-- 
2.10.0

^ permalink raw reply related

* [PATCH v8 15/16] drivers: acpi: iort: add single mapping function
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>

The current IORT id mapping API requires components to provide
an input requester ID (a Bus-Device-Function (BDF) identifier for
PCI devices) to translate an input identifier to an output
identifier through an IORT range mapping.

Named components do not have an identifiable source ID therefore
their respective input/output mapping can only be defined in
IORT tables through single mappings, that provide a translation
that does not require any input identifier.

Current IORT interface for requester id mappings (iort_node_map_rid())
is not suitable for components that do not provide a requester id,
so it cannot be used for IORT named components.

Add an interface to the IORT API to enable retrieval of id
by allowing an indexed walk of the single mappings array for
a given component, therefore completing the IORT mapping API.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/acpi/arm64/iort.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 62057c6..7d30605 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -318,6 +318,45 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
 	return 0;
 }
 
+static
+struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
+					u32 *id_out, u8 type_mask,
+					int index)
+{
+	struct acpi_iort_node *parent;
+	struct acpi_iort_id_mapping *map;
+
+	if (!node->mapping_offset || !node->mapping_count ||
+				     index >= node->mapping_count)
+		return NULL;
+
+	map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+			   node->mapping_offset);
+
+	/* Firmware bug! */
+	if (!map->output_reference) {
+		pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+		       node, node->type);
+		return NULL;
+	}
+
+	parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+			       map->output_reference);
+
+	if (!(IORT_TYPE_MASK(parent->type) & type_mask))
+		return NULL;
+
+	if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+			*id_out = map[index].output_base;
+			return parent;
+		}
+	}
+
+	return NULL;
+}
+
 static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
 						u32 rid_in, u32 *rid_out,
 						u8 type_mask)
-- 
2.10.0

^ permalink raw reply related

* [PATCH v8 16/16] drivers: acpi: iort: introduce iort_iommu_configure
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>

DT based systems have a generic kernel API to configure IOMMUs
for devices (ie of_iommu_configure()).

On ARM based ACPI systems, the of_iommu_configure() equivalent can
be implemented atop ACPI IORT kernel API, with the corresponding
functions to map device identifiers to IOMMUs and retrieve the
corresponding IOMMU operations necessary for DMA operations set-up.

By relying on the iommu_fwspec generic kernel infrastructure,
implement the IORT based IOMMU configuration for ARM ACPI systems
and hook it up in the ACPI kernel layer that implements DMA
configuration for a device.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> [ACPI core]
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/acpi/arm64/iort.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/scan.c       |  7 +++-
 include/linux/acpi_iort.h |  6 +++
 3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 7d30605..5fa585d 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -28,6 +28,8 @@
 
 #define IORT_TYPE_MASK(type)	(1 << (type))
 #define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
+#define IORT_IOMMU_TYPE		((1 << ACPI_IORT_NODE_SMMU) |	\
+				(1 << ACPI_IORT_NODE_SMMU_V3))
 
 struct iort_its_msi_chip {
 	struct list_head	list;
@@ -501,6 +503,102 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
 	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
 }
 
+static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
+{
+	u32 *rid = data;
+
+	*rid = alias;
+	return 0;
+}
+
+static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
+			       struct fwnode_handle *fwnode,
+			       const struct iommu_ops *ops)
+{
+	int ret = iommu_fwspec_init(dev, fwnode, ops);
+
+	if (!ret)
+		ret = iommu_fwspec_add_ids(dev, &streamid, 1);
+
+	return ret;
+}
+
+static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
+					struct acpi_iort_node *node,
+					u32 streamid)
+{
+	const struct iommu_ops *ops = NULL;
+	int ret = -ENODEV;
+	struct fwnode_handle *iort_fwnode;
+
+	if (node) {
+		iort_fwnode = iort_get_fwnode(node);
+		if (!iort_fwnode)
+			return NULL;
+
+		ops = iommu_get_instance(iort_fwnode);
+		if (!ops)
+			return NULL;
+
+		ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
+	}
+
+	return ret ? NULL : ops;
+}
+
+/**
+ * iort_iommu_configure - Set-up IOMMU configuration for a device.
+ *
+ * @dev: device to configure
+ *
+ * Returns: iommu_ops pointer on configuration success
+ *          NULL on configuration failure
+ */
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{
+	struct acpi_iort_node *node, *parent;
+	const struct iommu_ops *ops = NULL;
+	u32 streamid = 0;
+
+	if (dev_is_pci(dev)) {
+		struct pci_bus *bus = to_pci_dev(dev)->bus;
+		u32 rid;
+
+		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
+				       &rid);
+
+		node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+				      iort_match_node_callback, &bus->dev);
+		if (!node)
+			return NULL;
+
+		parent = iort_node_map_rid(node, rid, &streamid,
+					   IORT_IOMMU_TYPE);
+
+		ops = iort_iommu_xlate(dev, parent, streamid);
+
+	} else {
+		int i = 0;
+
+		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+				      iort_match_node_callback, dev);
+		if (!node)
+			return NULL;
+
+		parent = iort_node_get_id(node, &streamid,
+					  IORT_IOMMU_TYPE, i++);
+
+		while (parent) {
+			ops = iort_iommu_xlate(dev, parent, streamid);
+
+			parent = iort_node_get_id(node, &streamid,
+						  IORT_IOMMU_TYPE, i++);
+		}
+	}
+
+	return ops;
+}
+
 static void __init acpi_iort_register_irq(int hwirq, const char *name,
 					  int trigger,
 					  struct resource *res)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 694e0b6..e5f7004 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -7,6 +7,7 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/acpi.h>
+#include <linux/acpi_iort.h>
 #include <linux/signal.h>
 #include <linux/kthread.h>
 #include <linux/dmi.h>
@@ -1377,6 +1378,8 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
  */
 void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
 {
+	const struct iommu_ops *iommu;
+
 	/*
 	 * Set default coherent_dma_mask to 32 bit.  Drivers are expected to
 	 * setup the correct supported mask.
@@ -1391,11 +1394,13 @@ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
 	if (!dev->dma_mask)
 		dev->dma_mask = &dev->coherent_dma_mask;
 
+	iommu = iort_iommu_configure(dev);
+
 	/*
 	 * Assume dma valid range starts at 0 and covers the whole
 	 * coherent_dma_mask.
 	 */
-	arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+	arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
 			   attr == DEV_DMA_COHERENT);
 }
 EXPORT_SYMBOL_GPL(acpi_dma_configure);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 79ba1bb..dcb2b60 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -34,6 +34,8 @@ void acpi_iort_init(void);
 bool iort_node_match(u8 type);
 u32 iort_msi_map_rid(struct device *dev, u32 req_id);
 struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
+/* IOMMU interface */
+const struct iommu_ops *iort_iommu_configure(struct device *dev);
 #else
 static inline void acpi_iort_init(void) { }
 static inline bool iort_node_match(u8 type) { return false; }
@@ -42,6 +44,10 @@ static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 static inline struct irq_domain *iort_get_device_domain(struct device *dev,
 							u32 req_id)
 { return NULL; }
+/* IOMMU interface */
+static inline
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{ return NULL; }
 #endif
 
 #define IORT_ACPI_DECLARE(name, table_id, fn)		\
-- 
2.10.0

^ permalink raw reply related

* [PATCH] ARM: ux500: fix prcmu_is_cpu_in_wfi() calculation
From: Daniel Lezcano @ 2016-11-16 15:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116152047.3336967-1-arnd@arndb.de>

On Wed, Nov 16, 2016 at 04:20:37PM +0100, Arnd Bergmann wrote:
> This function clearly never worked and always returns true,
> as pointed out by gcc-7:
> 
> arch/arm/mach-ux500/pm.c: In function 'prcmu_is_cpu_in_wfi':
> arch/arm/mach-ux500/pm.c:137:212: error: ?: using integer constants in boolean context, the expression will always evaluate to 'true' [-Werror=int-in-bool-context]
> 
> With the added braces, the condition actually makes sense.
> 
> Fixes: 34fe6f107eab ("mfd : Check if the other db8500 core is in WFI")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  arch/arm/mach-ux500/pm.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c
> index 8538910db202..a970e7fcba9e 100644
> --- a/arch/arm/mach-ux500/pm.c
> +++ b/arch/arm/mach-ux500/pm.c
> @@ -134,8 +134,8 @@ bool prcmu_pending_irq(void)
>   */
>  bool prcmu_is_cpu_in_wfi(int cpu)
>  {
> -	return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
> -		     PRCM_ARM_WFI_STANDBY_WFI0;
> +	return readl(PRCM_ARM_WFI_STANDBY) &
> +		(cpu ? PRCM_ARM_WFI_STANDBY_WFI1 : PRCM_ARM_WFI_STANDBY_WFI0);
>  }
>  
>  /*

Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>

Very strange this board did not hang with this broken function.

It is used in a critical function for cpuidle. Is it possible to make a quick
test with this cpuidle test program [1] ?

Thanks!

  -- Daniel

[1] https://git.linaro.org/power/pm-qa.git/tree/cpuidle/cpuidle_killer.c

-- 

 <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply

* [PATCH net 1/3] net: phy: realtek: add eee advertisement disable options
From: Jerome Brunet @ 2016-11-16 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116150628.GI23231@lunn.ch>

On Wed, 2016-11-16 at 16:06 +0100, Andrew Lunn wrote:
> On Wed, Nov 16, 2016 at 03:51:30PM +0100, Jerome Brunet wrote:
> > 
> > On Wed, 2016-11-16 at 14:23 +0100, Andrew Lunn wrote:
> > > 
> > > > 
> > > > 
> > > > There two kind of PHYs supporting eee, the one advertising eee
> > > > by
> > > > default (like realtek) and the one not advertising it (like
> > > > micrel).
> > 
> > This is just the default register value.
> > 
> > > 
> > > 
> > > I don't know too much about EEE. So maybe a dumb question. Does
> > > the
> > > MAC need to be involved? Or is it just the PHY?
> > > 
> > > If the MAC needs to be involved, the PHY should not be
> > > advertising
> > > EEE
> > > unless the MAC asks for it by calling phy_init_eee(). If this is
> > > true,
> > > maybe we need to change the realtek driver, and others in that
> > > class.
> > 
> > As far I understand, the advertised capabilities are exchanged
> > during
> > the auto-negotiation.
> > 
> > At this stage, if the advertisement is disabled (regarless of the
> > actual support) on either side of the link, there will be no low
> > power
> > idle state on the Tx nor the Rx path.
> > 
> > If the advertisement is enabled on both side but we don't call
> > phy_init_eee, I suppose Tx won't enter LPI, but Rx could.
> 
> What i was trying to find out is, if the MAC needs to support EEE as
> well as the PHY, what happens when the MAC does not support EEE, but
> the PHYs do negotiate EEE? Does it break?

Interesting question. In a regular case, I suppose it should be fine.
As you would have LPI only on the Rx path this should be transparent to
the MAC. That's my understanding. Maybe people knowing EEE better than
me could confirm (or not) ? Peppe? Alexandre?

I just checked with the OdroidC2, I disabled eee support by forcing
"dma_cap.eee = 0" in?stmmac_get_hw_features. As expected, no tx_LPI
interrupts but plenty of rx_LPI interrupts.

What was not expected is test failing like before.
So in our case, having LPI on the Rx path is fine for receiving data,
but not for sending.

> 
> ????Andrew

^ permalink raw reply

* [PATCH 1/2] staging: vc04_services: remove duplicate mutex_lock_interruptible
From: Arnd Bergmann @ 2016-11-16 15:39 UTC (permalink / raw)
  To: linux-arm-kernel

The driver tries to redefine mutex_lock_interruptible as an open-coded
mutex_lock_killable, but that definition clashes with the normal
mutex_lock_interruptible definition when CONFIG_DEBUG_LOCK_ALLOC
is set:

staging/vc04_services/interface/vchiq_arm/vchiq_killable.h:67:0: error: "mutex_lock_interruptible" redefined [-Werror]
 #define mutex_lock_interruptible mutex_lock_interruptible_killable
include/linux/mutex.h:161:0: note: this is the location of the previous definition

This simply removes the private implementation and uses the
normal mutex_lock_killable directly.

We could do the same for the down_interruptible_killable here, but
it's better to just remove the semaphores entirely from the driver,
which also takes care of that.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 .../vc04_services/interface/vchiq_arm/vchiq_arm.c    |  2 +-
 .../interface/vchiq_arm/vchiq_connected.c            |  4 ++--
 .../vc04_services/interface/vchiq_arm/vchiq_core.c   | 20 ++++++++++----------
 .../interface/vchiq_arm/vchiq_kern_lib.c             |  4 ++--
 .../interface/vchiq_arm/vchiq_killable.h             | 14 --------------
 5 files changed, 15 insertions(+), 29 deletions(-)

diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index d0435a05ea35..0d987898b4f8 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -554,7 +554,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 			ret = -EINVAL;
 			break;
 		}
-		rc = mutex_lock_interruptible(&instance->state->mutex);
+		rc = mutex_lock_killable(&instance->state->mutex);
 		if (rc != 0) {
 			vchiq_log_error(vchiq_arm_log_level,
 				"vchiq: connect: could not lock mutex for "
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
index 5efc62ffb2f5..7ea29665bd0c 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
@@ -72,7 +72,7 @@ void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
 {
 	connected_init();
 
-	if (mutex_lock_interruptible(&g_connected_mutex) != 0)
+	if (mutex_lock_killable(&g_connected_mutex) != 0)
 		return;
 
 	if (g_connected)
@@ -107,7 +107,7 @@ void vchiq_call_connected_callbacks(void)
 
 	connected_init();
 
-	if (mutex_lock_interruptible(&g_connected_mutex) != 0)
+	if (mutex_lock_killable(&g_connected_mutex) != 0)
 		return;
 
 	for (i = 0; i <  g_num_deferred_callbacks; i++)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 7440db2ce40b..028e90bc1cdc 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -794,7 +794,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
 	WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
 
 	if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
-		(mutex_lock_interruptible(&state->slot_mutex) != 0))
+		(mutex_lock_killable(&state->slot_mutex) != 0))
 		return VCHIQ_RETRY;
 
 	if (type == VCHIQ_MSG_DATA) {
@@ -863,7 +863,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
 				return VCHIQ_RETRY;
 			if (service->closing)
 				return VCHIQ_ERROR;
-			if (mutex_lock_interruptible(&state->slot_mutex) != 0)
+			if (mutex_lock_killable(&state->slot_mutex) != 0)
 				return VCHIQ_RETRY;
 			if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
 				/* The service has been closed */
@@ -1033,7 +1033,7 @@ queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
 	local = state->local;
 
 	if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
-		(mutex_lock_interruptible(&state->sync_mutex) != 0))
+		(mutex_lock_killable(&state->sync_mutex) != 0))
 		return VCHIQ_RETRY;
 
 	remote_event_wait(state, &local->sync_release);
@@ -1365,7 +1365,7 @@ resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
 		WARN_ON(!((int)(queue->local_insert - queue->process) > 0));
 		WARN_ON(!((int)(queue->remote_insert - queue->process) > 0));
 
-		rc = mutex_lock_interruptible(&state->bulk_transfer_mutex);
+		rc = mutex_lock_killable(&state->bulk_transfer_mutex);
 		if (rc != 0)
 			break;
 
@@ -1839,7 +1839,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
 				int resolved = 0;
 
 				DEBUG_TRACE(PARSE_LINE);
-				if (mutex_lock_interruptible(
+				if (mutex_lock_killable(
 					&service->bulk_mutex) != 0) {
 					DEBUG_TRACE(PARSE_LINE);
 					goto bail_not_ready;
@@ -1903,7 +1903,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
 					&service->bulk_rx : &service->bulk_tx;
 
 				DEBUG_TRACE(PARSE_LINE);
-				if (mutex_lock_interruptible(
+				if (mutex_lock_killable(
 					&service->bulk_mutex) != 0) {
 					DEBUG_TRACE(PARSE_LINE);
 					goto bail_not_ready;
@@ -2780,7 +2780,7 @@ do_abort_bulks(VCHIQ_SERVICE_T *service)
 	VCHIQ_STATUS_T status;
 
 	/* Abort any outstanding bulk transfers */
-	if (mutex_lock_interruptible(&service->bulk_mutex) != 0)
+	if (mutex_lock_killable(&service->bulk_mutex) != 0)
 		return 0;
 	abort_outstanding_bulks(service, &service->bulk_tx);
 	abort_outstanding_bulks(service, &service->bulk_rx);
@@ -3300,7 +3300,7 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
 	queue = (dir == VCHIQ_BULK_TRANSMIT) ?
 		&service->bulk_tx : &service->bulk_rx;
 
-	if (mutex_lock_interruptible(&service->bulk_mutex) != 0) {
+	if (mutex_lock_killable(&service->bulk_mutex) != 0) {
 		status = VCHIQ_RETRY;
 		goto error_exit;
 	}
@@ -3314,7 +3314,7 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
 				status = VCHIQ_RETRY;
 				goto error_exit;
 			}
-			if (mutex_lock_interruptible(&service->bulk_mutex)
+			if (mutex_lock_killable(&service->bulk_mutex)
 				!= 0) {
 				status = VCHIQ_RETRY;
 				goto error_exit;
@@ -3344,7 +3344,7 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
 
 	/* The slot mutex must be held when the service is being closed, so
 	   claim it here to ensure that isn't happening */
-	if (mutex_lock_interruptible(&state->slot_mutex) != 0) {
+	if (mutex_lock_killable(&state->slot_mutex) != 0) {
 		status = VCHIQ_RETRY;
 		goto cancel_bulk_error_exit;
 	}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
index 14bd2857e462..e93922a87263 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
@@ -134,7 +134,7 @@ VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
 	vchiq_log_trace(vchiq_core_log_level,
 		"%s(%p) called", __func__, instance);
 
-	if (mutex_lock_interruptible(&state->mutex) != 0)
+	if (mutex_lock_killable(&state->mutex) != 0)
 		return VCHIQ_RETRY;
 
 	/* Remove all services */
@@ -191,7 +191,7 @@ VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
 	vchiq_log_trace(vchiq_core_log_level,
 		"%s(%p) called", __func__, instance);
 
-	if (mutex_lock_interruptible(&state->mutex) != 0) {
+	if (mutex_lock_killable(&state->mutex) != 0) {
 		vchiq_log_trace(vchiq_core_log_level,
 			"%s: call to mutex_lock failed", __func__);
 		status = VCHIQ_RETRY;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h
index 335446e05476..778063ba312a 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h
@@ -52,18 +52,4 @@ static inline int __must_check down_interruptible_killable(struct semaphore *sem
 }
 #define down_interruptible down_interruptible_killable
 
-
-static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock)
-{
-	/* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
-	int ret;
-	sigset_t blocked, oldset;
-	siginitsetinv(&blocked, SHUTDOWN_SIGS);
-	sigprocmask(SIG_SETMASK, &blocked, &oldset);
-	ret = mutex_lock_interruptible(lock);
-	sigprocmask(SIG_SETMASK, &oldset, NULL);
-	return ret;
-}
-#define mutex_lock_interruptible mutex_lock_interruptible_killable
-
 #endif
-- 
2.9.0

^ permalink raw reply related

* [PATCH 2/2] staging: vc04_services: clarify firmware dependency
From: Arnd Bergmann @ 2016-11-16 15:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116154139.3703209-1-arnd@arndb.de>

The raspberrypi-firmware driver may be built as a loadable module,
which causes a link-time failure if the vc04_services driver is
built-in during compile-testing:

drivers/staging/vc04_services/vchiq.o: In function `vchiq_probe':
vchiq_connected.c:(.text.vchiq_probe+0x2c): undefined reference to `rpi_firmware_get'
drivers/staging/vc04_services/vchiq.o: In function `vchiq_platform_init':
vchiq_connected.c:(.text.vchiq_platform_init+0x1f0): undefined reference to `rpi_firmware_property'

This extends the dependency list to ensure the firmware is either
reachable, or completely disabled in case of compile-testing.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/staging/vc04_services/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/vc04_services/Kconfig b/drivers/staging/vc04_services/Kconfig
index 660dcedc2820..061ffd261086 100644
--- a/drivers/staging/vc04_services/Kconfig
+++ b/drivers/staging/vc04_services/Kconfig
@@ -1,6 +1,6 @@
 config BCM2835_VCHIQ
 	tristate "Videocore VCHIQ"
-	depends on RASPBERRYPI_FIRMWARE || COMPILE_TEST
+	depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
 	default y
 	help
 		Kernel to VideoCore communication interface for the
-- 
2.9.0

^ permalink raw reply related

* [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
From: Sean Paul @ 2016-11-16 15:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-2-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add DRM master driver for Hisilicon Hibmc SoC which used for
> Out-of-band management. Blow is the general hardware connection,
> both the Hibmc and the host CPU are on the same mother board.
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---

In the future, please keep track of the differences between patch
versions. I noticed you have a short changelog in the cover letter,
but it really helps to add one per-patch as well, it makes reviewing
much simpler.

Reviewed-by: Sean Paul <seanpaul@chromium.org>


>  drivers/gpu/drm/hisilicon/Kconfig                |   1 +
>  drivers/gpu/drm/hisilicon/Makefile               |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig          |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile         |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  | 308 +++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  41 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
>  7 files changed, 560 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>
> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
> index 558c61b..2fd2724 100644
> --- a/drivers/gpu/drm/hisilicon/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/Kconfig
> @@ -2,4 +2,5 @@
>  # hisilicon drm device configuration.
>  # Please keep this list sorted alphabetically
>
> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
>  source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
> index e3f6d49..c8155bf 100644
> --- a/drivers/gpu/drm/hisilicon/Makefile
> +++ b/drivers/gpu/drm/hisilicon/Makefile
> @@ -2,4 +2,5 @@
>  # Makefile for hisilicon drm drivers.
>  # Please keep this list sorted alphabetically
>
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
>  obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> new file mode 100644
> index 0000000..380622a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -0,0 +1,9 @@
> +config DRM_HISI_HIBMC
> +       tristate "DRM Support for Hisilicon Hibmc"
> +       depends on DRM && PCI
> +       select DRM_KMS_HELPER
> +       select DRM_TTM
> +
> +       help
> +         Choose this option if you have a Hisilicon Hibmc soc chipset.
> +         If M is selected the module will be called hibmc-drm.
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> new file mode 100644
> index 0000000..47962a0
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -0,0 +1,4 @@
> +ccflags-y := -Iinclude/drm
> +hibmc-drm-y := hibmc_drm_drv.o
> +
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> new file mode 100644
> index 0000000..6d20580
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -0,0 +1,308 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/console.h>
> +#include <linux/module.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static const struct file_operations hibmc_fops = {
> +       .owner          = THIS_MODULE,
> +       .open           = drm_open,
> +       .release        = drm_release,
> +       .unlocked_ioctl = drm_ioctl,
> +       .compat_ioctl   = drm_compat_ioctl,
> +       .poll           = drm_poll,
> +       .read           = drm_read,
> +       .llseek         = no_llseek,
> +};
> +
> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> +       return 0;
> +}
> +
> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> +}
> +
> +static struct drm_driver hibmc_driver = {
> +       .fops                   = &hibmc_fops,
> +       .name                   = "hibmc",
> +       .date                   = "20160828",
> +       .desc                   = "hibmc drm driver",
> +       .major                  = 1,
> +       .minor                  = 0,
> +       .get_vblank_counter     = drm_vblank_no_hw_counter,
> +       .enable_vblank          = hibmc_enable_vblank,
> +       .disable_vblank         = hibmc_disable_vblank,
> +};
> +
> +static int hibmc_pm_suspend(struct device *dev)
> +{
> +       return 0;
> +}
> +
> +static int hibmc_pm_resume(struct device *dev)
> +{
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops hibmc_pm_ops = {
> +       SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
> +                               hibmc_pm_resume)
> +};
> +
> +/*
> + * It can operate in one of three modes: 0, 1 or Sleep.
> + */
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> +                         unsigned int power_mode)
> +{
> +       unsigned int control_value = 0;
> +       void __iomem   *mmio = priv->mmio;
> +       unsigned int input = 1;
> +
> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               return;
> +
> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               input = 0;
> +
> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
> +       control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
> +                          HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
> +}
> +
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
> +{
> +       unsigned int gate_reg;
> +       unsigned int mode;
> +       void __iomem   *mmio = priv->mmio;
> +
> +       /* Get current power mode. */
> +       mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
> +
> +       switch (mode) {
> +       case HIBMC_PW_MODE_CTL_MODE_MODE0:
> +               gate_reg = HIBMC_MODE0_GATE;
> +               break;
> +
> +       case HIBMC_PW_MODE_CTL_MODE_MODE1:
> +               gate_reg = HIBMC_MODE1_GATE;
> +               break;
> +
> +       default:
> +               gate_reg = HIBMC_MODE0_GATE;
> +               break;
> +       }
> +       writel(gate, mmio + gate_reg);
> +}
> +
> +static void hibmc_hw_config(struct hibmc_drm_private *priv)
> +{
> +       unsigned int reg;
> +
> +       /* On hardware reset, power mode 0 is default. */
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +
> +       hibmc_set_current_gate(priv, reg);
> +
> +       /*
> +        * Reset the memory controller. If the memory controller
> +        * is not reset in chip,the system might hang when sw accesses
> +        * the memory.The memory should be resetted after
> +        * changing the MXCLK.
> +        */
> +       reg = readl(priv->mmio + HIBMC_MISC_CTRL);
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
> +
> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +}
> +
> +static int hibmc_hw_map(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct pci_dev *pdev = dev->pdev;
> +       resource_size_t addr, size, ioaddr, iosize;
> +
> +       ioaddr = pci_resource_start(pdev, 1);
> +       iosize = pci_resource_len(pdev, 1);
> +       priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
> +       if (!priv->mmio) {
> +               DRM_ERROR("Cannot map mmio region\n");
> +               return -ENOMEM;
> +       }
> +
> +       addr = pci_resource_start(pdev, 0);
> +       size = pci_resource_len(pdev, 0);
> +       priv->fb_map = devm_ioremap(dev->dev, addr, size);
> +       if (!priv->fb_map) {
> +               DRM_ERROR("Cannot map framebuffer\n");
> +               return -ENOMEM;
> +       }
> +       priv->fb_base = addr;
> +       priv->fb_size = size;
> +
> +       return 0;
> +}
> +
> +static int hibmc_hw_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +
> +       ret = hibmc_hw_map(priv);
> +       if (ret)
> +               return ret;
> +
> +       hibmc_hw_config(priv);
> +
> +       return 0;
> +}
> +
> +static int hibmc_unload(struct drm_device *dev)
> +{
> +       return 0;
> +}
> +
> +static int hibmc_load(struct drm_device *dev)
> +{
> +       struct hibmc_drm_private *priv;
> +       int ret;
> +
> +       priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv) {
> +               DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
> +               return -ENOMEM;
> +       }
> +       dev->dev_private = priv;
> +       priv->dev = dev;
> +
> +       ret = hibmc_hw_init(priv);
> +       if (ret)
> +               goto err;
> +
> +       return 0;
> +
> +err:
> +       hibmc_unload(dev);
> +       DRM_ERROR("failed to initialize drm driver: %d\n", ret);
> +       return ret;
> +}
> +
> +static int hibmc_pci_probe(struct pci_dev *pdev,
> +                          const struct pci_device_id *ent)
> +{
> +       struct drm_device *dev;
> +       int ret;
> +
> +       dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
> +       if (!dev) {
> +               DRM_ERROR("failed to allocate drm_device\n");
> +               return -ENOMEM;
> +       }
> +
> +       dev->pdev = pdev;
> +       pci_set_drvdata(pdev, dev);
> +
> +       ret = pci_enable_device(pdev);
> +       if (ret) {
> +               DRM_ERROR("failed to enable pci device: %d\n", ret);
> +               goto err_free;
> +       }
> +
> +       ret = hibmc_load(dev);
> +       if (ret) {
> +               DRM_ERROR("failed to load hibmc: %d\n", ret);
> +               goto err_disable;
> +       }
> +
> +       ret = drm_dev_register(dev, 0);
> +       if (ret) {
> +               DRM_ERROR("failed to register drv for userspace access: %d\n",
> +                         ret);
> +               goto err_unload;
> +       }
> +       return 0;
> +
> +err_unload:
> +       hibmc_unload(dev);
> +err_disable:
> +       pci_disable_device(pdev);
> +err_free:
> +       drm_dev_unref(dev);
> +
> +       return ret;
> +}
> +
> +static void hibmc_pci_remove(struct pci_dev *pdev)
> +{
> +       struct drm_device *dev = pci_get_drvdata(pdev);
> +
> +       drm_dev_unregister(dev);
> +       hibmc_unload(dev);
> +       drm_dev_unref(dev);
> +}
> +
> +static struct pci_device_id hibmc_pci_table[] = {
> +       {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
> +       {0,}
> +};
> +
> +static struct pci_driver hibmc_pci_driver = {
> +       .name =         "hibmc-drm",
> +       .id_table =     hibmc_pci_table,
> +       .probe =        hibmc_pci_probe,
> +       .remove =       hibmc_pci_remove,
> +       .driver.pm =    &hibmc_pm_ops,
> +};
> +
> +static int __init hibmc_init(void)
> +{
> +       return pci_register_driver(&hibmc_pci_driver);
> +}
> +
> +static void __exit hibmc_exit(void)
> +{
> +       return pci_unregister_driver(&hibmc_pci_driver);
> +}
> +
> +module_init(hibmc_init);
> +module_exit(hibmc_exit);
> +
> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
> +MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> new file mode 100644
> index 0000000..840cd5a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -0,0 +1,41 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_DRV_H
> +#define HIBMC_DRM_DRV_H
> +
> +#include <drm/drmP.h>
> +
> +struct hibmc_drm_private {
> +       /* hw */
> +       void __iomem   *mmio;
> +       void __iomem   *fb_map;
> +       unsigned long  fb_base;
> +       unsigned long  fb_size;
> +
> +       /* drm */
> +       struct drm_device  *dev;
> +
> +};
> +
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> +                         unsigned int power_mode);
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv,
> +                           unsigned int gate);
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> new file mode 100644
> index 0000000..f7035bf
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> @@ -0,0 +1,196 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_HW_H
> +#define HIBMC_DRM_HW_H
> +
> +/* register definition */
> +#define HIBMC_MISC_CTRL                                0x4
> +
> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
> +
> +#define HIBMC_CURRENT_GATE                     0x000040
> +#define HIBMC_CURR_GATE_DISPLAY(x)             ((x) << 2)
> +#define HIBMC_CURR_GATE_DISPLAY_MASK           0x4
> +
> +#define HIBMC_CURR_GATE_LOCALMEM(x)            ((x) << 1)
> +#define HIBMC_CURR_GATE_LOCALMEM_MASK          0x2
> +
> +#define HIBMC_MODE0_GATE                       0x000044
> +#define HIBMC_MODE1_GATE                       0x000048
> +#define HIBMC_POWER_MODE_CTRL                  0x00004C
> +
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)         ((x) << 3)
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK       0x8
> +
> +#define HIBMC_PW_MODE_CTL_MODE(x)              ((x) << 0)
> +#define HIBMC_PW_MODE_CTL_MODE_MASK            0x03
> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT           0
> +
> +#define HIBMC_PW_MODE_CTL_MODE_MODE0           0
> +#define HIBMC_PW_MODE_CTL_MODE_MODE1           1
> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP           2
> +
> +#define HIBMC_PANEL_PLL_CTRL                   0x00005C
> +#define HIBMC_CRT_PLL_CTRL                     0x000060
> +
> +#define HIBMC_PLL_CTRL_BYPASS(x)               ((x) << 18)
> +#define HIBMC_PLL_CTRL_BYPASS_MASK             0x40000
> +
> +#define HIBMC_PLL_CTRL_POWER(x)                        ((x) << 17)
> +#define HIBMC_PLL_CTRL_POWER_MASK              0x20000
> +
> +#define HIBMC_PLL_CTRL_INPUT(x)                        ((x) << 16)
> +#define HIBMC_PLL_CTRL_INPUT_MASK              0x10000
> +
> +#define HIBMC_PLL_CTRL_POD(x)                  ((x) << 14)
> +#define HIBMC_PLL_CTRL_POD_MASK                        0xC000
> +
> +#define HIBMC_PLL_CTRL_OD(x)                   ((x) << 12)
> +#define HIBMC_PLL_CTRL_OD_MASK                 0x3000
> +
> +#define HIBMC_PLL_CTRL_N(x)                    ((x) << 8)
> +#define HIBMC_PLL_CTRL_N_MASK                  0xF00
> +
> +#define HIBMC_PLL_CTRL_M(x)                    ((x) << 0)
> +#define HIBMC_PLL_CTRL_M_MASK                  0xFF
> +
> +#define HIBMC_CRT_DISP_CTL                     0x80200
> +
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)                ((x) << 25)
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK      0x2000000
> +
> +#define HIBMC_CRTSELECT_CRT                    1
> +
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
> +
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)      ((x) << 13)
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK    0x2000
> +
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)      ((x) << 12)
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK    0x1000
> +
> +#define HIBMC_CRT_DISP_CTL_TIMING(x)           ((x) << 8)
> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK         0x100
> +
> +#define HIBMC_CRT_DISP_CTL_PLANE(x)            ((x) << 2)
> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK          4
> +
> +#define HIBMC_CRT_DISP_CTL_FORMAT(x)           ((x) << 0)
> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK         0x03
> +
> +#define HIBMC_CRT_FB_ADDRESS                   0x080204
> +
> +#define HIBMC_CRT_FB_WIDTH                     0x080208
> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x)            ((x) << 16)
> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK          0x3FFF0000
> +#define HIBMC_CRT_FB_WIDTH_OFFS(x)             ((x) << 0)
> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK           0x3FFF
> +
> +#define HIBMC_CRT_HORZ_TOTAL                   0x08020C
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)          ((x) << 16)
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK                0xFFF0000
> +
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x)       ((x) << 0)
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK     0xFFF
> +
> +#define HIBMC_CRT_HORZ_SYNC                    0x080210
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)           ((x) << 16)
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK         0xFF0000
> +
> +#define HIBMC_CRT_HORZ_SYNC_START(x)           ((x) << 0)
> +#define HIBMC_CRT_HORZ_SYNC_START_MASK         0xFFF
> +
> +#define HIBMC_CRT_VERT_TOTAL                   0x080214
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)          ((x) << 16)
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK                0x7FFF0000
> +
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END(x)       ((x) << 0)
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK     0x7FF
> +
> +#define HIBMC_CRT_VERT_SYNC                    0x080218
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)          ((x) << 16)
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK                0x3F0000
> +
> +#define HIBMC_CRT_VERT_SYNC_START(x)           ((x) << 0)
> +#define HIBMC_CRT_VERT_SYNC_START_MASK         0x7FF
> +
> +/* Auto Centering */
> +#define HIBMC_CRT_AUTO_CENTERING_TL            0x080280
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)     ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK   0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK  0x7FF
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR            0x080284
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)  ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK        0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)   ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7FF
> +
> +/* register to control panel output */
> +#define HIBMC_DISPLAY_CONTROL_HISILE           0x80288
> +#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x)       ((x) << 0)
> +#define HIBMC_DISPLAY_CONTROL_PANELDATE(x)     ((x) << 1)
> +#define HIBMC_DISPLAY_CONTROL_FPEN(x)          ((x) << 2)
> +#define HIBMC_DISPLAY_CONTROL_VBIASEN(x)       ((x) << 3)
> +
> +#define HIBMC_RAW_INTERRUPT                    0x80290
> +#define HIBMC_RAW_INTERRUPT_VBLANK(x)          ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_VBLANK_MASK                0x4
> +
> +#define HIBMC_RAW_INTERRUPT_EN                 0x80298
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)       ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK     0x4
> +
> +/* register and values for PLL control */
> +#define CRT_PLL1_HS                            0x802a8
> +#define CRT_PLL1_HS_OUTER_BYPASS(x)            ((x) << 30)
> +#define CRT_PLL1_HS_INTER_BYPASS(x)            ((x) << 29)
> +#define CRT_PLL1_HS_POWERON(x)                 ((x) << 24)
> +
> +#define CRT_PLL1_HS_25MHZ                      0x23d40f02
> +#define CRT_PLL1_HS_40MHZ                      0x23940801
> +#define CRT_PLL1_HS_65MHZ                      0x23940d01
> +#define CRT_PLL1_HS_78MHZ                      0x23540F82
> +#define CRT_PLL1_HS_74MHZ                      0x23941dc2
> +#define CRT_PLL1_HS_80MHZ                      0x23941001
> +#define CRT_PLL1_HS_80MHZ_1152                 0x23540fc2
> +#define CRT_PLL1_HS_108MHZ                     0x23b41b01
> +#define CRT_PLL1_HS_162MHZ                     0x23480681
> +#define CRT_PLL1_HS_148MHZ                     0x23541dc2
> +#define CRT_PLL1_HS_193MHZ                     0x234807c1
> +
> +#define CRT_PLL2_HS                            0x802ac
> +#define CRT_PLL2_HS_25MHZ                      0x206B851E
> +#define CRT_PLL2_HS_40MHZ                      0x30000000
> +#define CRT_PLL2_HS_65MHZ                      0x40000000
> +#define CRT_PLL2_HS_78MHZ                      0x50E147AE
> +#define CRT_PLL2_HS_74MHZ                      0x602B6AE7
> +#define CRT_PLL2_HS_80MHZ                      0x70000000
> +#define CRT_PLL2_HS_108MHZ                     0x80000000
> +#define CRT_PLL2_HS_162MHZ                     0xA0000000
> +#define CRT_PLL2_HS_148MHZ                     0xB0CCCCCD
> +#define CRT_PLL2_HS_193MHZ                     0xC0872B02
> +
> +#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
> +#endif
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v4 0/2] ARM: dts: sun6i: hummingbird-a31: Enable display output through VGA bridge
From: Chen-Yu Tsai @ 2016-11-16 15:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This is v4 of my sun6i DRM/KMS display enablement series. It adds
regulator support to the dumb-vga-dac bridge and enables the VGA
output on the A31 Hummingbird.


Changes since v3:

  - Add Rob's Ack.

  - Fix up enable/disable callbacks as Archit suggested.

  - Dropped pinmux settings for GPIO pin.

Changes since v2:

  - Changed the enable-gpio of dumb-vga-dac to vdd-supply regulator.
    This better matches the hardware that I have: the DAC has a fixed
    regulator dropping the voltage from the board-wide 5V to 3.3V the
    DAC uses. The regulator is controlled through a GPIO pin.

  - Renamed the node of the VGA connector from "vga" to "vga-connector".

  - Renamed the node of the VGA DAC from "bridge" to "vga-dac".


Regards
ChenYu


Chen-Yu Tsai (2):
  drm/bridge: dumb-vga-dac: Support a VDD regulator supply
  ARM: dts: sun6i: hummingbird-a31: Enable display output through VGA
    bridge

 .../bindings/display/bridge/dumb-vga-dac.txt       |  2 +
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts        | 67 ++++++++++++++++++++++
 drivers/gpu/drm/bridge/dumb-vga-dac.c              | 35 +++++++++++
 3 files changed, 104 insertions(+)

-- 
2.10.2

^ permalink raw reply

* [PATCH v4 1/2] drm/bridge: dumb-vga-dac: Support a VDD regulator supply
From: Chen-Yu Tsai @ 2016-11-16 15:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116154232.872-1-wens@csie.org>

Some dumb VGA DACs are active components which require external power.
Add support for specifying a regulator as its power supply.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../bindings/display/bridge/dumb-vga-dac.txt       |  2 ++
 drivers/gpu/drm/bridge/dumb-vga-dac.c              | 35 ++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt b/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt
index 003bc246a270..164cbb15f04c 100644
--- a/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt
+++ b/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt
@@ -16,6 +16,8 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt.
 - Video port 0 for RGB input
 - Video port 1 for VGA output
 
+Optional properties:
+- vdd-supply: Power supply for DAC
 
 Example
 -------
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
index afec232185a7..15b549f94307 100644
--- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
+++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 #include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
@@ -23,6 +24,7 @@ struct dumb_vga {
 	struct drm_connector	connector;
 
 	struct i2c_adapter	*ddc;
+	struct regulator	*vdd;
 };
 
 static inline struct dumb_vga *
@@ -124,8 +126,32 @@ static int dumb_vga_attach(struct drm_bridge *bridge)
 	return 0;
 }
 
+static void dumb_vga_enable(struct drm_bridge *bridge)
+{
+	struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge);
+	int ret = 0;
+
+	if (vga->vdd)
+		ret = regulator_enable(vga->vdd);
+
+	if (ret) {
+		DRM_ERROR("Failed to enable vdd regulator: %d\n", ret);
+		return;
+	}
+}
+
+static void dumb_vga_disable(struct drm_bridge *bridge)
+{
+	struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge);
+
+	if (vga->vdd)
+		regulator_disable(vga->vdd);
+}
+
 static const struct drm_bridge_funcs dumb_vga_bridge_funcs = {
 	.attach		= dumb_vga_attach,
+	.enable		= dumb_vga_enable,
+	.disable	= dumb_vga_disable,
 };
 
 static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev)
@@ -169,6 +195,15 @@ static int dumb_vga_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, vga);
 
+	vga->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
+	if (IS_ERR(vga->vdd)) {
+		ret = PTR_ERR(vga->vdd);
+		if (ret == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		vga->vdd = NULL;
+		dev_dbg(&pdev->dev, "No vdd regulator found: %d\n", ret);
+	}
+
 	vga->ddc = dumb_vga_retrieve_ddc(&pdev->dev);
 	if (IS_ERR(vga->ddc)) {
 		if (PTR_ERR(vga->ddc) == -ENODEV) {
-- 
2.10.2

^ permalink raw reply related

* [PATCH v4 2/2] ARM: dts: sun6i: hummingbird-a31: Enable display output through VGA bridge
From: Chen-Yu Tsai @ 2016-11-16 15:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116154232.872-1-wens@csie.org>

The Hummingbird A31 board has a VGA DAC which converts RGB output
from the LCD interface to VGA analog signals.

Add nodes for the VGA DAC, its power supply, and enable this part
of the display pipeline.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts | 67 +++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 62287bd2aeb5..b168d6df2b30 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -63,6 +63,60 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	vga-connector {
+		compatible = "vga-connector";
+
+		port {
+			vga_con_in: endpoint {
+				remote-endpoint = <&vga_dac_out>;
+			};
+		};
+	};
+
+	vga-dac {
+		compatible = "dumb-vga-dac";
+		vdd-supply = <&reg_vga_3v3>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0>;
+
+				vga_dac_in: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&tcon0_out_vga>;
+				};
+			};
+
+			port at 1 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <1>;
+
+				vga_dac_out: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&vga_con_in>;
+				};
+			};
+		};
+	};
+
+	reg_vga_3v3: vga_3v3_regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vga-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		enable-active-high;
+		gpio = <&pio 7 25 GPIO_ACTIVE_HIGH>; /* PH25 */
+	};
+
 	wifi_pwrseq: wifi_pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		reset-gpios = <&pio 6 10 GPIO_ACTIVE_LOW>; /* PG10 */
@@ -253,6 +307,19 @@
 	status = "okay";
 };
 
+&tcon0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&lcd0_rgb888_pins>;
+	status = "okay";
+};
+
+&tcon0_out {
+	tcon0_out_vga: endpoint at 0 {
+		reg = <0>;
+		remote-endpoint = <&vga_dac_in>;
+	};
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
-- 
2.10.2

^ permalink raw reply related

* [PATCH fpga 8/9] fpga socfpga: Use the scatterlist interface
From: atull @ 2016-11-16 15:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116052033.GA6044@obsidianresearch.com>

On Wed, 16 Nov 2016, Jason Gunthorpe wrote:

> On Tue, Nov 15, 2016 at 09:47:05AM -0600, atull wrote:
> > Not different.
> > 
> > From 'fpga-mgr.txt':
> >   The programming sequence is:
> >    1. .write_init
> >    2. .write (may be called once or multiple times)
> >    3. .write_complete
> > 
> > The old write was be separate from write_init and write_complete
> > because I figured that in the future someone may be streaming in
> > the bitstream and not have the whole bitstream in memory.
> 
> What is the point of this if write_init gets a copy of the buffer -
> what is that supposed to be?

Sometimes write_init needs to look at the header of the image.
You can see that in the socfpga-a10.c (on linux-next/master)

> 
> If you see things this way why are you opposed to patch 9? I'll change
> things around to call write multiple times and force the sg list into
> write_init, which seems like what you intended anyhow..

Not against it (and I do need to spend some more time looking
at this stuff, this is coming at a busy time).  My point there
was that there was code that needed to go into the core so that
the ICE40 and the cyclone spi driver that are on the mailing
list won't have to have the same workaround that you were
adding to the socfpga.c driver.

Alan

> 
> Jason
> 

^ permalink raw reply

* [PATCH v7 2/7] drm/hisilicon/hibmc: Add video memory management
From: Sean Paul @ 2016-11-16 15:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-3-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Hibmc have 32m video memory which can be accessed through PCIe by host,
> we use ttm to manage these memory.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  14 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  41 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 485 ++++++++++++++++++++++++
>  4 files changed, 541 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 47962a0..19ed0ef 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 6d20580..521f69f 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -28,6 +28,7 @@
>         .release        = drm_release,
>         .unlocked_ioctl = drm_ioctl,
>         .compat_ioctl   = drm_compat_ioctl,
> +       .mmap           = hibmc_mmap,
>         .poll           = drm_poll,
>         .read           = drm_read,
>         .llseek         = no_llseek,
> @@ -43,6 +44,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> +       .driver_features        = DRIVER_GEM,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -52,6 +54,10 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>         .get_vblank_counter     = drm_vblank_no_hw_counter,
>         .enable_vblank          = hibmc_enable_vblank,
>         .disable_vblank         = hibmc_disable_vblank,
> +       .gem_free_object_unlocked = hibmc_gem_free_object,
> +       .dumb_create            = hibmc_dumb_create,
> +       .dumb_map_offset        = hibmc_dumb_mmap_offset,
> +       .dumb_destroy           = drm_gem_dumb_destroy,
>  };
>
>  static int hibmc_pm_suspend(struct device *dev)
> @@ -194,6 +200,10 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv)
>
>  static int hibmc_unload(struct drm_device *dev)
>  {
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       hibmc_mm_fini(priv);
> +       dev->dev_private = NULL;
>         return 0;
>  }
>
> @@ -214,6 +224,10 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_mm_init(priv);
> +       if (ret)
> +               goto err;
> +
>         return 0;
>
>  err:
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index 840cd5a..dcd304d 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,6 +20,8 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_gem.h>
> +#include <drm/ttm/ttm_bo_driver.h>
>
>  struct hibmc_drm_private {
>         /* hw */
> @@ -31,11 +33,50 @@ struct hibmc_drm_private {
>         /* drm */
>         struct drm_device  *dev;
>
> +       /* ttm */
> +       struct drm_global_reference mem_global_ref;
> +       struct ttm_bo_global_ref bo_global_ref;
> +       struct ttm_bo_device bdev;
> +       bool initialized;
> +
> +       bool mm_inited;
> +};
> +
> +struct hibmc_bo {
> +       struct ttm_buffer_object bo;
> +       struct ttm_placement placement;
> +       struct ttm_bo_kmap_obj kmap;
> +       struct drm_gem_object gem;
> +       struct ttm_place placements[3];
> +       int pin_count;
>  };
>
> +static inline struct hibmc_bo *hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       return container_of(bo, struct hibmc_bo, bo);
> +}
> +
> +static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
> +{
> +       return container_of(gem, struct hibmc_bo, gem);
> +}
> +
>  void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>                           unsigned int power_mode);
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj);
> +int hibmc_mm_init(struct hibmc_drm_private *hibmc);
> +void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> +int hibmc_bo_unpin(struct hibmc_bo *bo);
> +void hibmc_gem_free_object(struct drm_gem_object *obj);
> +int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
> +                     struct drm_mode_create_dumb *args);
> +int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
> +                          u32 handle, u64 *offset);
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
> +
>  #endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> new file mode 100644
> index 0000000..036d3ac
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -0,0 +1,485 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <ttm/ttm_page_alloc.h>
> +
> +#include "hibmc_drm_drv.h"
> +
> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
> +
> +static inline struct hibmc_drm_private *
> +hibmc_bdev(struct ttm_bo_device *bd)
> +{
> +       return container_of(bd, struct hibmc_drm_private, bdev);
> +}
> +
> +static int
> +hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
> +{
> +       return ttm_mem_global_init(ref->object);
> +}
> +
> +static void
> +hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
> +{
> +       ttm_mem_global_release(ref->object);
> +}
> +
> +static int hibmc_ttm_global_init(struct hibmc_drm_private *hibmc)
> +{
> +       int ret;
> +
> +       hibmc->mem_global_ref.global_type = DRM_GLOBAL_TTM_MEM;
> +       hibmc->mem_global_ref.size = sizeof(struct ttm_mem_global);
> +       hibmc->mem_global_ref.init = &hibmc_ttm_mem_global_init;
> +       hibmc->mem_global_ref.release = &hibmc_ttm_mem_global_release;
> +       ret = drm_global_item_ref(&hibmc->mem_global_ref);
> +       if (ret) {
> +               DRM_ERROR("could not get ref on ttm global: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->bo_global_ref.mem_glob =
> +               hibmc->mem_global_ref.object;
> +       hibmc->bo_global_ref.ref.global_type = DRM_GLOBAL_TTM_BO;
> +       hibmc->bo_global_ref.ref.size = sizeof(struct ttm_bo_global);
> +       hibmc->bo_global_ref.ref.init = &ttm_bo_global_init;
> +       hibmc->bo_global_ref.ref.release = &ttm_bo_global_release;
> +       ret = drm_global_item_ref(&hibmc->bo_global_ref.ref);
> +       if (ret) {
> +               DRM_ERROR("failed setting up TTM BO subsystem: %d\n", ret);
> +               drm_global_item_unref(&hibmc->mem_global_ref);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static void
> +hibmc_ttm_global_release(struct hibmc_drm_private *hibmc)
> +{
> +       drm_global_item_unref(&hibmc->bo_global_ref.ref);
> +       drm_global_item_unref(&hibmc->mem_global_ref);
> +       hibmc->mem_global_ref.release = NULL;
> +}
> +
> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
> +{
> +       struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo);
> +
> +       drm_gem_object_release(&bo->gem);
> +       kfree(bo);
> +}
> +
> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       return bo->destroy == &hibmc_bo_ttm_destroy;
> +}
> +
> +static int
> +hibmc_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
> +                      struct ttm_mem_type_manager *man)
> +{
> +       switch (type) {
> +       case TTM_PL_SYSTEM:
> +               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
> +               man->available_caching = TTM_PL_MASK_CACHING;
> +               man->default_caching = TTM_PL_FLAG_CACHED;
> +               break;
> +       case TTM_PL_VRAM:
> +               man->func = &ttm_bo_manager_func;
> +               man->flags = TTM_MEMTYPE_FLAG_FIXED |
> +                       TTM_MEMTYPE_FLAG_MAPPABLE;
> +               man->available_caching = TTM_PL_FLAG_UNCACHED |
> +                       TTM_PL_FLAG_WC;
> +               man->default_caching = TTM_PL_FLAG_WC;
> +               break;
> +       default:
> +               DRM_ERROR("unsupported memory type %u\n", type);
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +void hibmc_ttm_placement(struct hibmc_bo *bo, int domain)
> +{
> +       u32 count = 0;
> +       u32 i;
> +
> +       bo->placement.placement = bo->placements;
> +       bo->placement.busy_placement = bo->placements;
> +       if (domain & TTM_PL_FLAG_VRAM)
> +               bo->placements[count++].flags = TTM_PL_FLAG_WC |
> +                       TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
> +       if (domain & TTM_PL_FLAG_SYSTEM)
> +               bo->placements[count++].flags = TTM_PL_MASK_CACHING |
> +                       TTM_PL_FLAG_SYSTEM;
> +       if (!count)
> +               bo->placements[count++].flags = TTM_PL_MASK_CACHING |
> +                       TTM_PL_FLAG_SYSTEM;
> +
> +       bo->placement.num_placement = count;
> +       bo->placement.num_busy_placement = count;
> +       for (i = 0; i < count; i++) {
> +               bo->placements[i].fpfn = 0;
> +               bo->placements[i].lpfn = 0;
> +       }
> +}
> +
> +static void
> +hibmc_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
> +{
> +       struct hibmc_bo *hibmcbo = hibmc_bo(bo);
> +
> +       if (!hibmc_ttm_bo_is_hibmc_bo(bo))
> +               return;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_SYSTEM);
> +       *pl = hibmcbo->placement;
> +}
> +
> +static int hibmc_bo_verify_access(struct ttm_buffer_object *bo,
> +                                 struct file *filp)
> +{
> +       struct hibmc_bo *hibmcbo = hibmc_bo(bo);
> +
> +       return drm_vma_node_verify_access(&hibmcbo->gem.vma_node,
> +                                         filp->private_data);
> +}
> +
> +static int hibmc_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
> +                                   struct ttm_mem_reg *mem)
> +{
> +       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
> +       struct hibmc_drm_private *hibmc = hibmc_bdev(bdev);
> +
> +       mem->bus.addr = NULL;
> +       mem->bus.offset = 0;
> +       mem->bus.size = mem->num_pages << PAGE_SHIFT;
> +       mem->bus.base = 0;
> +       mem->bus.is_iomem = false;
> +       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
> +               return -EINVAL;
> +       switch (mem->mem_type) {
> +       case TTM_PL_SYSTEM:
> +               /* system memory */
> +               return 0;
> +       case TTM_PL_VRAM:
> +               mem->bus.offset = mem->start << PAGE_SHIFT;
> +               mem->bus.base = pci_resource_start(hibmc->dev->pdev, 0);
> +               mem->bus.is_iomem = true;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +static void hibmc_ttm_backend_destroy(struct ttm_tt *tt)
> +{
> +       ttm_tt_fini(tt);
> +       kfree(tt);
> +}
> +
> +static struct ttm_backend_func hibmc_tt_backend_func = {
> +       .destroy = &hibmc_ttm_backend_destroy,
> +};
> +
> +static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev,
> +                                         unsigned long size,
> +                                         u32 page_flags,
> +                                         struct page *dummy_read_page)
> +{
> +       struct ttm_tt *tt;
> +       int ret;
> +
> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
> +       if (!tt) {
> +               DRM_ERROR("failed to allocate ttm_tt\n");
> +               return NULL;
> +       }
> +       tt->func = &hibmc_tt_backend_func;
> +       ret = ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize ttm_tt: %d\n", ret);
> +               kfree(tt);
> +               return NULL;
> +       }
> +       return tt;
> +}
> +
> +static int hibmc_ttm_tt_populate(struct ttm_tt *ttm)
> +{
> +       return ttm_pool_populate(ttm);
> +}
> +
> +static void hibmc_ttm_tt_unpopulate(struct ttm_tt *ttm)
> +{
> +       ttm_pool_unpopulate(ttm);
> +}
> +
> +struct ttm_bo_driver hibmc_bo_driver = {
> +       .ttm_tt_create          = hibmc_ttm_tt_create,
> +       .ttm_tt_populate        = hibmc_ttm_tt_populate,
> +       .ttm_tt_unpopulate      = hibmc_ttm_tt_unpopulate,
> +       .init_mem_type          = hibmc_bo_init_mem_type,
> +       .evict_flags            = hibmc_bo_evict_flags,
> +       .move                   = NULL,
> +       .verify_access          = hibmc_bo_verify_access,
> +       .io_mem_reserve         = &hibmc_ttm_io_mem_reserve,
> +       .io_mem_free            = NULL,
> +       .lru_tail               = &ttm_bo_default_lru_tail,
> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
> +};
> +
> +int hibmc_mm_init(struct hibmc_drm_private *hibmc)
> +{
> +       int ret;
> +       struct drm_device *dev = hibmc->dev;
> +       struct ttm_bo_device *bdev = &hibmc->bdev;
> +
> +       ret = hibmc_ttm_global_init(hibmc);
> +       if (ret)
> +               return ret;
> +
> +       ret = ttm_bo_device_init(&hibmc->bdev,
> +                                hibmc->bo_global_ref.ref.object,
> +                                &hibmc_bo_driver,
> +                                dev->anon_inode->i_mapping,
> +                                DRM_FILE_PAGE_OFFSET,
> +                                true);
> +       if (ret) {
> +               hibmc_ttm_global_release(hibmc);
> +               DRM_ERROR("error initializing bo driver: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
> +                            hibmc->fb_size >> PAGE_SHIFT);
> +       if (ret) {
> +               hibmc_ttm_global_release(hibmc);
> +               DRM_ERROR("failed ttm VRAM init: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->mm_inited = true;
> +       return 0;
> +}
> +
> +void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
> +{
> +       if (!hibmc->mm_inited)
> +               return;
> +
> +       ttm_bo_device_release(&hibmc->bdev);
> +       hibmc_ttm_global_release(hibmc);
> +       hibmc->mm_inited = false;
> +}
> +
> +static void hibmc_bo_unref(struct hibmc_bo **bo)
> +{
> +       struct ttm_buffer_object *tbo;
> +
> +       if ((*bo) == NULL)
> +               return;
> +
> +       tbo = &((*bo)->bo);
> +       ttm_bo_unref(&tbo);
> +       *bo = NULL;
> +}
> +
> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
> +                   u32 flags, struct hibmc_bo **phibmcbo)
> +{
> +       struct hibmc_drm_private *hibmc = dev->dev_private;
> +       struct hibmc_bo *hibmcbo;
> +       size_t acc_size;
> +       int ret;
> +
> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
> +       if (!hibmcbo) {
> +               DRM_ERROR("failed to allocate hibmcbo\n");
> +               return -ENOMEM;
> +       }
> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize drm gem object: %d\n", ret);
> +               kfree(hibmcbo);
> +               return ret;
> +       }
> +
> +       hibmcbo->bo.bdev = &hibmc->bdev;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
> +
> +       acc_size = ttm_bo_dma_acc_size(&hibmc->bdev, size,
> +                                      sizeof(struct hibmc_bo));
> +
> +       ret = ttm_bo_init(&hibmc->bdev, &hibmcbo->bo, size,
> +                         ttm_bo_type_device, &hibmcbo->placement,
> +                         align >> PAGE_SHIFT, false, NULL, acc_size,
> +                         NULL, NULL, hibmc_bo_ttm_destroy);
> +       if (ret) {
> +               hibmc_bo_unref(&hibmcbo);
> +               DRM_ERROR("failed to initialize ttm_bo: %d\n", ret);
> +               return ret;
> +       }
> +
> +       *phibmcbo = hibmcbo;
> +       return 0;
> +}
> +
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr)
> +{
> +       int i, ret;
> +
> +       if (bo->pin_count) {
> +               bo->pin_count++;
> +               if (gpu_addr)
> +                       *gpu_addr = bo->bo.offset;
> +               return 0;
> +       }
> +
> +       hibmc_ttm_placement(bo, pl_flag);
> +       for (i = 0; i < bo->placement.num_placement; i++)
> +               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
> +       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +       if (ret)
> +               return ret;
> +
> +       bo->pin_count = 1;
> +       if (gpu_addr)
> +               *gpu_addr = bo->bo.offset;
> +       return 0;
> +}
> +
> +int hibmc_bo_unpin(struct hibmc_bo *bo)
> +{
> +       int i, ret;
> +
> +       if (!bo->pin_count) {
> +               DRM_ERROR("unpin bad %p\n", bo);
> +               return 0;
> +       }
> +       bo->pin_count--;
> +       if (bo->pin_count)
> +               return 0;
> +
> +       for (i = 0; i < bo->placement.num_placement ; i++)
> +               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
> +       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +       if (ret) {
> +               DRM_ERROR("validate failed for unpin: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       struct drm_file *file_priv;
> +       struct hibmc_drm_private *hibmc;
> +
> +       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
> +               return -EINVAL;
> +
> +       file_priv = filp->private_data;
> +       hibmc = file_priv->minor->dev->dev_private;
> +       return ttm_bo_mmap(filp, vma, &hibmc->bdev);
> +}
> +
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj)
> +{
> +       struct hibmc_bo *hibmcbo;
> +       int ret;
> +
> +       *obj = NULL;
> +
> +       size = PAGE_ALIGN(size);
> +       if (size == 0) {
> +               DRM_ERROR("error: zero size\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
> +       if (ret) {
> +               if (ret != -ERESTARTSYS)
> +                       DRM_ERROR("failed to allocate GEM object: %d\n", ret);
> +               return ret;
> +       }
> +       *obj = &hibmcbo->gem;
> +       return 0;
> +}
> +
> +int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
> +                     struct drm_mode_create_dumb *args)
> +{
> +       struct drm_gem_object *gobj;
> +       u32 handle;
> +       int ret;
> +
> +       args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16);
> +       args->size = args->pitch * args->height;
> +
> +       ret = hibmc_gem_create(dev, args->size, false,
> +                              &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create GEM object: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_gem_handle_create(file, gobj, &handle);
> +       drm_gem_object_unreference_unlocked(gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to unreference GEM object: %d\n", ret);
> +               return ret;
> +       }
> +
> +       args->handle = handle;
> +       return 0;
> +}
> +
> +void hibmc_gem_free_object(struct drm_gem_object *obj)
> +{
> +       struct hibmc_bo *hibmcbo = gem_to_hibmc_bo(obj);
> +
> +       hibmc_bo_unref(&hibmcbo);
> +}
> +
> +static u64 hibmc_bo_mmap_offset(struct hibmc_bo *bo)
> +{
> +       return drm_vma_node_offset_addr(&bo->bo.vma_node);
> +}
> +
> +int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
> +                          u32 handle, u64 *offset)
> +{
> +       struct drm_gem_object *obj;
> +       struct hibmc_bo *bo;
> +
> +       obj = drm_gem_object_lookup(file, handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       bo = gem_to_hibmc_bo(obj);
> +       *offset = hibmc_bo_mmap_offset(bo);
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +       return 0;
> +}
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH 0/8] DMA: s3c64xx: Conversion to the new channel request API
From: Arnd Bergmann @ 2016-11-16 15:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116032620.GV3000@localhost>

On Wednesday, November 16, 2016 8:56:20 AM CET Vinod Koul wrote:
> On Thu, Nov 10, 2016 at 04:17:48PM +0100, Sylwester Nawrocki wrote:
> > This patch series aims to convert the s3c64xx platform to use
> > the new DMA channel request API, i.e. this is only meaningful 
> > for non-dt systems using s3c64xx SoCs.
> > 
> > Presumably the first 2 or 4 patches in this series could be queued 
> > for v4.10-rc1 and the remaining patches could be left for subsequent
> > release, to avoid non-trivial conflict with patches already applied 
> > in the ASoC tree.
> 
> I am fine with dma patch (expect the subsystem tag) and others except arm
> ones have acks, so I think we can merge this for v4.10-rc1. I cna create a
> immutable tag and people can merge into their tree in case they have
> dependencies.
> 
> Btw need acks on ARM patches before I can apply

Whole series

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* [PATCH v7 3/7] drm/hisilicon/hibmc: Add support for frame buffer
From: Sean Paul @ 2016-11-16 15:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-4-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add support for fbdev and kms fb management.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   |   7 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 ++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  67 ++++++
>  5 files changed, 366 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 19ed0ef..ff77a7e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 521f69f..4b52b29 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -202,6 +202,7 @@ static int hibmc_unload(struct drm_device *dev)
>  {
>         struct hibmc_drm_private *priv = dev->dev_private;
>
> +       hibmc_fbdev_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
>         return 0;
> @@ -228,6 +229,12 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_fbdev_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize fbdev: %d\n", ret);
> +               goto err;
> +       }
> +
>         return 0;
>
>  err:
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index dcd304d..d283d66 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,9 +20,21 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/ttm/ttm_bo_driver.h>
>
> +struct hibmc_framebuffer {
> +       struct drm_framebuffer fb;
> +       struct drm_gem_object *obj;
> +};
> +
> +struct hibmc_fbdev {
> +       struct drm_fb_helper helper;
> +       struct hibmc_framebuffer *fb;
> +       int size;
> +};
> +
>  struct hibmc_drm_private {
>         /* hw */
>         void __iomem   *mmio;
> @@ -39,9 +51,13 @@ struct hibmc_drm_private {
>         struct ttm_bo_device bdev;
>         bool initialized;
>
> +       /* fbdev */
> +       struct hibmc_fbdev *fbdev;
>         bool mm_inited;
>  };
>
> +#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
> +
>  struct hibmc_bo {
>         struct ttm_buffer_object bo;
>         struct ttm_placement placement;
> @@ -66,8 +82,16 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_fbdev_init(struct hibmc_drm_private *priv);
> +void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
> +
>  int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>                      struct drm_gem_object **obj);
> +struct hibmc_framebuffer *
> +hibmc_framebuffer_init(struct drm_device *dev,
> +                      const struct drm_mode_fb_cmd2 *mode_cmd,
> +                      struct drm_gem_object *obj);
> +
>  int hibmc_mm_init(struct hibmc_drm_private *hibmc);
>  void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
>  int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> new file mode 100644
> index 0000000..9b06967
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> @@ -0,0 +1,267 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +
> +static int hibmcfb_create_object(
> +                               struct hibmc_drm_private *priv,
> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
> +                               struct drm_gem_object **gobj_p)
> +{
> +       struct drm_gem_object *gobj;
> +       struct drm_device *dev = priv->dev;
> +       u32 size;
> +       int ret = 0;
> +
> +       size = mode_cmd->pitches[0] * mode_cmd->height;
> +       ret = hibmc_gem_create(dev, size, true, &gobj);
> +       if (ret)
> +               return ret;
> +
> +       *gobj_p = gobj;
> +       return ret;
> +}
> +
> +static struct fb_ops hibmc_drm_fb_ops = {
> +       .owner = THIS_MODULE,
> +       .fb_check_var = drm_fb_helper_check_var,
> +       .fb_set_par = drm_fb_helper_set_par,
> +       .fb_fillrect = drm_fb_helper_sys_fillrect,
> +       .fb_copyarea = drm_fb_helper_sys_copyarea,
> +       .fb_imageblit = drm_fb_helper_sys_imageblit,
> +       .fb_pan_display = drm_fb_helper_pan_display,
> +       .fb_blank = drm_fb_helper_blank,
> +       .fb_setcmap = drm_fb_helper_setcmap,
> +};
> +
> +static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
> +                              struct drm_fb_helper_surface_size *sizes)
> +{
> +       struct hibmc_fbdev *hi_fbdev =
> +               container_of(helper, struct hibmc_fbdev, helper);
> +       struct hibmc_drm_private *priv = helper->dev->dev_private;
> +       struct fb_info *info;
> +       struct drm_mode_fb_cmd2 mode_cmd;
> +       struct drm_gem_object *gobj = NULL;
> +       int ret = 0;
> +       int ret1;
> +       size_t size;
> +       unsigned int bytes_per_pixel;
> +       struct hibmc_bo *bo = NULL;
> +
> +       DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
> +                        sizes->surface_width, sizes->surface_height,
> +                        sizes->surface_bpp);
> +       sizes->surface_depth = 32;
> +
> +       bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
> +
> +       mode_cmd.width = sizes->surface_width;
> +       mode_cmd.height = sizes->surface_height;
> +       mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
> +       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
> +                                                         sizes->surface_depth);
> +
> +       size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
> +
> +       ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
> +               return -ENOMEM;
> +       }
> +
> +       bo = gem_to_hibmc_bo(gobj);
> +
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to reserve ttm_bo: %d\n", ret);
> +               goto out_unref_gem;
> +       }
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to pin fbcon: %d\n", ret);
> +               goto out_unreserve_ttm_bo;
> +       }
> +
> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> +       if (ret) {
> +               DRM_ERROR("failed to kmap fbcon: %d\n", ret);
> +               goto out_unpin_bo;
> +       }
> +       ttm_bo_unreserve(&bo->bo);
> +
> +       info = drm_fb_helper_alloc_fbi(helper);
> +       if (IS_ERR(info)) {
> +               ret = PTR_ERR(info);
> +               DRM_ERROR("failed to allocate fbi: %d\n", ret);
> +               goto out_release_fbi;
> +       }
> +
> +       info->par = hi_fbdev;
> +
> +       hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
> +       if (IS_ERR(hi_fbdev->fb)) {
> +               ret = PTR_ERR(info);
> +               DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
> +               goto out_release_fbi;
> +       }
> +
> +       priv->fbdev->size = size;
> +       hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
> +
> +       strcpy(info->fix.id, "hibmcdrmfb");
> +
> +       info->flags = FBINFO_DEFAULT;
> +       info->fbops = &hibmc_drm_fb_ops;
> +
> +       drm_fb_helper_fill_fix(info, hi_fbdev->fb->fb.pitches[0],
> +                              hi_fbdev->fb->fb.depth);
> +       drm_fb_helper_fill_var(info, &priv->fbdev->helper, sizes->fb_width,
> +                              sizes->fb_height);
> +
> +       info->screen_base = bo->kmap.virtual;
> +       info->screen_size = size;
> +
> +       info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
> +       info->fix.smem_len = size;
> +       return 0;
> +
> +out_release_fbi:
> +       drm_fb_helper_release_fbi(helper);
> +       ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret1) {
> +               DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1);
> +               goto out_unref_gem;
> +       }
> +       ttm_bo_kunmap(&bo->kmap);
> +out_unpin_bo:
> +       hibmc_bo_unpin(bo);
> +out_unreserve_ttm_bo:
> +       ttm_bo_unreserve(&bo->bo);
> +out_unref_gem:
> +       drm_gem_object_unreference_unlocked(gobj);
> +
> +       return ret;
> +}
> +
> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
> +{
> +       struct hibmc_framebuffer *gfb = fbdev->fb;
> +       struct drm_fb_helper *fbh = &fbdev->helper;
> +
> +       drm_fb_helper_unregister_fbi(fbh);
> +       drm_fb_helper_release_fbi(fbh);
> +
> +       drm_fb_helper_fini(fbh);
> +
> +       if (gfb)
> +               drm_framebuffer_unreference(&gfb->fb);
> +}
> +
> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
> +       .fb_probe = hibmc_drm_fb_create,
> +};
> +
> +int hibmc_fbdev_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +       struct fb_var_screeninfo *var;
> +       struct fb_fix_screeninfo *fix;
> +       struct hibmc_fbdev *hifbdev;
> +
> +       hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
> +       if (!hifbdev) {
> +               DRM_ERROR("failed to allocate hibmc_fbdev\n");
> +               return -ENOMEM;
> +       }
> +
> +       priv->fbdev = hifbdev;
> +       drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
> +                             &hibmc_fbdev_helper_funcs);
> +
> +       /* Now just one crtc and one channel */
> +       ret = drm_fb_helper_init(priv->dev,
> +                                &hifbdev->helper, 1, 1);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize fb helper: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
> +       if (ret) {
> +               DRM_ERROR("failed to add all connectors: %d\n", ret);
> +               goto fini;
> +       }
> +
> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
> +       if (ret) {
> +               DRM_ERROR("failed to setup initial conn config: %d\n", ret);
> +               goto fini;
> +       }
> +
> +       var = &hifbdev->helper.fbdev->var;
> +       fix = &hifbdev->helper.fbdev->fix;
> +
> +       DRM_DEBUG_DRIVER("Member of info->var is :\n"
> +                        "xres=%d\n"
> +                        "yres=%d\n"
> +                        "xres_virtual=%d\n"
> +                        "yres_virtual=%d\n"
> +                        "xoffset=%d\n"
> +                        "yoffset=%d\n"
> +                        "bits_per_pixel=%d\n"
> +                        "...\n", var->xres, var->yres, var->xres_virtual,
> +                        var->yres_virtual, var->xoffset, var->yoffset,
> +                        var->bits_per_pixel);
> +       DRM_DEBUG_DRIVER("Member of info->fix is :\n"
> +                        "smem_start=%lx\n"
> +                        "smem_len=%d\n"
> +                        "type=%d\n"
> +                        "type_aux=%d\n"
> +                        "visual=%d\n"
> +                        "xpanstep=%d\n"
> +                        "ypanstep=%d\n"
> +                        "ywrapstep=%d\n"
> +                        "line_length=%d\n"
> +                        "accel=%d\n"
> +                        "capabilities=%d\n"
> +                        "...\n", fix->smem_start, fix->smem_len, fix->type,
> +                        fix->type_aux, fix->visual, fix->xpanstep,
> +                        fix->ypanstep, fix->ywrapstep, fix->line_length,
> +                        fix->accel, fix->capabilities);
> +
> +       return 0;
> +
> +fini:
> +       drm_fb_helper_fini(&hifbdev->helper);
> +       return ret;
> +}
> +
> +void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
> +{
> +       if (!priv->fbdev)
> +               return;
> +
> +       hibmc_fbdev_destroy(priv->fbdev);
> +       priv->fbdev = NULL;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 036d3ac..3ff65f4 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -16,6 +16,7 @@
>   *
>   */
>
> +#include <drm/drm_atomic_helper.h>
>  #include <ttm/ttm_page_alloc.h>
>
>  #include "hibmc_drm_drv.h"
> @@ -483,3 +484,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>         drm_gem_object_unreference_unlocked(obj);
>         return 0;
>  }
> +
> +static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb)
> +{
> +       struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb);
> +
> +       drm_gem_object_unreference_unlocked(hibmc_fb->obj);
> +       drm_framebuffer_cleanup(fb);
> +       kfree(hibmc_fb);
> +}
> +
> +static const struct drm_framebuffer_funcs hibmc_fb_funcs = {
> +       .destroy = hibmc_user_framebuffer_destroy,
> +};
> +
> +struct hibmc_framebuffer *
> +hibmc_framebuffer_init(struct drm_device *dev,
> +                      const struct drm_mode_fb_cmd2 *mode_cmd,
> +                      struct drm_gem_object *obj)
> +{
> +       struct hibmc_framebuffer *hibmc_fb;
> +       int ret;
> +
> +       hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL);
> +       if (!hibmc_fb) {
> +               DRM_ERROR("failed to allocate hibmc_fb\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       drm_helper_mode_fill_fb_struct(&hibmc_fb->fb, mode_cmd);
> +       hibmc_fb->obj = obj;
> +       ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs);
> +       if (ret) {
> +               DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
> +               kfree(hibmc_fb);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return hibmc_fb;
> +}
> +
> +static struct drm_framebuffer *
> +hibmc_user_framebuffer_create(struct drm_device *dev,
> +                             struct drm_file *filp,
> +                             const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +       struct drm_gem_object *obj;
> +       struct hibmc_framebuffer *hibmc_fb;
> +
> +       DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
> +                        mode_cmd->width, mode_cmd->height,
> +                        (mode_cmd->pixel_format) & 0xff,
> +                        (mode_cmd->pixel_format >> 8)  & 0xff,
> +                        (mode_cmd->pixel_format >> 16) & 0xff,
> +                        (mode_cmd->pixel_format >> 24) & 0xff);
> +
> +       obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
> +       if (!obj)
> +               return ERR_PTR(-ENOENT);
> +
> +       hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj);
> +       if (IS_ERR(hibmc_fb)) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return ERR_PTR((long)hibmc_fb);
> +       }
> +       return &hibmc_fb->fb;
> +}
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH 2/2] ahci: qoriq: report warning when ecc register is missing
From: Mathieu Poirier @ 2016-11-16 15:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479265879-48840-2-git-send-email-yuantian.tang@nxp.com>

On Wed, Nov 16, 2016 at 11:11:19AM +0800, yuantian.tang at nxp.com wrote:
> From: Tang Yuantian <Yuantian.Tang@nxp.com>
> 
> For ls1021a and ls1046a socs, sata ecc must be disabled.
> If ecc register is not found in sata node in dts, report
> a warning.

Hi Yuantian,

What happens if sata ecc is _not_ disaled on those socs?  Can the driver still
work?  If not then it is probably a better idea to return an error code that can
prevent the driver from initialising.

Thanks,
Mathieu

> 
> Signed-off-by: Tang Yuantian <yuantian.tang@nxp.com>
> ---
>  drivers/ata/ahci_qoriq.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c
> index 45c88de..66eb4b5 100644
> --- a/drivers/ata/ahci_qoriq.c
> +++ b/drivers/ata/ahci_qoriq.c
> @@ -158,6 +158,7 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
>  
>  	switch (qpriv->type) {
>  	case AHCI_LS1021A:
> +		WARN_ON(!qpriv->ecc_addr);
>  		writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
> @@ -185,6 +186,7 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
>  		break;
>  
>  	case AHCI_LS1046A:
> +		WARN_ON(!qpriv->ecc_addr);
>  		writel(LS1046A_SATA_ECC_DIS, qpriv->ecc_addr);
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -- 
> 2.1.0.27.g96db324
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v7 4/7] drm/hisilicon/hibmc: Add support for display engine
From: Sean Paul @ 2016-11-16 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-5-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add display engine function, crtc/plane is initialized here.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 477 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  69 +++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>  5 files changed, 558 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index ff77a7e..8e0cf72 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> new file mode 100644
> index 0000000..2a1386e
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -0,0 +1,477 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +struct hibmc_display_panel_pll {
> +       unsigned long M;
> +       unsigned long N;
> +       unsigned long OD;
> +       unsigned long POD;
> +};
> +
> +struct hibmc_dislay_pll_config {
> +       unsigned long hdisplay;
> +       unsigned long vdisplay;
> +       u32 pll1_config_value;
> +       u32 pll2_config_value;
> +};
> +
> +static const struct hibmc_dislay_pll_config hibmc_pll_table[] = {
> +       {800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
> +       {1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
> +       {1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
> +       {1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
> +       {1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
> +       {1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
> +       {1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
> +       {1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
> +};
> +
> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
> +
> +static int hibmc_plane_atomic_check(struct drm_plane *plane,
> +                                   struct drm_plane_state *state)
> +{
> +       struct drm_framebuffer *fb = state->fb;
> +       struct drm_crtc *crtc = state->crtc;
> +       struct drm_crtc_state *crtc_state;
> +       u32 src_w = state->src_w >> 16;
> +       u32 src_h = state->src_h >> 16;
> +
> +       if (!crtc || !fb)
> +               return 0;
> +
> +       crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
> +       if (IS_ERR(crtc_state))
> +               return PTR_ERR(crtc_state);
> +
> +       if (src_w != state->crtc_w || src_h != state->crtc_h) {
> +               DRM_DEBUG_ATOMIC("scale not support\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x < 0 || state->crtc_y < 0) {
> +               DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x + state->crtc_w >
> +           crtc_state->adjusted_mode.hdisplay ||
> +           state->crtc_y + state->crtc_h >
> +           crtc_state->adjusted_mode.vdisplay) {
> +               DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_plane_atomic_update(struct drm_plane *plane,
> +                                     struct drm_plane_state *old_state)
> +{
> +       struct drm_plane_state  *state  = plane->state;
> +       u32 reg;
> +       int ret;
> +       u64 gpu_addr = 0;
> +       unsigned int line_l;
> +       struct hibmc_drm_private *priv = plane->dev->dev_private;
> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct hibmc_bo *bo;
> +
> +       if (!state->fb)
> +               return;
> +
> +       hibmc_fb = to_hibmc_framebuffer(state->fb);
> +       bo = gem_to_hibmc_bo(hibmc_fb->obj);
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to reserve ttm_bo: %d", ret);
> +               return;
> +       }
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
> +       ttm_bo_unreserve(&bo->bo);
> +       if (ret) {
> +               DRM_ERROR("failed to pin hibmc_bo: %d", ret);
> +               return;
> +       }
> +
> +       writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS);
> +
> +       reg = state->fb->width * (state->fb->bits_per_pixel / 8);
> +       /* now line_pad is 16 */
> +       reg = PADDING(16, reg);
> +
> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
> +       line_l = PADDING(16, line_l);
> +       writel(HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_WIDTH, reg) |
> +              HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_OFFS, line_l),
> +              priv->mmio + HIBMC_CRT_FB_WIDTH);
> +
> +       /* SET PIXEL FORMAT */
> +       reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
> +       reg &= ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
> +       reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_FORMAT,
> +                          state->fb->bits_per_pixel / 16);
> +       writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
> +}
> +
> +static const u32 channel_formats1[] = {
> +       DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
> +       DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_ABGR8888
> +};
> +
> +static struct drm_plane_funcs hibmc_plane_funcs = {
> +       .update_plane   = drm_atomic_helper_update_plane,
> +       .disable_plane  = drm_atomic_helper_disable_plane,
> +       .set_property = drm_atomic_helper_plane_set_property,
> +       .destroy = drm_plane_cleanup,
> +       .reset = drm_atomic_helper_plane_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +};
> +
> +static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
> +       .atomic_check = hibmc_plane_atomic_check,
> +       .atomic_update = hibmc_plane_atomic_update,
> +};
> +
> +static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_plane *plane;
> +       int ret = 0;
> +
> +       plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
> +       if (!plane) {
> +               DRM_ERROR("failed to alloc memory when init plane\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +       /*
> +        * plane init
> +        * TODO: Now only support primary plane, overlay planes
> +        * need to do.
> +        */
> +       ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
> +                                      channel_formats1,
> +                                      ARRAY_SIZE(channel_formats1),
> +                                      DRM_PLANE_TYPE_PRIMARY,
> +                                      NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init plane: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +
> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
> +       return plane;
> +}
> +
> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       hibmc_set_current_gate(priv, reg);
> +       drm_crtc_vblank_on(crtc);
> +}
> +
> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       drm_crtc_vblank_off(crtc);
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(0);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(0);
> +       hibmc_set_current_gate(priv, reg);
> +}
> +
> +static unsigned int format_pll_reg(void)
> +{
> +       unsigned int pllreg = 0;
> +       struct hibmc_display_panel_pll pll = {0};
> +
> +       /*
> +        * Note that all PLL's have the same format. Here,
> +        * we just use Panel PLL parameter to work out the bit
> +        * fields in the register.On returning a 32 bit number, the value can
> +        * be applied to any PLL in the calling function.
> +        */
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_BYPASS, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POWER, 1);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_INPUT, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POD, pll.POD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_OD, pll.OD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_N, pll.N);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_M, pll.M);
> +
> +       return pllreg;
> +}
> +
> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
> +{
> +       u32 val;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       val = readl(priv->mmio + CRT_PLL1_HS);
> +       val &= ~(CRT_PLL1_HS_OUTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       val = CRT_PLL1_HS_INTER_BYPASS(1) | CRT_PLL1_HS_POWERON(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       writel(pll, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val = pll & ~(CRT_PLL1_HS_POWERON(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val &= ~(CRT_PLL1_HS_INTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val |= CRT_PLL1_HS_OUTER_BYPASS(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +}
> +
> +static void get_pll_config(unsigned long x, unsigned long y,
> +                          u32 *pll1, u32 *pll2)
> +{
> +       int i;
> +       int count = ARRAY_SIZE(hibmc_pll_table);
> +
> +       for (i = 0; i < count; i++) {
> +               if (hibmc_pll_table[i].hdisplay == x &&
> +                   hibmc_pll_table[i].vdisplay == y) {
> +                       *pll1 = hibmc_pll_table[i].pll1_config_value;
> +                       *pll2 = hibmc_pll_table[i].pll2_config_value;
> +                       return;
> +               }
> +       }
> +
> +       /* if found none, we use default value */
> +       *pll1 = CRT_PLL1_HS_25MHZ;
> +       *pll2 = CRT_PLL2_HS_25MHZ;
> +}
> +
> +/*
> + * This function takes care the extra registers and bit fields required to
> + * setup a mode in board.
> + * Explanation about Display Control register:
> + * FPGA only supports 7 predefined pixel clocks, and clock select is
> + * in bit 4:0 of new register 0x802a8.
> + */
> +static unsigned int display_ctrl_adjust(struct drm_device *dev,
> +                                       struct drm_display_mode *mode,
> +                                       unsigned int ctrl)
> +{
> +       unsigned long x, y;
> +       u32 pll1; /* bit[31:0] of PLL */
> +       u32 pll2; /* bit[63:32] of PLL */
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       x = mode->hdisplay;
> +       y = mode->vdisplay;
> +
> +       get_pll_config(x, y, &pll1, &pll2);
> +       writel(pll2, priv->mmio + CRT_PLL2_HS);
> +       set_vclock_hisilicon(dev, pll1);
> +
> +       /*
> +        * Hisilicon has to set up the top-left and bottom-right
> +        * registers as well.
> +        * Note that normal chip only use those two register for
> +        * auto-centering mode.
> +        */
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_TOP, 0) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_LEFT, 0),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM, y - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_RIGHT, x - 1),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_BR);
> +
> +       /*
> +        * Assume common fields in ctrl have been properly set before
> +        * calling this function.
> +        * This function only sets the extra fields in ctrl.
> +        */
> +
> +       /* Set bit 25 of display controller: Select CRT or VGA clock */
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CRTSELECT_MASK;
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK;
> +
> +       ctrl |= HIBMC_CRT_DISP_CTL_CRTSELECT(HIBMC_CRTSELECT_CRT);
> +
> +       /* clock_phase_polarity is 0 */
> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(0);
> +
> +       writel(ctrl, priv->mmio + HIBMC_CRT_DISP_CTL);
> +
> +       return ctrl;
> +}
> +
> +static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
> +{
> +       unsigned int val;
> +       struct drm_display_mode *mode = &crtc->state->mode;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +       int width = mode->hsync_end - mode->hsync_start;
> +       int height = mode->vsync_end - mode->vsync_start;
> +
> +       writel(format_pll_reg(), priv->mmio + HIBMC_CRT_PLL_CTRL);
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISP_END, mode->hdisplay - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_WIDTH, width) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_START, mode->hsync_start - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_SYNC);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_TOTAL, mode->vtotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_DISP_END, mode->vdisplay - 1),
> +              priv->mmio + HIBMC_CRT_VERT_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_HEIGHT, height) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_START, mode->vsync_start - 1),
> +              priv->mmio + HIBMC_CRT_VERT_SYNC);
> +
> +       val = HIBMC_FIELD(HIBMC_CRT_DISP_CTL_VSYNC_PHASE, 0);
> +       val |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_HSYNC_PHASE, 0);
> +       val |= HIBMC_CRT_DISP_CTL_TIMING(1);
> +       val |= HIBMC_CRT_DISP_CTL_PLANE(1);
> +
> +       display_ctrl_adjust(dev, mode, val);
> +}
> +
> +static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +{
> +       unsigned int reg;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       hibmc_set_current_gate(priv, reg);
> +
> +       /* We can add more initialization as needed. */
> +}
> +
> +static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&crtc->dev->event_lock, flags);
> +       if (crtc->state->event)
> +               drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +       crtc->state->event = NULL;
> +       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
> +}
> +
> +static const struct drm_crtc_funcs hibmc_crtc_funcs = {
> +       .page_flip = drm_atomic_helper_page_flip,
> +       .set_config = drm_atomic_helper_set_config,
> +       .destroy = drm_crtc_cleanup,
> +       .reset = drm_atomic_helper_crtc_reset,
> +       .atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +};
> +
> +static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
> +       .enable         = hibmc_crtc_enable,
> +       .disable        = hibmc_crtc_disable,
> +       .mode_set_nofb  = hibmc_crtc_mode_set_nofb,
> +       .atomic_begin   = hibmc_crtc_atomic_begin,
> +       .atomic_flush   = hibmc_crtc_atomic_flush,
> +};
> +
> +int hibmc_de_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_crtc *crtc;
> +       struct drm_plane *plane;
> +       int ret;
> +
> +       plane = hibmc_plane_init(priv);
> +       if (IS_ERR(plane)) {
> +               DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
> +               return PTR_ERR(plane);
> +       }
> +
> +       crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
> +       if (!crtc) {
> +               DRM_ERROR("failed to alloc memory when init crtc\n");
> +               return -ENOMEM;
> +       }
> +
> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
> +                                       NULL, &hibmc_crtc_funcs, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_mode_crtc_set_gamma_size(crtc, 256);
> +       if (ret) {
> +               DRM_ERROR("failed to set gamma size: %d\n", ret);
> +               return ret;
> +       }
> +       drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
> +
> +       return 0;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 4b52b29..9de3564 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -19,6 +19,9 @@
>  #include <linux/console.h>
>  #include <linux/module.h>
>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
>
> @@ -44,7 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> -       .driver_features        = DRIVER_GEM,
> +       .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> +                                 DRIVER_ATOMIC,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,11 +66,31 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>
>  static int hibmc_pm_suspend(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_kms_helper_poll_disable(drm_dev);
> +       priv->suspend_state = drm_atomic_helper_suspend(drm_dev);
> +       if (IS_ERR(priv->suspend_state)) {
> +               DRM_ERROR("drm_atomic_helper_suspend failed: %ld\n",
> +                         PTR_ERR(priv->suspend_state));
> +               drm_kms_helper_poll_enable(drm_dev);
> +               return PTR_ERR(priv->suspend_state);
> +       }
> +
>         return 0;
>  }
>
>  static int hibmc_pm_resume(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_atomic_helper_resume(drm_dev, priv->suspend_state);
> +       drm_kms_helper_poll_enable(drm_dev);
> +
>         return 0;
>  }
>
> @@ -75,6 +99,41 @@ static int hibmc_pm_resume(struct device *dev)
>                                 hibmc_pm_resume)
>  };
>
> +static int hibmc_kms_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +
> +       drm_mode_config_init(priv->dev);
> +       priv->mode_config_initialized = true;
> +
> +       priv->dev->mode_config.min_width = 0;
> +       priv->dev->mode_config.min_height = 0;
> +       priv->dev->mode_config.max_width = 1920;
> +       priv->dev->mode_config.max_height = 1440;
> +
> +       priv->dev->mode_config.fb_base = priv->fb_base;
> +       priv->dev->mode_config.preferred_depth = 24;
> +       priv->dev->mode_config.prefer_shadow = 0;
> +
> +       priv->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
> +
> +       ret = hibmc_de_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init de: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_kms_fini(struct hibmc_drm_private *priv)
> +{
> +       if (priv->mode_config_initialized) {
> +               drm_mode_config_cleanup(priv->dev);
> +               priv->mode_config_initialized = false;
> +       }
> +}
> +
>  /*
>   * It can operate in one of three modes: 0, 1 or Sleep.
>   */
> @@ -203,6 +262,7 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +       hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
>         return 0;
> @@ -229,6 +289,13 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_kms_init(priv);
> +       if (ret)
> +               goto err;
> +
> +       /* reset all the states of crtc/plane/encoder/connector */
> +       drm_mode_config_reset(dev);
> +
>         ret = hibmc_fbdev_init(priv);
>         if (ret) {
>                 DRM_ERROR("failed to initialize fbdev: %d\n", ret);
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index d283d66..87af1eb 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,6 +20,7 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/ttm/ttm_bo_driver.h>
> @@ -44,6 +45,8 @@ struct hibmc_drm_private {
>
>         /* drm */
>         struct drm_device  *dev;
> +       bool mode_config_initialized;
> +       struct drm_atomic_state *suspend_state;
>
>         /* ttm */
>         struct drm_global_reference mem_global_ref;
> @@ -82,6 +85,7 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_de_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> @@ -103,4 +107,6 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>                            u32 handle, u64 *offset);
>  int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
>
> +extern const struct drm_mode_config_funcs hibmc_mode_funcs;
> +
>  #endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 3ff65f4..e76abf6 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -550,3 +550,9 @@ struct hibmc_framebuffer *
>         }
>         return &hibmc_fb->fb;
>  }
> +
> +const struct drm_mode_config_funcs hibmc_mode_funcs = {
> +       .atomic_check = drm_atomic_helper_check,
> +       .atomic_commit = drm_atomic_helper_commit,
> +       .fb_create = hibmc_user_framebuffer_create,
> +};
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 5/7] drm/hisilicon/hibmc: Add support for VDAC
From: Sean Paul @ 2016-11-16 15:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-6-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
> stream from DE to VGA analog signals.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile         |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 147 +++++++++++++++++++++++
>  4 files changed, 155 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 8e0cf72..f2e04c0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 9de3564..c133644 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -123,6 +123,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
>                 return ret;
>         }
>
> +       ret = hibmc_vdac_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init vdac: %d\n", ret);
> +               return ret;
> +       }
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index 87af1eb..b626caf 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -86,6 +86,7 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
>  int hibmc_de_init(struct hibmc_drm_private *priv);
> +int hibmc_vdac_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> new file mode 100644
> index 0000000..d1f67a9
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -0,0 +1,147 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static int hibmc_connector_get_modes(struct drm_connector *connector)
> +{
> +       return drm_add_modes_noedid(connector, 800, 600);
> +}
> +
> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
> +                                     struct drm_display_mode *mode)
> +{
> +       return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +hibmc_connector_best_encoder(struct drm_connector *connector)
> +{
> +       return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
> +}
> +
> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
> +                                                *connector, bool force)
> +{
> +       return connector_status_connected;
> +}
> +
> +static const struct drm_connector_helper_funcs
> +       hibmc_connector_helper_funcs = {
> +       .get_modes = hibmc_connector_get_modes,
> +       .mode_valid = hibmc_connector_mode_valid,
> +       .best_encoder = hibmc_connector_best_encoder,
> +};
> +
> +static const struct drm_connector_funcs hibmc_connector_funcs = {
> +       .dpms = drm_atomic_helper_connector_dpms,
> +       .detect = hibmc_connector_detect,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .destroy = drm_connector_cleanup,
> +       .reset = drm_atomic_helper_connector_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static struct drm_connector *
> +hibmc_connector_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL);
> +       if (!connector) {
> +               DRM_ERROR("failed to alloc memory when init connector\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       ret = drm_connector_init(dev, connector,
> +                                &hibmc_connector_funcs,
> +                                DRM_MODE_CONNECTOR_VGA);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +       drm_connector_helper_add(connector,
> +                                &hibmc_connector_helper_funcs);
> +
> +       return connector;
> +}
> +
> +static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
> +                                  struct drm_display_mode *mode,
> +                                  struct drm_display_mode *adj_mode)
> +{
> +       u32 reg;
> +       struct drm_device *dev = encoder->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1);
> +       writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +}
> +
> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
> +       .mode_set = hibmc_encoder_mode_set,
> +};
> +
> +static const struct drm_encoder_funcs hibmc_encoder_funcs = {
> +       .destroy = drm_encoder_cleanup,
> +};
> +
> +int hibmc_vdac_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_encoder *encoder;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = hibmc_connector_init(priv);
> +       if (IS_ERR(connector)) {
> +               DRM_ERROR("failed to create connector: %ld\n",
> +                         PTR_ERR(connector));
> +               return PTR_ERR(connector);
> +       }
> +
> +       encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
> +       if (!encoder) {
> +               DRM_ERROR("failed to alloc memory when init encoder\n");
> +               return -ENOMEM;
> +       }
> +
> +       encoder->possible_crtcs = 0x1;
> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
> +                              DRM_MODE_ENCODER_DAC, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder: %d\n", ret);
> +               return ret;
> +       }
> +
> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
> +       drm_mode_connector_attach_encoder(connector, encoder);
> +
> +       return 0;
> +}
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 6/7] drm/hisilicon/hibmc: Add support for vblank interrupt
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-7-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add vblank interrupt.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 56 ++++++++++++++++++++++++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  1 +
>  2 files changed, 56 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index c133644..73ba8b0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -39,16 +39,45 @@
>
>  static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +
>         return 0;
>  }
>
>  static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +}
> +
> +irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
> +{
> +       struct drm_device *dev = (struct drm_device *)arg;
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +       u32 status;
> +
> +       status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
> +
> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
> +                      priv->mmio + HIBMC_RAW_INTERRUPT);
> +               drm_handle_vblank(dev, 0);
> +       }
> +
> +       return IRQ_HANDLED;
>  }
>
>  static struct drm_driver hibmc_driver = {
>         .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> -                                 DRIVER_ATOMIC,
> +                                 DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,6 +91,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>         .dumb_create            = hibmc_dumb_create,
>         .dumb_map_offset        = hibmc_dumb_mmap_offset,
>         .dumb_destroy           = drm_gem_dumb_destroy,
> +       .irq_handler            = hibmc_drm_interrupt,
>  };
>
>  static int hibmc_pm_suspend(struct device *dev)
> @@ -268,6 +298,13 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +
> +       if (dev->irq_enabled)
> +               drm_irq_uninstall(dev);
> +       if (priv->msi_enabled)
> +               pci_disable_msi(dev->pdev);
> +       drm_vblank_cleanup(dev);
> +
>         hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
> @@ -299,6 +336,23 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize vblank: %d\n", ret);
> +               goto err;
> +       }
> +
> +       priv->msi_enabled = 0;
> +       ret = pci_enable_msi(dev->pdev);
> +       if (ret) {
> +               DRM_WARN("enabling MSI failed: %d\n", ret);
> +       } else {
> +               priv->msi_enabled = 1;
> +               ret = drm_irq_install(dev, dev->pdev->irq);
> +               if (ret)
> +                       DRM_WARN("install irq failed: %d\n", ret);
> +       }
> +
>         /* reset all the states of crtc/plane/encoder/connector */
>         drm_mode_config_reset(dev);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index b626caf..e195521 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -42,6 +42,7 @@ struct hibmc_drm_private {
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
> +       bool msi_enabled;
>
>         /* drm */
>         struct drm_device  *dev;
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 7/7] MAINTAINERS: Update HISILICON DRM entries
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-8-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2a58eea..84a7296 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4123,6 +4123,7 @@ F:        drivers/gpu/drm/gma500/
>
>  DRM DRIVERS FOR HISILICON
>  M:     Xinliang Liu <z.liuxinliang@hisilicon.com>
> +M:     Rongrong Zou <zourongrong@gmail.com>
>  R:     Xinwei Kong <kong.kongxinwei@hisilicon.com>
>  R:     Chen Feng <puck.chen@hisilicon.com>
>  L:     dri-devel at lists.freedesktop.org
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
From: Sean Paul @ 2016-11-16 16:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-1-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
> BMC SoC with a display controller intergrated, usually it is used on
> server for Out-of-band management purpose. In this patch set, we just
> support basic function for Hibmc display subsystem. Hibmc display
> subsystem is connected to host CPU by PCIe as blow:
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Hardware Detail for Hibmc display subsystem
> -----------
>
>   The display subsystem of Hibmc is show as bellow:
>   +----+      +----+      +----+     +--------+
>   |    |      |    |      |    |     |        |
>   | FB |----->| DE |----->|VDAC|---->|external|
>   |    |      |    |      |    |     | VGA    |
>   +----+      +----+      +----+     +--------+
>
>   -DE(Display Engine) is the display controller.
>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>   stream from DE to VGA analog signals.
>

For the whole series/driver:

Acked-by: Sean Paul <seanpaul@chromium.org>



> Change History
> ------------
> Changes in v7:
>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>    hibmc_drm_drv.c.
>   -remove hibmc_drm_de.h and move the struct defined in head file to
>    hibmc_drm_de.c.
>   -plane is initialized inside crtc, not in hibmc_kms_init().
>   -connector is initialized inside encoder, not in hibmc_kms_init().
>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>   -remove these empty stubs because caller will do NULL check.
>     hibmc_plane_atomic_disable
>     hibmc_crtc_atomic_check
>     hibmc_encoder_disable
>     hibmc_encoder_enable
>     hibmc_encoder_atomic_check
>   -clean up in all error paths of creating driver-private framebuffer.
>
> Changes in v6:
>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>    instead.
>   -remove the deprecated drm_framebuffer_unregister_private(),
>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>   -uninstall irq in hibmc_unload().
>
> Changes in v5:
>   -rebase on v4.9-rc2.
>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>    and remove redundant console_lock and console_unlock.
>
> Changes in v4:
>   -remove unused include files, and include header file when it is needed.
>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>
> Changes in v3:
>   -enable KMS, in v2, only fbdev is enabled.
>   -management video memory with ttm.
>   -add vblank interrupt.
>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>   -I have a basic test with igt.
>
> Changes in v2:
>   -Remove self-defined macros for bit operations.
>   -Remove unused register.
>   -Replace those deprecated functions with new version of them.
>   -use drm_connector_register_all() to register connector after
>    drm_dev_register().
>
> The patch v2 is at
> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>
> Rongrong Zou (7):
>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>   drm/hisilicon/hibmc: Add video memory management
>   drm/hisilicon/hibmc: Add support for frame buffer
>   drm/hisilicon/hibmc: Add support for display engine
>   drm/hisilicon/hibmc: Add support for VDAC
>   drm/hisilicon/hibmc: Add support for vblank interrupt
>   MAINTAINERS: Update HISILICON DRM entries
>
>  MAINTAINERS                                       |   1 +
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>  12 files changed, 2231 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
From: Sean Paul @ 2016-11-16 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOw6vbLgDwiVs8zC5bEhdhJUvVZh2toG_d+FgkzV7vUJjU=3RQ@mail.gmail.com>

On Wed, Nov 16, 2016 at 11:01 AM, Sean Paul <seanpaul@chromium.org> wrote:
> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
>> BMC SoC with a display controller intergrated, usually it is used on
>> server for Out-of-band management purpose. In this patch set, we just
>> support basic function for Hibmc display subsystem. Hibmc display
>> subsystem is connected to host CPU by PCIe as blow:
>>
>> +----------+       +----------+
>> |          | PCIe  |  Hibmc   |
>> |host CPU( |<----->| display  |
>> |arm64,x86)|       |subsystem |
>> +----------+       +----------+
>>
>> Hardware Detail for Hibmc display subsystem
>> -----------
>>
>>   The display subsystem of Hibmc is show as bellow:
>>   +----+      +----+      +----+     +--------+
>>   |    |      |    |      |    |     |        |
>>   | FB |----->| DE |----->|VDAC|---->|external|
>>   |    |      |    |      |    |     | VGA    |
>>   +----+      +----+      +----+     +--------+
>>
>>   -DE(Display Engine) is the display controller.
>>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>>   stream from DE to VGA analog signals.
>>
>
> For the whole series/driver:
>
> Acked-by: Sean Paul <seanpaul@chromium.org>
>
>

Also, please send those fixups for the other ttm drivers ;)

>
>> Change History
>> ------------
>> Changes in v7:
>>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>>    hibmc_drm_drv.c.
>>   -remove hibmc_drm_de.h and move the struct defined in head file to
>>    hibmc_drm_de.c.
>>   -plane is initialized inside crtc, not in hibmc_kms_init().
>>   -connector is initialized inside encoder, not in hibmc_kms_init().
>>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>>   -remove these empty stubs because caller will do NULL check.
>>     hibmc_plane_atomic_disable
>>     hibmc_crtc_atomic_check
>>     hibmc_encoder_disable
>>     hibmc_encoder_enable
>>     hibmc_encoder_atomic_check
>>   -clean up in all error paths of creating driver-private framebuffer.
>>
>> Changes in v6:
>>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>>    instead.
>>   -remove the deprecated drm_framebuffer_unregister_private(),
>>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>>   -uninstall irq in hibmc_unload().
>>
>> Changes in v5:
>>   -rebase on v4.9-rc2.
>>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>>    and remove redundant console_lock and console_unlock.
>>
>> Changes in v4:
>>   -remove unused include files, and include header file when it is needed.
>>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>>
>> Changes in v3:
>>   -enable KMS, in v2, only fbdev is enabled.
>>   -management video memory with ttm.
>>   -add vblank interrupt.
>>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>>   -I have a basic test with igt.
>>
>> Changes in v2:
>>   -Remove self-defined macros for bit operations.
>>   -Remove unused register.
>>   -Replace those deprecated functions with new version of them.
>>   -use drm_connector_register_all() to register connector after
>>    drm_dev_register().
>>
>> The patch v2 is at
>> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>>
>> Rongrong Zou (7):
>>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>>   drm/hisilicon/hibmc: Add video memory management
>>   drm/hisilicon/hibmc: Add support for frame buffer
>>   drm/hisilicon/hibmc: Add support for display engine
>>   drm/hisilicon/hibmc: Add support for VDAC
>>   drm/hisilicon/hibmc: Add support for vblank interrupt
>>   MAINTAINERS: Update HISILICON DRM entries
>>
>>  MAINTAINERS                                       |   1 +
>>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>>  12 files changed, 2231 insertions(+)
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>
>> --
>> 1.9.1
>>

^ permalink raw reply

* [PATCH 1/2] ahci: qoriq: added a condition to enable dma coherence
From: Robin Murphy @ 2016-11-16 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479265879-48840-1-git-send-email-yuantian.tang@nxp.com>

On 16/11/16 03:11, yuantian.tang at nxp.com wrote:
> From: Tang Yuantian <Yuantian.Tang@nxp.com>
> 
> Enable DMA coherence in SATA controller on condition that
> dma-coherent property exists in sata node in DTS.
> 
> Signed-off-by: Tang Yuantian <yuantian.tang@nxp.com>
> ---
>  drivers/ata/ahci_qoriq.c | 15 +++++++++++----
>  1 file changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c
> index 9884c8c..45c88de 100644
> --- a/drivers/ata/ahci_qoriq.c
> +++ b/drivers/ata/ahci_qoriq.c
> @@ -59,6 +59,7 @@ struct ahci_qoriq_priv {
>  	struct ccsr_ahci *reg_base;
>  	enum ahci_qoriq_type type;
>  	void __iomem *ecc_addr;
> +	bool is_dmacoherent;
>  };
>  
>  static const struct of_device_id ahci_qoriq_of_match[] = {
> @@ -164,26 +165,31 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
>  		writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
>  		writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + LS1021A_AXICC_ADDR);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG,
> +					reg_base + LS1021A_AXICC_ADDR);
>  		break;
>  
>  	case AHCI_LS1043A:
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
>  		break;
>  
>  	case AHCI_LS2080A:
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
>  		break;
>  
>  	case AHCI_LS1046A:
>  		writel(LS1046A_SATA_ECC_DIS, qpriv->ecc_addr);
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
>  		break;
>  	}
>  
> @@ -221,6 +227,7 @@ static int ahci_qoriq_probe(struct platform_device *pdev)
>  		if (IS_ERR(qoriq_priv->ecc_addr))
>  			return PTR_ERR(qoriq_priv->ecc_addr);
>  	}
> +	qoriq_priv->is_dmacoherent = of_property_read_bool(np, "dma-coherent");

Better to use of_dma_is_coherent(np) rather than open-coding it.

Robin.

>  
>  	rc = ahci_platform_enable_resources(hpriv);
>  	if (rc)
> 

^ permalink raw reply

* [PATCH v2 0/3] ARM: davinci: PM: cleanup init, add DT support
From: Kevin Hilman @ 2016-11-16 16:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c0f1cfa2-4086-72fc-783b-d0d8c837cb08@ti.com>

Sekhar Nori <nsekhar@ti.com> writes:

> Hi Kevin,
>
> On Wednesday 16 November 2016 01:24 AM, Kevin Hilman wrote:
>> This series removes the fake platform_device used to initialize PM on
>> legacy davinci platforms, and also adds PM support for DT platforms.
>> 
>> Tested with legacy boot on da850-evm, and DT boot on da850-lcdk.  Used
>> RTC to wake from suspend-to-RAM: e.g. rtcwake -m mem -s 4 -d /dev/rtc0
>
> With these patches applied, I saw the following randconfig build error.
>
> arch/arm/mach-davinci/built-in.o: In function `davinci_pm_init':
> pm_domain.c:(.init.text+0x13d8): undefined reference to `da8xx_get_mem_ctlr'
> pm_domain.c:(.init.text+0x14bc): undefined reference to `da8xx_syscfg1_base'
> make: *** [vmlinux] Error 1
>
> Attached is the defconfig. I did not check to see if your patches 
> introduced it or if this is something that always existed and never 
> caught.

It looks like a new problem caused by moving those calls into pm.c.

The problem is that currently pm.o can be built even when da850 support
is not enabled, which is the case in your defconfig.

I'll hae a look at how to cleanup that dependency.

Kevin

^ permalink raw reply

* [PATCH] ARM: dts: imx: add SPI to GW54xx
From: Tim Harvey @ 2016-11-16 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

The GW54xx revision E adds SPI via an off-board connector.

Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
 arch/arm/boot/dts/imx6qdl-gw54xx.dtsi | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
index b6982959..6eb4fc9 100644
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -149,6 +149,14 @@
 				 <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
 };
 
+&ecspi2 {
+	fsl,spi-num-chipselects = <1>;
+	cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi2>;
+	status = "okay";
+};
+
 &fec {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet>;
@@ -511,6 +519,15 @@
 			>;
 		};
 
+		pinctrl_ecspi2: escpi2grp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK	0x100b1
+				MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI	0x100b1
+				MX6QDL_PAD_EIM_OE__ECSPI2_MISO	0x100b1
+				MX6QDL_PAD_EIM_RW__GPIO2_IO26	0x100b1
+			>;
+		};
+
 		pinctrl_flexcan1: flexcan1grp {
 			fsl,pins = <
 				MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX	0x1b0b1
-- 
1.9.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox