* [PATCH v6 2/5] [media] davinci: vpif_capture: remove hard-coded I2C adapter id
From: Kevin Hilman @ 2016-12-07 18:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161207183025.20684-1-khilman@baylibre.com>
Remove hard-coded I2C adapter in favor of getting the
ID from platform_data.
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
---
drivers/media/platform/davinci/vpif_capture.c | 5 ++++-
include/media/davinci/vpif_types.h | 1 +
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 20c4344ed118..c24049acd40a 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -1486,7 +1486,10 @@ static __init int vpif_probe(struct platform_device *pdev)
}
if (!vpif_obj.config->asd_sizes) {
- i2c_adap = i2c_get_adapter(1);
+ int i2c_id = vpif_obj.config->i2c_adapter_id;
+
+ i2c_adap = i2c_get_adapter(i2c_id);
+ WARN_ON(!i2c_adap);
for (i = 0; i < subdev_count; i++) {
subdevdata = &vpif_obj.config->subdev_info[i];
vpif_obj.sd[i] =
diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h
index 3cb1704a0650..4282a7db99d4 100644
--- a/include/media/davinci/vpif_types.h
+++ b/include/media/davinci/vpif_types.h
@@ -82,6 +82,7 @@ struct vpif_capture_config {
struct vpif_capture_chan_config chan_config[VPIF_CAPTURE_MAX_CHANNELS];
struct vpif_subdev_info *subdev_info;
int subdev_count;
+ int i2c_adapter_id;
const char *card_name;
struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
int *asd_sizes; /* 0-terminated array of asd group sizes */
--
2.9.3
^ permalink raw reply related
* [PATCH v6 1/5] [media] davinci: VPIF: fix module loading, init errors
From: Kevin Hilman @ 2016-12-07 18:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161207183025.20684-1-khilman@baylibre.com>
Fix problems with automatic module loading by adding MODULE_ALIAS. Also
fix various load-time errors cause by incorrect or not present
platform_data.
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
---
drivers/media/platform/davinci/vpif.c | 5 ++++-
drivers/media/platform/davinci/vpif_capture.c | 15 ++++++++++++++-
drivers/media/platform/davinci/vpif_display.c | 6 ++++++
3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
index 0380cf2e5775..f50148dcba64 100644
--- a/drivers/media/platform/davinci/vpif.c
+++ b/drivers/media/platform/davinci/vpif.c
@@ -32,6 +32,9 @@
MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
MODULE_LICENSE("GPL");
+#define VPIF_DRIVER_NAME "vpif"
+MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
+
#define VPIF_CH0_MAX_MODES 22
#define VPIF_CH1_MAX_MODES 2
#define VPIF_CH2_MAX_MODES 15
@@ -466,7 +469,7 @@ static const struct dev_pm_ops vpif_pm = {
static struct platform_driver vpif_driver = {
.driver = {
- .name = "vpif",
+ .name = VPIF_DRIVER_NAME,
.pm = vpif_pm_ops,
},
.remove = vpif_remove,
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 5104cc0ee40e..20c4344ed118 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -45,6 +45,7 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level 0-1");
#define VPIF_DRIVER_NAME "vpif_capture"
+MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
/* global variables */
static struct vpif_device vpif_obj = { {NULL} };
@@ -647,6 +648,10 @@ static int vpif_input_to_subdev(
vpif_dbg(2, debug, "vpif_input_to_subdev\n");
+ if (!chan_cfg)
+ return -1;
+ if (input_index >= chan_cfg->input_count)
+ return -1;
subdev_name = chan_cfg->inputs[input_index].subdev_name;
if (subdev_name == NULL)
return -1;
@@ -654,7 +659,7 @@ static int vpif_input_to_subdev(
/* loop through the sub device list to get the sub device info */
for (i = 0; i < vpif_cfg->subdev_count; i++) {
subdev_info = &vpif_cfg->subdev_info[i];
- if (!strcmp(subdev_info->name, subdev_name))
+ if (subdev_info && !strcmp(subdev_info->name, subdev_name))
return i;
}
return -1;
@@ -685,6 +690,9 @@ static int vpif_set_input(
if (sd_index >= 0) {
sd = vpif_obj.sd[sd_index];
subdev_info = &vpif_cfg->subdev_info[sd_index];
+ } else {
+ /* no subdevice, no input to setup */
+ return 0;
}
/* first setup input path from sub device to vpif */
@@ -1435,6 +1443,11 @@ static __init int vpif_probe(struct platform_device *pdev)
int res_idx = 0;
int i, err;
+ if (!pdev->dev.platform_data) {
+ dev_warn(&pdev->dev, "Missing platform data. Giving up.\n");
+ return -EINVAL;
+ }
+
vpif_dev = &pdev->dev;
err = initialize_vpif();
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index 75b27233ec2f..7f632b757d32 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -42,6 +42,7 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level 0-1");
#define VPIF_DRIVER_NAME "vpif_display"
+MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
/* Is set to 1 in case of SDTV formats, 2 in case of HDTV formats. */
static int ycmux_mode;
@@ -1249,6 +1250,11 @@ static __init int vpif_probe(struct platform_device *pdev)
int res_idx = 0;
int i, err;
+ if (!pdev->dev.platform_data) {
+ dev_warn(&pdev->dev, "Missing platform data. Giving up.\n");
+ return -EINVAL;
+ }
+
vpif_dev = &pdev->dev;
err = initialize_vpif();
--
2.9.3
^ permalink raw reply related
* [PATCH v6 0/5] davinci: VPIF: add DT support
From: Kevin Hilman @ 2016-12-07 18:30 UTC (permalink / raw)
To: linux-arm-kernel
Prepare the groundwork for adding DT support for davinci VPIF drivers.
This series does some fixups/cleanups and then adds the DT binding and
DT compatible string matching for DT probing.
The controversial part from previous versions around async subdev
parsing, and specifically hard-coding the input/output routing of
subdevs, has been left out of this series. That part can be done as a
follow-on step after agreement has been reached on the path forward.
With this version, platforms can still use the VPIF capture/display
drivers, but must provide platform_data for the subdevs and subdev
routing.
Tested video capture to memory on da850-lcdk board using composite
input.
Changes since v5:
- locking fix: updated comment around lock variable
- binding doc: added example for
- added reviewed-by tags from Laurent (thanks!)
Changes since v4:
- dropped controversial async subdev parsing support. That can be
done as a follow-up step after the discussions have finalized on the
right approach.
- DT binding Acked by DT maintainer (Rob H.)
- reworked locking fix (suggested by Laurent)
Changes since v3:
- move to a single VPIF node, DT binding updated accordingly
- misc fixes/updates based on reviews from Sakari
Changes since v2:
- DT binding doc: fix example to use correct compatible
Changes since v1:
- more specific compatible strings, based on SoC: ti,da850-vpif*
- fix locking bug when unlocking over subdev s_stream
Kevin Hilman (5):
[media] davinci: VPIF: fix module loading, init errors
[media] davinci: vpif_capture: remove hard-coded I2C adapter id
[media] davinci: vpif_capture: fix start/stop streaming locking
[media] dt-bindings: add TI VPIF documentation
[media] davinci: VPIF: add basic support for DT init
.../devicetree/bindings/media/ti,da850-vpif.txt | 83 ++++++++++++++++++++++
drivers/media/platform/davinci/vpif.c | 14 +++-
drivers/media/platform/davinci/vpif_capture.c | 26 +++++--
drivers/media/platform/davinci/vpif_capture.h | 2 +-
drivers/media/platform/davinci/vpif_display.c | 6 ++
include/media/davinci/vpif_types.h | 1 +
6 files changed, 125 insertions(+), 7 deletions(-)
create mode 100644 Documentation/devicetree/bindings/media/ti,da850-vpif.txt
--
2.9.3
^ permalink raw reply
* [RFC v3 09/10] iommu/arm-smmu: Implement reserved region get/put callbacks
From: Robin Murphy @ 2016-12-07 18:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <c11755b8-4fb3-3f2f-d0b2-e688a5f8a6b6@redhat.com>
On 07/12/16 15:02, Auger Eric wrote:
> Hi Robin,
> On 06/12/2016 19:55, Robin Murphy wrote:
>> On 15/11/16 13:09, Eric Auger wrote:
>>> The get() populates the list with the PCI host bridge windows
>>> and the MSI IOVA range.
>>>
>>> At the moment an arbitray MSI IOVA window is set at 0x8000000
>>> of size 1MB. This will allow to report those info in iommu-group
>>> sysfs?
>
>
> First thank you for reviewing the series. This is definitively helpful!
>>>
>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>
>>> ---
>>>
>>> RFC v2 -> v3:
>>> - use existing get/put_resv_regions
>>>
>>> RFC v1 -> v2:
>>> - use defines for MSI IOVA base and length
>>> ---
>>> drivers/iommu/arm-smmu.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 52 insertions(+)
>>>
>>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>>> index 8f72814..81f1a83 100644
>>> --- a/drivers/iommu/arm-smmu.c
>>> +++ b/drivers/iommu/arm-smmu.c
>>> @@ -278,6 +278,9 @@ enum arm_smmu_s2cr_privcfg {
>>>
>>> #define FSYNR0_WNR (1 << 4)
>>>
>>> +#define MSI_IOVA_BASE 0x8000000
>>> +#define MSI_IOVA_LENGTH 0x100000
>>> +
>>> static int force_stage;
>>> module_param(force_stage, int, S_IRUGO);
>>> MODULE_PARM_DESC(force_stage,
>>> @@ -1545,6 +1548,53 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
>>> return iommu_fwspec_add_ids(dev, &fwid, 1);
>>> }
>>>
>>> +static void arm_smmu_get_resv_regions(struct device *dev,
>>> + struct list_head *head)
>>> +{
>>> + struct iommu_resv_region *region;
>>> + struct pci_host_bridge *bridge;
>>> + struct resource_entry *window;
>>> +
>>> + /* MSI region */
>>> + region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
>>> + IOMMU_RESV_MSI);
>>> + if (!region)
>>> + return;
>>> +
>>> + list_add_tail(®ion->list, head);
>>> +
>>> + if (!dev_is_pci(dev))
>>> + return;
>>> +
>>> + bridge = pci_find_host_bridge(to_pci_dev(dev)->bus);
>>> +
>>> + resource_list_for_each_entry(window, &bridge->windows) {
>>> + phys_addr_t start;
>>> + size_t length;
>>> +
>>> + if (resource_type(window->res) != IORESOURCE_MEM &&
>>> + resource_type(window->res) != IORESOURCE_IO)
>>
>> As Joerg commented elsewhere, considering anything other than memory
>> resources isn't right (I appreciate you've merely copied my own mistake
>> here). We need some other way to handle root complexes where the CPU
>> MMIO views of PCI windows appear in PCI memory space - using the I/O
>> address of I/O resources only works by chance on Juno, and it still
>> doesn't account for config space. I suggest we just leave that out for
>> the time being to make life easier (does it even apply to anything other
>> than Juno?) and figure it out later.
> OK so I understand I should remove IORESOURCE_IO check.
>>
>>> + continue;
>>> +
>>> + start = window->res->start - window->offset;
>>> + length = window->res->end - window->res->start + 1;
>>> + region = iommu_alloc_resv_region(start, length,
>>> + IOMMU_RESV_NOMAP);
>>> + if (!region)
>>> + return;
>>> + list_add_tail(®ion->list, head);
>>> + }
>>> +}
>>
>> Either way, there's nothing SMMU-specific about PCI windows. The fact
>> that we'd have to copy-paste all of this into the SMMUv3 driver
>> unchanged suggests it should go somewhere common (although I would be
>> inclined to leave the insertion of the fake MSI region to driver-private
>> wrappers). As I said before, the current iova_reserve_pci_windows()
>> simply wants splitting into appropriate public callbacks for
>> get_resv_regions and apply_resv_regions.
> Do you mean somewhere common in the arm-smmu subsystem (new file) or in
> another subsystem (pci?)
>
> More generally the current implementation does not handle the case where
> any of those PCIe host bridge window collide with the MSI window. To me
> this is a flaw.
> 1) Either we take into account the PCIe windows and prevent any
> collision when allocating the MSI window.
> 2) or we do not care about PCIe host bridge windows at kernel level.
Even more generally, the MSI window also needs to avoid any other
IOMMU-specific reserved regions as well - fortunately I don't think
there's any current intersection between platforms with RMRR-type
reservations and platforms which require MSI mapping - so I think we've
got enough freedom for the moment, but it's certainly an argument in
favour of ultimately expressing PCI windows through the same mechanism
to keep everything in the same place. The other big advantage of
reserved regions is that they will automatically apply to DMA domains as
well.
> If 1) we are back to the original issue of where do we put the MSI
> window. Obviously at a place which might not be QEMU friendly anymore.
> What allocation policy shall we use?
>
> Second option - sorry I may look stubborn - which I definitively prefer
> and which was also advocated by Alex, we handle PCI host bridge windows
> at user level. MSI window is reported through the iommu group sysfs.
> PCIe host bridge windows can be enumerated through /proc/iomem. Both x86
> iommu and arm smmu would report an MSI reserved window. ARM MSI window
> would become a de facto reserved window for guests.
So from the ABI perspective, the sysfs iommu_group/*/reserved_regions
represents a minimum set of regions (MSI, RMRR, etc.) which definitely
*must* be reserved, but offers no guarantee that there aren't also other
regions not represented there. That seems reasonable to start with, and
still leaves us free to expand the scope of reserved regions in future
without breaking anything.
> Thoughts?
I like the second option too - "grep PCI /proc/iomem" already catches
more than enumerating the resources does (i.e. ECAM space) - and neither
does it preclude growing the more extensive version on top over time.
For the sake of moving forward, I'd be happy with just dropping the PCI
stuff from here, and leaving the SMMU drivers exposing the single
hard-coded MSI region directly (to be fair, it'd hardly be the first
function which is identical between the two). We can take a look into
making iommu-dma implement PCI windows as nomap resv_regions properly as
an orthogonal thing (for the sake of DMA domains), after which we should
be in a position to drop the hard-coding and start placing the MSI
window dynamically where appropriate.
Robin.
>>> +static void arm_smmu_put_resv_regions(struct device *dev,
>>> + struct list_head *head)
>>> +{
>>> + struct iommu_resv_region *entry, *next;
>>> +
>>> + list_for_each_entry_safe(entry, next, head, list)
>>> + kfree(entry);
>>> +}
>>> +
>>> static struct iommu_ops arm_smmu_ops = {
>>> .capable = arm_smmu_capable,
>>> .domain_alloc = arm_smmu_domain_alloc,
>>> @@ -1560,6 +1610,8 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
>>> .domain_get_attr = arm_smmu_domain_get_attr,
>>> .domain_set_attr = arm_smmu_domain_set_attr,
>>> .of_xlate = arm_smmu_of_xlate,
>>> + .get_resv_regions = arm_smmu_get_resv_regions,
>>> + .put_resv_regions = arm_smmu_put_resv_regions,
>>> .pgsize_bitmap = -1UL, /* Restricted during device attach */
>>> };
>>>
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
^ permalink raw reply
* [RFC PATCH net-next v3 2/2] macb: Enable 1588 support in SAMA5Dx platforms.
From: Andrei Pistirica @ 2016-12-07 18:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481134912-2243-1-git-send-email-andrei.pistirica@microchip.com>
This patch does the following:
- Enable HW time stamp for the following platforms: SAMA5D2, SAMA5D3 and
SAMA5D4.
- HW time stamp capabilities are advertised via ethtool and macb ioctl is
updated accordingly.
- HW time stamp on the PTP Ethernet packets are received using the
SO_TIMESTAMPING API. Where timers are obtained from the PTP event/peer
registers.
Note: Patch on net-next, on December 7th.
Signed-off-by: Andrei Pistirica <andrei.pistirica@microchip.com>
---
Patch history:
Version 1:
Integration with SAMA5D2 only. This feature wasn't tested on any
other platform that might use cadence/gem.
Patch is not completely ported to the very latest version of net-next,
and it will be after review.
Version 2 modifications:
- add PTP caps for SAMA5D2/3/4 platforms
- and cosmetic changes
Version 3 modifications:
- add support for sama5D2/3/4 platforms using GEM-PTP interface.
drivers/net/ethernet/cadence/macb.c | 165 ++++++++++++++++++++++++++++++++++--
1 file changed, 160 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 538544a..e2d4983 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -714,6 +714,8 @@ static void macb_tx_interrupt(struct macb_queue *queue)
/* First, update TX stats if needed */
if (skb) {
+ gem_ptp_do_txstamp(bp, skb);
+
netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
macb_tx_ring_wrap(bp, tail),
skb->data);
@@ -878,6 +880,8 @@ static int gem_rx(struct macb *bp, int budget)
GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK)
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ gem_ptp_do_rxstamp(bp, skb);
+
bp->stats.rx_packets++;
bp->stats.rx_bytes += skb->len;
@@ -2080,6 +2084,9 @@ static int macb_open(struct net_device *dev)
netif_tx_start_all_queues(dev);
+ if (bp->ptp_info)
+ bp->ptp_info->ptp_init(dev);
+
return 0;
}
@@ -2101,6 +2108,9 @@ static int macb_close(struct net_device *dev)
macb_free_consistent(bp);
+ if (bp->ptp_info)
+ bp->ptp_info->ptp_remove(dev);
+
return 0;
}
@@ -2374,6 +2384,130 @@ static int macb_set_ringparam(struct net_device *netdev,
return 0;
}
+#ifdef CONFIG_MACB_USE_HWSTAMP
+static unsigned int gem_get_tsu_rate(struct macb *bp)
+{
+ /* Note: TSU rate is hardwired to PCLK. */
+ return clk_get_rate(bp->pclk);
+}
+
+static int gem_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ struct macb *bp = netdev_priv(dev);
+
+ ethtool_op_get_ts_info(dev, info);
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->phc_index = -1;
+
+ if (bp->ptp_clock)
+ info->phc_index = ptp_clock_index(bp->ptp_clock);
+
+ return 0;
+}
+
+static int gem_hwtst_set(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ struct hwtstamp_config config;
+ struct macb *priv = netdev_priv(netdev);
+ u32 regval;
+
+ netdev_vdbg(netdev, "macb_hwtstamp_ioctl\n");
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ priv->hwts_tx_en = false;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->hwts_tx_en = true;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ if (priv->hwts_rx_en)
+ priv->hwts_rx_en = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ regval = macb_readl(priv, NCR);
+ macb_writel(priv, NCR, (regval | MACB_BIT(SRTSM)));
+
+ if (!priv->hwts_rx_en)
+ priv->hwts_rx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+static int gem_hwtst_get(struct net_device *netdev,
+ struct ifreq *ifr)
+{
+ struct hwtstamp_config config;
+ struct macb *priv = netdev_priv(netdev);
+
+ config.flags = 0;
+ config.tx_type = priv->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+ config.rx_filter = (priv->hwts_rx_en ?
+ HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+static struct macb_ptp_info gem_ptp_info = {
+ .ptp_init = gem_ptp_init,
+ .ptp_remove = gem_ptp_remove,
+ .get_tsu_rate = gem_get_tsu_rate,
+ .get_ts_info = gem_get_ts_info,
+ .hwtst_get = gem_hwtst_get,
+ .hwtst_set = gem_hwtst_set,
+};
+#endif
+
+static int macb_get_ts_info(struct net_device *netdev,
+ struct ethtool_ts_info *info)
+{
+ struct macb *bp = netdev_priv(netdev);
+
+ if (bp->ptp_info)
+ return bp->ptp_info->get_ts_info(netdev, info);
+
+ return ethtool_op_get_ts_info(netdev, info);
+}
+
static const struct ethtool_ops macb_ethtool_ops = {
.get_regs_len = macb_get_regs_len,
.get_regs = macb_get_regs,
@@ -2391,7 +2525,7 @@ static const struct ethtool_ops gem_ethtool_ops = {
.get_regs_len = macb_get_regs_len,
.get_regs = macb_get_regs,
.get_link = ethtool_op_get_link,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = macb_get_ts_info,
.get_ethtool_stats = gem_get_ethtool_stats,
.get_strings = gem_get_ethtool_strings,
.get_sset_count = gem_get_sset_count,
@@ -2404,6 +2538,7 @@ static const struct ethtool_ops gem_ethtool_ops = {
static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct phy_device *phydev = dev->phydev;
+ struct macb *bp = netdev_priv(dev);
if (!netif_running(dev))
return -EINVAL;
@@ -2411,7 +2546,20 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, rq, cmd);
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ if (bp->ptp_info)
+ return bp->ptp_info->hwtst_set(dev, rq, cmd);
+
+ return -EOPNOTSUPP;
+ case SIOCGHWTSTAMP:
+ if (bp->ptp_info)
+ return bp->ptp_info->hwtst_get(dev, rq);
+
+ return -EOPNOTSUPP;
+ default:
+ return phy_mii_ioctl(phydev, rq, cmd);
+ }
}
static int macb_set_features(struct net_device *netdev,
@@ -2485,6 +2633,12 @@ static void macb_configure_caps(struct macb *bp,
dcfg = gem_readl(bp, DCFG2);
if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0)
bp->caps |= MACB_CAPS_FIFO_MODE;
+
+ /* iff HWSTAMP is configure and gem has the capability */
+#ifdef CONFIG_MACB_USE_HWSTAMP
+ if (gem_has_ptp(bp))
+ bp->ptp_info = &gem_ptp_info;
+#endif
}
dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps);
@@ -3041,7 +3195,7 @@ static const struct macb_config pc302gem_config = {
};
static const struct macb_config sama5d2_config = {
- .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+ .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_GEM_HAS_PTP,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init,
@@ -3049,14 +3203,15 @@ static const struct macb_config sama5d2_config = {
static const struct macb_config sama5d3_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE
- | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+ | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII
+ | MACB_CAPS_GEM_HAS_PTP,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init,
};
static const struct macb_config sama5d4_config = {
- .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+ .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_GEM_HAS_PTP,
.dma_burst_length = 4,
.clk_init = macb_clk_init,
.init = macb_init,
--
2.7.4
^ permalink raw reply related
* [RFC PATCH net-next v3 1/2] macb: Add 1588 support in Cadence GEM.
From: Andrei Pistirica @ 2016-12-07 18:21 UTC (permalink / raw)
To: linux-arm-kernel
Cadence GEM provides a 102 bit time counter with 48 bits for seconds,
30 bits for nsecs and 24 bits for sub-nsecs to control 1588 timestamping.
This patch does the following:
- Registers to ptp clock framework
- Timer initialization is done by writing time of day to the timer counter.
- ns increment register is programmed as NSEC_PER_SEC/tsu-clock-rate.
For a 16 bit subns precision, the subns increment equals
remainder of (NS_PER_SEC/TSU_CLK) * (2^16).
- Timestamps are obtained from the TX/RX PTP event/PEER registers.
The timestamp obtained thus is updated in skb for upper layers to access.
- The drivers register functions with ptp to perform time and frequency
adjustment.
- Time adjustment is done by writing to the 1558_ADJUST register.
The controller will read the delta in this register and update the timer
counter register. Alternatively, for large time offset adjustments,
the driver reads the secs and nsecs counter values, adds/subtracts the
delta and updates the timer counter.
- Frequency is adjusted by adjusting addend (8bit nanosecond increment) and
addendsub (16bit increment nanosecond fractions).
The 102bit counter is incremented at nominal frequency with addend and
addendsub values. Each period addend and addendsub values are adjusted
based on ppm drift.
Signed-off-by: Andrei Pistirica <andrei.pistirica@microchip.com>
Signed-off-by: Harini Katakam <harinik@xilinx.com>
---
Patch history:
Version 1:
This patch is based on original Harini's patch, implemented in a
separate file to ease the review/maintanance and integration with
other platforms (e.g. Zynq Ultrascale+ MPSoC).
Feature was tested on SAMA5D2 platform using ptp4l v1.6 from linuxptp
project and also with ptpd2 version 2.3.1. PTP was tested over
IPv4,IPv6 and 802.3 protocols.
In case that macb is compiled as a module, it has been renamed to
cadence-macb.ko to avoid naming confusion in Makefile.
Version 2 modifications:
- bitfields for TSU are named according to SAMA5D2 data sheet
- identify GEM-PTP support based on platform capability
- add spinlock for TSU access
- change macb_ptp_adjfreq and use fewer 64bit divisions
Version 3 modifications:
- new adjfine api with one 64 division for frequency adjustment
(based on Richard's input)
- add maximum adjustment frequency (ppb) based on nominal frequency
- per platform PTP configuration
- cosmetic changes
Note 1: Kbuild uses "select" instead of "imply", and the macb maintainer agreed
to make the change when it will be available in net-next.
Note 2: Guys, this driver does not support GEM-GXL!
Note 3: Patch on net-next, on December 7th.
drivers/net/ethernet/cadence/Kconfig | 10 +-
drivers/net/ethernet/cadence/Makefile | 8 +-
drivers/net/ethernet/cadence/macb.h | 102 +++++++++
drivers/net/ethernet/cadence/macb_ptp.c | 390 ++++++++++++++++++++++++++++++++
4 files changed, 508 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/cadence/macb_ptp.c
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index f0bcb15..ebbc65f 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -29,6 +29,14 @@ config MACB
support for the MACB/GEM chip.
To compile this driver as a module, choose M here: the module
- will be called macb.
+ will be called cadence-macb.
+
+config MACB_USE_HWSTAMP
+ bool "Use IEEE 1588 hwstamp"
+ depends on MACB
+ default y
+ select PTP_1588_CLOCK
+ ---help---
+ Enable IEEE 1588 Precision Time Protocol (PTP) support for MACB.
endif # NET_CADENCE
diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1..4402d42 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -2,4 +2,10 @@
# Makefile for the Atmel network device drivers.
#
-obj-$(CONFIG_MACB) += macb.o
+cadence-macb-y := macb.o
+
+ifeq ($(CONFIG_MACB_USE_HWSTAMP),y)
+cadence-macb-y += macb_ptp.o
+endif
+
+obj-$(CONFIG_MACB) += cadence-macb.o
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index d67adad..b3688f1 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -10,6 +10,9 @@
#ifndef _MACB_H
#define _MACB_H
+#include <linux/ptp_clock.h>
+#include <linux/ptp_clock_kernel.h>
+
#define MACB_GREGS_NBR 16
#define MACB_GREGS_VERSION 2
#define MACB_MAX_QUEUES 8
@@ -131,6 +134,20 @@
#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum Error Counter */
#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error Counter */
#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error Counter */
+#define GEM_TISUBN 0x01bc /* 1588 Timer Increment Sub-ns */
+#define GEM_TSH 0x01c0 /* 1588 Timer Seconds High */
+#define GEM_TSL 0x01d0 /* 1588 Timer Seconds Low */
+#define GEM_TN 0x01d4 /* 1588 Timer Nanoseconds */
+#define GEM_TA 0x01d8 /* 1588 Timer Adjust */
+#define GEM_TI 0x01dc /* 1588 Timer Increment */
+#define GEM_EFTSL 0x01e0 /* PTP Event Frame Tx Seconds Low */
+#define GEM_EFTN 0x01e4 /* PTP Event Frame Tx Nanoseconds */
+#define GEM_EFRSL 0x01e8 /* PTP Event Frame Rx Seconds Low */
+#define GEM_EFRN 0x01ec /* PTP Event Frame Rx Nanoseconds */
+#define GEM_PEFTSL 0x01f0 /* PTP Peer Event Frame Tx Secs Low */
+#define GEM_PEFTN 0x01f4 /* PTP Peer Event Frame Tx Ns */
+#define GEM_PEFRSL 0x01f8 /* PTP Peer Event Frame Rx Sec Low */
+#define GEM_PEFRN 0x01fc /* PTP Peer Event Frame Rx Ns */
#define GEM_DCFG1 0x0280 /* Design Config 1 */
#define GEM_DCFG2 0x0284 /* Design Config 2 */
#define GEM_DCFG3 0x0288 /* Design Config 3 */
@@ -174,6 +191,7 @@
#define MACB_NCR_TPF_SIZE 1
#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */
#define MACB_TZQ_SIZE 1
+#define MACB_SRTSM_OFFSET 15
/* Bitfields in NCFGR */
#define MACB_SPD_OFFSET 0 /* Speed */
@@ -319,6 +337,32 @@
#define MACB_PTZ_SIZE 1
#define MACB_WOL_OFFSET 14 /* Enable wake-on-lan interrupt */
#define MACB_WOL_SIZE 1
+#define MACB_DRQFR_OFFSET 18 /* PTP Delay Request Frame Received */
+#define MACB_DRQFR_SIZE 1
+#define MACB_SFR_OFFSET 19 /* PTP Sync Frame Received */
+#define MACB_SFR_SIZE 1
+#define MACB_DRQFT_OFFSET 20 /* PTP Delay Request Frame Transmitted */
+#define MACB_DRQFT_SIZE 1
+#define MACB_SFT_OFFSET 21 /* PTP Sync Frame Transmitted */
+#define MACB_SFT_SIZE 1
+#define MACB_PDRQFR_OFFSET 22 /* PDelay Request Frame Received */
+#define MACB_PDRQFR_SIZE 1
+#define MACB_PDRSFR_OFFSET 23 /* PDelay Response Frame Received */
+#define MACB_PDRSFR_SIZE 1
+#define MACB_PDRQFT_OFFSET 24 /* PDelay Request Frame Transmitted */
+#define MACB_PDRQFT_SIZE 1
+#define MACB_PDRSFT_OFFSET 25 /* PDelay Response Frame Transmitted */
+#define MACB_PDRSFT_SIZE 1
+#define MACB_SRI_OFFSET 26 /* TSU Seconds Register Increment */
+#define MACB_SRI_SIZE 1
+
+/* Timer increment fields */
+#define MACB_TI_CNS_OFFSET 0
+#define MACB_TI_CNS_SIZE 8
+#define MACB_TI_ACNS_OFFSET 8
+#define MACB_TI_ACNS_SIZE 8
+#define MACB_TI_NIT_OFFSET 16
+#define MACB_TI_NIT_SIZE 8
/* Bitfields in MAN */
#define MACB_DATA_OFFSET 0 /* data */
@@ -386,6 +430,17 @@
#define GEM_PBUF_LSO_OFFSET 27
#define GEM_PBUF_LSO_SIZE 1
+/* Bitfields in TISUBN */
+#define GEM_SUBNSINCR_OFFSET 0
+#define GEM_SUBNSINCR_SIZE 16
+
+/* Bitfields in TI */
+#define GEM_NSINCR_OFFSET 0
+#define GEM_NSINCR_SIZE 8
+
+/* Bitfields in ADJ */
+#define GEM_ADDSUB_OFFSET 31
+#define GEM_ADDSUB_SIZE 1
/* Constants for CLK */
#define MACB_CLK_DIV8 0
#define MACB_CLK_DIV16 1
@@ -417,6 +472,7 @@
#define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000
#define MACB_CAPS_SG_DISABLED 0x40000000
#define MACB_CAPS_MACB_IS_GEM 0x80000000
+#define MACB_CAPS_GEM_HAS_PTP 0x00000020
/* LSO settings */
#define MACB_LSO_UFO_ENABLE 0x01
@@ -782,6 +838,19 @@ struct macb_or_gem_ops {
int (*mog_rx)(struct macb *bp, int budget);
};
+/* MACB-PTP interface: adapt to platform needs and GEM (e.g. GXL). */
+struct macb_ptp_info {
+ void (*ptp_init)(struct net_device *ndev);
+ void (*ptp_remove)(struct net_device *ndev);
+ unsigned int (*get_tsu_rate)(struct macb *bp);
+ int (*get_ts_info)(struct net_device *dev,
+ struct ethtool_ts_info *info);
+ int (*hwtst_get)(struct net_device *netdev,
+ struct ifreq *ifr);
+ int (*hwtst_set)(struct net_device *netdev,
+ struct ifreq *ifr, int cmd);
+};
+
struct macb_config {
u32 caps;
unsigned int dma_burst_length;
@@ -874,11 +943,44 @@ struct macb {
unsigned int jumbo_max_len;
u32 wol;
+
+ struct macb_ptp_info *ptp_info;
+#ifdef CONFIG_MACB_USE_HWSTAMP
+ bool hwts_tx_en;
+ bool hwts_rx_en;
+ spinlock_t tsu_clk_lock; /* gem tsu clock locking */
+ unsigned int tsu_rate;
+
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_caps;
+ u32 ns_incr;
+ u32 subns_incr;
+#endif
};
+#ifdef CONFIG_MACB_USE_HWSTAMP
+void gem_ptp_init(struct net_device *ndev);
+void gem_ptp_remove(struct net_device *ndev);
+
+void gem_ptp_do_txstamp(struct macb *bp, struct sk_buff *skb);
+void gem_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb);
+
+#else
+static inline void gem_ptp_init(struct net_device *ndev) { }
+static inline void gem_ptp_remove(struct net_device *ndev) { }
+
+static inline void gem_ptp_do_txstamp(struct macb *bp, struct sk_buff *skb) { }
+static inline void gem_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb) { }
+#endif
+
static inline bool macb_is_gem(struct macb *bp)
{
return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
}
+static inline bool gem_has_ptp(struct macb *bp)
+{
+ return !!(bp->caps & MACB_CAPS_GEM_HAS_PTP);
+}
+
#endif /* _MACB_H */
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
new file mode 100644
index 0000000..efefd9e
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -0,0 +1,390 @@
+/*
+ * 1588 PTP support for GEM device.
+ *
+ * Copyright (C) 2016 Microchip Technology
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/time64.h>
+#include <linux/ptp_classify.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/net_tstamp.h>
+
+#include "macb.h"
+
+#define GEM_PTP_TIMER_NAME "gem-ptp-timer"
+
+static inline void gem_tsu_get_time(struct macb *bp,
+ struct timespec64 *ts)
+{
+ u64 sec, sech, secl;
+
+ spin_lock(&bp->tsu_clk_lock);
+
+ /* GEM's internal time */
+ sech = gem_readl(bp, TSH);
+ secl = gem_readl(bp, TSL);
+ ts->tv_nsec = gem_readl(bp, TN);
+ ts->tv_sec = (sech << 32) | secl;
+
+ /* minimize error */
+ sech = gem_readl(bp, TSH);
+ secl = gem_readl(bp, TSL);
+ sec = (sech << 32) | secl;
+ if (ts->tv_sec != sec) {
+ ts->tv_sec = sec;
+ ts->tv_nsec = gem_readl(bp, TN);
+ }
+
+ spin_unlock(&bp->tsu_clk_lock);
+}
+
+static inline void gem_tsu_set_time(struct macb *bp,
+ const struct timespec64 *ts)
+{
+ u32 ns, sech, secl;
+ s64 word_mask = 0xffffffff;
+
+ sech = (u32)ts->tv_sec;
+ secl = (u32)ts->tv_sec;
+ ns = ts->tv_nsec;
+ if (ts->tv_sec > word_mask)
+ sech = (ts->tv_sec >> 32);
+
+ spin_lock(&bp->tsu_clk_lock);
+
+ /* TSH doesn't latch the time and no atomicity! */
+ gem_writel(bp, TN, 0); /* clear to avoid overflow */
+ gem_writel(bp, TSH, sech);
+ gem_writel(bp, TSL, secl);
+ gem_writel(bp, TN, ns);
+
+ spin_unlock(&bp->tsu_clk_lock);
+}
+
+static int gem_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+ u32 word, diff;
+ u64 adj, rate;
+ int neg_adj = 0;
+
+ if (scaled_ppm < 0) {
+ neg_adj = 1;
+ scaled_ppm = -scaled_ppm;
+ }
+ rate = scaled_ppm;
+
+ /* word: unused(8bit) | ns(8bit) | fractions(16bit) */
+ word = (bp->ns_incr << 16) + bp->subns_incr;
+
+ adj = word;
+ adj *= rate;
+ adj >>= 16; /* remove fractions */
+ adj += 500000UL;
+ diff = div_u64(adj, 1000000UL);
+ word = neg_adj ? word - diff : word + diff;
+
+ spin_lock(&bp->tsu_clk_lock);
+
+ gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, (word & 0xffff)));
+ gem_writel(bp, TI, GEM_BF(NSINCR, (word >> 16)));
+
+ spin_unlock(&bp->tsu_clk_lock);
+ return 0;
+}
+
+static int gem_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+ struct timespec64 now, then = ns_to_timespec64(delta);
+ u32 adj, sign = 0;
+
+ if (delta < 0) {
+ delta = -delta;
+ sign = 1;
+ }
+
+ if (delta > 0x3FFFFFFF) {
+ gem_tsu_get_time(bp, &now);
+
+ if (sign)
+ now = timespec64_sub(now, then);
+ else
+ now = timespec64_add(now, then);
+
+ gem_tsu_set_time(bp, (const struct timespec64 *)&now);
+ } else {
+ adj = delta;
+ if (sign)
+ adj |= GEM_BIT(ADDSUB);
+
+ gem_writel(bp, TA, adj);
+ }
+
+ return 0;
+}
+
+static int gem_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+
+ gem_tsu_get_time(bp, ts);
+
+ return 0;
+}
+
+static int gem_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+
+ gem_tsu_set_time(bp, ts);
+
+ return 0;
+}
+
+static int gem_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info gem_ptp_caps_template = {
+ .owner = THIS_MODULE,
+ .name = GEM_PTP_TIMER_NAME,
+ .max_adj = 0,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .n_pins = 0,
+ .pps = 0,
+ .adjfine = gem_ptp_adjfine,
+ .adjtime = gem_ptp_adjtime,
+ .gettime64 = gem_ptp_gettime,
+ .settime64 = gem_ptp_settime,
+ .enable = gem_ptp_enable,
+};
+
+static s32 gem_ptp_max_adj(unsigned int f_nom)
+{
+ u64 adj;
+
+ /* The 48 bits of seconds for the GEM overflows every:
+ * 2^48/(365.25 * 24 * 60 *60) =~ 8 925 512 years (~= 9 mil years),
+ * thus the maximum adjust frequency must not overflow CNS register:
+ *
+ * addend = 10^9/nominal_freq
+ * adj_max = +/- addend*ppb_max/10^9
+ * max_ppb = (2^8-1)*nominal_freq-10^9
+ */
+ adj = f_nom;
+ adj *= 0xffff;
+ adj -= 1000000000ULL;
+ return adj;
+}
+
+static void gem_ptp_init_timer(struct macb *bp)
+{
+ struct timespec64 now;
+ u32 rem = 0;
+
+ getnstimeofday64(&now);
+ gem_tsu_set_time(bp, (const struct timespec64 *)&now);
+
+ bp->ns_incr = div_u64_rem(NSEC_PER_SEC, bp->tsu_rate, &rem);
+ if (rem) {
+ u64 adj = rem;
+
+ adj <<= 16; /* 16 bits nsec fragments */
+ bp->subns_incr = div_u64(adj, bp->tsu_rate);
+ } else {
+ bp->subns_incr = 0;
+ }
+
+ gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, bp->subns_incr));
+ gem_writel(bp, TI, GEM_BF(NSINCR, bp->ns_incr));
+ gem_writel(bp, TA, 0);
+}
+
+static void gem_ptp_clear_timer(struct macb *bp)
+{
+ bp->ns_incr = 0;
+ bp->subns_incr = 0;
+
+ gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, 0));
+ gem_writel(bp, TI, GEM_BF(NSINCR, 0));
+ gem_writel(bp, TA, 0);
+}
+
+/* While GEM can timestamp PTP packets, it does not mark the RX descriptor
+ * to identify them. UDP packets must be parsed to identify PTP packets.
+ *
+ * Note: Inspired from drivers/net/ethernet/ti/cpts.c
+ */
+static int gem_get_ptp_peer(struct sk_buff *skb, int ptp_class)
+{
+ unsigned int offset = 0;
+ u8 *msgtype, *data = skb->data;
+
+ /* PTP frames are rare! */
+ if (likely(ptp_class == PTP_CLASS_NONE))
+ return -1;
+
+ if (ptp_class & PTP_CLASS_VLAN)
+ offset += VLAN_HLEN;
+
+ switch (ptp_class & PTP_CLASS_PMASK) {
+ case PTP_CLASS_IPV4:
+ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;
+ break;
+ case PTP_CLASS_IPV6:
+ offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;
+ break;
+ case PTP_CLASS_L2:
+ offset += ETH_HLEN;
+ break;
+
+ /* something went wrong! */
+ default:
+ return -1;
+ }
+
+ if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID)
+ return -1;
+
+ if (unlikely(ptp_class & PTP_CLASS_V1))
+ msgtype = data + offset + OFF_PTP_CONTROL;
+ else
+ msgtype = data + offset;
+
+ return (*msgtype) & 0x2;
+}
+
+static void gem_ptp_tx_hwtstamp(struct macb *bp, struct sk_buff *skb,
+ int peer_ev)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ struct timespec64 ts;
+ u64 ns;
+
+ /* PTP Peer Event Frame packets */
+ if (peer_ev) {
+ ts.tv_sec = gem_readl(bp, PEFTSL);
+ ts.tv_nsec = gem_readl(bp, PEFTN);
+
+ /* PTP Event Frame packets */
+ } else {
+ ts.tv_sec = gem_readl(bp, EFTSL);
+ ts.tv_nsec = gem_readl(bp, EFTN);
+ }
+ ns = timespec64_to_ns(&ts);
+
+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ns);
+ skb_tstamp_tx(skb, skb_hwtstamps(skb));
+}
+
+static void gem_ptp_rx_hwtstamp(struct macb *bp, struct sk_buff *skb,
+ int peer_ev)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ struct timespec64 ts;
+ u64 ns;
+
+ if (peer_ev) {
+ /* PTP Peer Event Frame packets */
+ ts.tv_sec = gem_readl(bp, PEFRSL);
+ ts.tv_nsec = gem_readl(bp, PEFRN);
+ } else {
+ /* PTP Event Frame packets */
+ ts.tv_sec = gem_readl(bp, EFRSL);
+ ts.tv_nsec = gem_readl(bp, EFRN);
+ }
+ ns = timespec64_to_ns(&ts);
+
+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+
+/* no static, GEM PTP interface functions */
+void gem_ptp_do_txstamp(struct macb *bp, struct sk_buff *skb)
+{
+ if (!bp->hwts_tx_en)
+ return;
+
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ int class = ptp_classify_raw(skb);
+ int peer;
+
+ peer = gem_get_ptp_peer(skb, class);
+ if (peer < 0)
+ return;
+
+ /* Timestamp this packet */
+ gem_ptp_tx_hwtstamp(bp, skb, peer);
+ }
+}
+
+void gem_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb)
+{
+ int class, peer;
+
+ if (!bp->hwts_rx_en)
+ return;
+
+ __skb_push(skb, ETH_HLEN);
+ class = ptp_classify_raw(skb);
+ __skb_pull(skb, ETH_HLEN);
+
+ peer = gem_get_ptp_peer(skb, class);
+ if (peer < 0)
+ return;
+
+ gem_ptp_rx_hwtstamp(bp, skb, peer);
+}
+
+void gem_ptp_init(struct net_device *ndev)
+{
+ struct macb *bp = netdev_priv(ndev);
+
+ spin_lock_init(&bp->tsu_clk_lock);
+ bp->ptp_caps = gem_ptp_caps_template;
+
+ /* nominal frequency and maximum adjustment in ppb */
+ bp->tsu_rate = bp->ptp_info->get_tsu_rate(bp);
+ bp->ptp_caps.max_adj = gem_ptp_max_adj(bp->tsu_rate);
+
+ gem_ptp_init_timer(bp);
+
+ bp->ptp_clock = ptp_clock_register(&bp->ptp_caps, NULL);
+ if (IS_ERR(&bp->ptp_clock)) {
+ bp->ptp_clock = NULL;
+ pr_err("ptp clock register failed\n");
+ return;
+ }
+
+ dev_info(&bp->pdev->dev, "%s ptp clock registered.\n",
+ GEM_PTP_TIMER_NAME);
+}
+
+void gem_ptp_remove(struct net_device *ndev)
+{
+ struct macb *bp = netdev_priv(ndev);
+
+ if (bp->ptp_clock)
+ ptp_clock_unregister(bp->ptp_clock);
+
+ gem_ptp_clear_timer(bp);
+
+ dev_info(&bp->pdev->dev, "%s ptp clock unregistered.\n",
+ GEM_PTP_TIMER_NAME);
+}
--
2.7.4
^ permalink raw reply related
* [PATCH v2 1/2] firmware: arm_scpi: zero RX buffer before requesting data from the mbox
From: Sudeep Holla @ 2016-12-07 18:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125005432.1205-2-martin.blumenstingl@googlemail.com>
On 25/11/16 00:54, Martin Blumenstingl wrote:
> The original code was relying on the fact that the SCPI firmware
> responds with the same number of bytes (or more, all extra data would be
> ignored in that case) as requested.
> However, we have some pre-v1.0 SCPI firmwares which are responding with
> less data for some commands (sensor_value.hi_val did not exist in the
> old implementation). This means that some data from the previous
> command's RX buffer was leaked into the current command (as the RX
> buffer is re-used for all commands on the same channel). Clearing the
> RX buffer before (re-) using it ensures we get a consistent result, even
> if the SCPI firmware returns less bytes than requested.
>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
> drivers/firmware/arm_scpi.c | 19 ++++++++++++++++++-
> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
> index 70e1323..8c183d8 100644
> --- a/drivers/firmware/arm_scpi.c
> +++ b/drivers/firmware/arm_scpi.c
> @@ -259,6 +259,7 @@ struct scpi_chan {
> struct mbox_chan *chan;
> void __iomem *tx_payload;
> void __iomem *rx_payload;
> + resource_size_t max_payload_len;
> struct list_head rx_pending;
> struct list_head xfers_list;
> struct scpi_xfer *xfers;
> @@ -470,6 +471,20 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
> if (t->rx_buf) {
> if (!(++ch->token))
> ++ch->token;
> +
> + /* clear the RX buffer as it is shared across all commands on
> + * the same channel (to make sure we're not leaking data from
> + * the previous response into the current command if the SCPI
> + * firmware writes less data than requested).
> + * This is especially important for pre-v1.0 SCPI firmwares
> + * where some fields in the responses do not exist (while they
> + * exist but are optional in newer versions). One example for
> + * this problem is sensor_value.hi_val, which would contain
> + * ("leak") the second 4 bytes of the RX buffer from the
> + * previous command.
> + */
> + memset_io(ch->rx_payload, 0, ch->max_payload_len);
> +
This looks like a overkill to me. I prefer your first approach over
this, if it's only this command that's affected. I am still not sure
why Neil Armstrong mentioned that it worked for him with 64-bit read.
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH V8 3/3] irqchip: qcom: Add IRQ combiner driver
From: Marc Zyngier @ 2016-12-07 18:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480460259-8585-4-git-send-email-agustinv@codeaurora.org>
Hi Agustin,
On 29/11/16 22:57, Agustin Vega-Frias wrote:
> Driver for interrupt combiners in the Top-level Control and Status
> Registers (TCSR) hardware block in Qualcomm Technologies chips.
>
> An interrupt combiner in this block combines a set of interrupts by
> OR'ing the individual interrupt signals into a summary interrupt
> signal routed to a parent interrupt controller, and provides read-
> only, 32-bit registers to query the status of individual interrupts.
> The status bit for IRQ n is bit (n % 32) within register (n / 32)
> of the given combiner. Thus, each combiner can be described as a set
> of register offsets and the number of IRQs managed.
>
> Signed-off-by: Agustin Vega-Frias <agustinv@codeaurora.org>
> ---
> drivers/irqchip/Kconfig | 8 +
> drivers/irqchip/Makefile | 1 +
> drivers/irqchip/qcom-irq-combiner.c | 337 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 346 insertions(+)
> create mode 100644 drivers/irqchip/qcom-irq-combiner.c
>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index bc0af33..610f902 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -279,3 +279,11 @@ config EZNPS_GIC
> config STM32_EXTI
> bool
> select IRQ_DOMAIN
> +
> +config QCOM_IRQ_COMBINER
> + bool "QCOM IRQ combiner support"
> + depends on ARCH_QCOM
> + select IRQ_DOMAIN
> + help
> + Say yes here to add support for the IRQ combiner devices embedded
> + in Qualcomm Technologies chips.
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index e4dbfc8..1818a0b 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -74,3 +74,4 @@ obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
> obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
> obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
> obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
> +obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
> diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c
> new file mode 100644
> index 0000000..fc25251
> --- /dev/null
> +++ b/drivers/irqchip/qcom-irq-combiner.c
> @@ -0,0 +1,337 @@
> +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +/*
> + * Driver for interrupt combiners in the Top-level Control and Status
> + * Registers (TCSR) hardware block in Qualcomm Technologies chips.
> + * An interrupt combiner in this block combines a set of interrupts by
> + * OR'ing the individual interrupt signals into a summary interrupt
> + * signal routed to a parent interrupt controller, and provides read-
> + * only, 32-bit registers to query the status of individual interrupts.
> + * The status bit for IRQ n is bit (n % 32) within register (n / 32)
> + * of the given combiner. Thus, each combiner can be described as a set
> + * of register offsets and the number of IRQs managed.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/platform_device.h>
> +
> +#define REG_SIZE 32
> +
> +struct combiner_reg {
> + void __iomem *addr;
> + unsigned long mask;
> +};
> +
> +struct combiner {
> + struct irq_chip irq_chip;
> + struct irq_domain *domain;
> + int parent_irq;
> + u32 nirqs;
> + u32 nregs;
> + struct combiner_reg regs[0];
> +};
> +
> +static inline u32 irq_register(int irq)
> +{
> + return irq / REG_SIZE;
> +}
> +
> +static inline u32 irq_bit(int irq)
> +{
> + return irq % REG_SIZE;
> +
> +}
> +
> +static inline int irq_nr(u32 reg, u32 bit)
> +{
> + return reg * REG_SIZE + bit;
> +}
> +
> +/*
> + * Handler for the cascaded IRQ.
> + */
> +static void combiner_handle_irq(struct irq_desc *desc)
> +{
> + struct combiner *combiner = irq_desc_get_handler_data(desc);
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> + u32 reg;
> +
> + chained_irq_enter(chip, desc);
> +
> + for (reg = 0; reg < combiner->nregs; reg++) {
> + int virq;
> + int hwirq;
> + u32 bit;
> + u32 status;
> +
> + if (combiner->regs[reg].mask == 0)
> + continue;
> +
> + status = readl_relaxed(combiner->regs[reg].addr);
> + status &= combiner->regs[reg].mask;
> +
> + while (status) {
> + bit = __ffs(status);
> + status &= ~(1 << bit);
> + hwirq = irq_nr(reg, bit);
> + virq = irq_find_mapping(combiner->domain, hwirq);
> + if (virq >= 0)
> + generic_handle_irq(virq);
> +
> + }
> + }
> +
> + chained_irq_exit(chip, desc);
> +}
> +
> +/*
> + * irqchip callbacks
> + */
> +
> +static void combiner_irq_chip_mask_irq(struct irq_data *data)
> +{
> + struct combiner *combiner = irq_data_get_irq_chip_data(data);
> + struct combiner_reg *reg = combiner->regs + irq_register(data->hwirq);
> +
> + clear_bit(irq_bit(data->hwirq), ®->mask);
> +}
> +
> +static void combiner_irq_chip_unmask_irq(struct irq_data *data)
> +{
> + struct combiner *combiner = irq_data_get_irq_chip_data(data);
> + struct combiner_reg *reg = combiner->regs + irq_register(data->hwirq);
> +
> + set_bit(irq_bit(data->hwirq), ®->mask);
> +}
> +
> +/*
> + * irq_domain_ops callbacks
> + */
> +
> +static int combiner_irq_map(struct irq_domain *domain, unsigned int irq,
> + irq_hw_number_t hwirq)
> +{
> + struct combiner *combiner = domain->host_data;
> +
> + if (hwirq >= combiner->nirqs)
> + return -EINVAL;
> +
> + irq_set_chip_and_handler(irq, &combiner->irq_chip, handle_level_irq);
> + irq_set_chip_data(irq, combiner);
> + irq_set_parent(irq, combiner->parent_irq);
Do you really need this irq_set_parent? This only makes sense if you're
resending edge interrupts, and you seem to be level only.
> + irq_set_noprobe(irq);
> + return 0;
> +}
> +
> +static void combiner_irq_unmap(struct irq_domain *domain, unsigned int irq)
> +{
> + irq_set_chip_and_handler(irq, NULL, NULL);
> + irq_set_chip_data(irq, NULL);
> + irq_set_parent(irq, -1);
All of this should probably be replaced with a call to
irq_domain_reset_irq_data().
> +}
> +
> +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
Is there any case where this is not valid?
> +static int combiner_irq_translate(struct irq_domain *d, struct irq_fwspec *fws,
> + unsigned long *hwirq, unsigned int *type)
> +{
> + if (is_acpi_node(fws->fwnode)) {
> + if (fws->param_count != 2)
> + return -EINVAL;
> +
> + *hwirq = fws->param[0];
> + *type = fws->param[1];
Given that you're only handling level interrupts, shouldn't you abort if
detecting an edge interrupt?
> + return 0;
> + }
> +
> + return -EINVAL;
> +}
> +#endif
> +
> +static const struct irq_domain_ops domain_ops = {
> + .map = combiner_irq_map,
> + .unmap = combiner_irq_unmap,
> +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
> + .translate = combiner_irq_translate
> +#endif
> +};
> +
> +/*
> + * Device probing
> + */
> +
> +#ifdef CONFIG_ACPI
> +
> +static acpi_status count_registers_cb(struct acpi_resource *ares, void *context)
> +{
> + int *count = context;
> +
> + if (ares->type == ACPI_RESOURCE_TYPE_GENERIC_REGISTER)
> + ++(*count);
> + return AE_OK;
> +}
> +
> +static int count_registers(struct platform_device *pdev)
> +{
> + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
> + acpi_status status;
> + int count = 0;
> +
> + if (!acpi_has_method(adev->handle, METHOD_NAME__CRS))
> + return -EINVAL;
> +
> + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
> + count_registers_cb, &count);
> + if (ACPI_FAILURE(status))
> + return -EINVAL;
> + return count;
> +}
> +
> +struct get_registers_context {
> + struct device *dev;
> + struct combiner *combiner;
> + int err;
> +};
> +
> +static acpi_status get_registers_cb(struct acpi_resource *ares, void *context)
> +{
> + struct get_registers_context *ctx = context;
> + struct acpi_resource_generic_register *reg;
> + phys_addr_t paddr;
> + void __iomem *vaddr;
> +
> + if (ares->type != ACPI_RESOURCE_TYPE_GENERIC_REGISTER)
> + return AE_OK;
> +
> + reg = &ares->data.generic_reg;
> + paddr = reg->address;
> + if ((reg->space_id != ACPI_SPACE_MEM) ||
> + (reg->bit_offset != 0) ||
> + (reg->bit_width > REG_SIZE)) {
> + dev_err(ctx->dev, "Bad register resource @%pa\n", &paddr);
> + ctx->err = -EINVAL;
> + return AE_ERROR;
> + }
> +
> + vaddr = devm_ioremap(ctx->dev, reg->address, REG_SIZE);
> + if (IS_ERR(vaddr)) {
> + dev_err(ctx->dev, "Can't map register @%pa\n", &paddr);
> + ctx->err = PTR_ERR(vaddr);
> + return AE_ERROR;
> + }
> +
> + ctx->combiner->regs[ctx->combiner->nregs].addr = vaddr;
> + ctx->combiner->nirqs += reg->bit_width;
> + ctx->combiner->nregs++;
> + return AE_OK;
> +}
> +
> +static int get_registers(struct platform_device *pdev, struct combiner *comb)
> +{
> + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
> + acpi_status status;
> + struct get_registers_context ctx;
> +
> + if (!acpi_has_method(adev->handle, METHOD_NAME__CRS))
> + return -EINVAL;
> +
> + ctx.dev = &pdev->dev;
> + ctx.combiner = comb;
> + ctx.err = 0;
> +
> + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
> + get_registers_cb, &ctx);
> + if (ACPI_FAILURE(status))
> + return ctx.err;
> + return 0;
> +}
> +
> +#else /* !CONFIG_ACPI */
> +
> +static int count_registers(struct platform_device *pdev)
> +{
> + return -EINVAL;
> +}
> +
> +static int get_registers(struct platform_device *pdev, struct combiner *comb)
> +{
> + return -EINVAL;
> +}
So this driver is obviously ACPI only. Can't you just get rid of these,
of the #ifdef CONFIG_ACPI, and simply make it depend on ACPI?
> +
> +#endif
> +
> +static int __init combiner_probe(struct platform_device *pdev)
> +{
> + struct combiner *combiner;
> + size_t alloc_sz;
> + u32 nregs;
> + int err;
> +
> + nregs = count_registers(pdev);
> + if (nregs <= 0) {
> + dev_err(&pdev->dev, "Error reading register resources\n");
> + return -EINVAL;
> + }
> +
> + alloc_sz = sizeof(*combiner) + sizeof(struct combiner_reg) * nregs;
> + combiner = devm_kzalloc(&pdev->dev, alloc_sz, GFP_KERNEL);
> + if (!combiner)
> + return -ENOMEM;
> +
> + err = get_registers(pdev, combiner);
> + if (err < 0)
> + return err;
> +
> + combiner->parent_irq = platform_get_irq(pdev, 0);
> + if (combiner->parent_irq <= 0) {
> + dev_err(&pdev->dev, "Error getting IRQ resource\n");
> + return -EINVAL;
Can you ever get in a situation where it'd be more sensible to return
-EPROBE_DEFER? I'm thinking of a case where you'd have this irq chip
cascaded into another one, which is not present yet?
> + }
> +
> + combiner->domain = irq_domain_create_linear(
> + pdev->dev.fwnode, combiner->nirqs, &domain_ops, combiner);
On a single line, please. Do no listen to the checkpatch police that
will tell you otherwise. It really hurt my eyes to see this opening
bracket and *nothing* after that.
> + if (!combiner->domain)
> + /* Errors printed by irq_domain_create_linear */
> + return -ENODEV;
> +
> + irq_set_chained_handler_and_data(combiner->parent_irq,
> + combiner_handle_irq, combiner);
> + combiner->irq_chip.irq_mask = combiner_irq_chip_mask_irq;
> + combiner->irq_chip.irq_unmask = combiner_irq_chip_unmask_irq;
> + combiner->irq_chip.name = pdev->name;
Arghh. Please don't do that. Once you've called irq_set_chained_*, the
interrupt is live, and can be requested. Unlikely, but still. In
general, feeding uninitialized data to a function is pretty bad.
Also, do you really need to show pdev->name in /proc/cpuinfo? Just make
the irq_chip structure static, outside of combiner, and have "QCOM80B1"
(or something of your liking) as the name once and for all.
> +
> + dev_info(&pdev->dev, "Initialized with [p=%d,n=%d,r=%p]\n",
> + combiner->parent_irq, combiner->nirqs, combiner->regs[0].addr);
> + return 0;
> +}
> +
> +static const struct acpi_device_id qcom_irq_combiner_acpi_match[] = {
> + { "QCOM80B1", },
> + { }
> +};
> +
> +static struct platform_driver qcom_irq_combiner_probe = {
> + .driver = {
> + .name = "qcom-irq-combiner",
> + .owner = THIS_MODULE,
> + .acpi_match_table = ACPI_PTR(qcom_irq_combiner_acpi_match),
> + },
> + .probe = combiner_probe,
> +};
> +
> +static int __init register_qcom_irq_combiner(void)
> +{
> + return platform_driver_register(&qcom_irq_combiner_probe);
> +}
> +device_initcall(register_qcom_irq_combiner);
>
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH] Input: lpc32xx-keys - fix invalid error handling of a requested irq
From: Sylvain Lemieux @ 2016-12-07 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205014753.2092-1-vz@mleia.com>
On Mon, 2016-12-05 at 03:47 +0200, Vladimir Zapolskiy wrote:
> Semantics of NR_IRQS is different on machines with SPARSE_IRQ option
> disabled or enabled, in the latter case IRQs are allocated starting
> at least from the value specified by NR_IRQS and going upwards, so
> the check of (irq >= NR_IRQ) to decide about an error code returned by
> platform_get_irq() is completely invalid, don't attempt to overrule
> irq subsystem in the driver.
>
> The change fixes lpc32xx_keys driver initialization on boot:
>
> lpc32xx_keys 40050000.key: failed to get platform irq
> lpc32xx_keys: probe of 40050000.key failed with error -22
>
> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
> drivers/input/keyboard/lpc32xx-keys.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Cosmetic - please update the subject line when doing the commit:
replace " -" by ":" after lpc32xx-keys
Acked-by: Sylvain Lemieux <slemieux.tyco@gmail.com>
^ permalink raw reply
* [PATCH] mtd: nand: lpc32xx: fix invalid error handling of a requested irq
From: Sylvain Lemieux @ 2016-12-07 18:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205014710.2015-1-vz@mleia.com>
On Mon, 2016-12-05 at 03:47 +0200, Vladimir Zapolskiy wrote:
> Semantics of NR_IRQS is different on machines with SPARSE_IRQ option
> disabled or enabled, in the latter case IRQs are allocated starting
> at least from the value specified by NR_IRQS and going upwards, so
> the check of (irq >= NR_IRQ) to decide about an error code returned by
> platform_get_irq() is completely invalid, don't attempt to overrule
> irq subsystem in the driver.
>
> The change fixes LPC32xx NAND MLC driver initialization on boot.
>
> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
> drivers/mtd/nand/lpc32xx_mlc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Acked-by: Sylvain Lemieux <slemieux.tyco@gmail.com>
^ permalink raw reply
* [PATCH 3/3] pwm: lpc32xx: remove handling of PWM channels
From: Sylvain Lemieux @ 2016-12-07 17:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205014308.1741-2-vz@mleia.com>
On Mon, 2016-12-05 at 03:43 +0200, Vladimir Zapolskiy wrote:
> Because LPC32xx PWM controllers have single output which is registered as
> the only PWM device/channel per controller, it is known in advance that
> pwm->hwpwm value is always 0. On basis of this fact simplify the code
> by removing operations with pwm->hwpwm, there is no controls which require
> channel number as input.
>
> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
> drivers/pwm/pwm-lpc32xx.c | 20 +++++++++-----------
> 1 file changed, 9 insertions(+), 11 deletions(-)
>
Reviewed-by: Sylvain Lemieux <slemieux.tyco@gmail.com>
^ permalink raw reply
* [PATCH 2/3] pwm: lpc32xx: switch driver to one phandle argument for PWM consumers
From: Sylvain Lemieux @ 2016-12-07 17:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205014308.1741-1-vz@mleia.com>
On Mon, 2016-12-05 at 03:43 +0200, Vladimir Zapolskiy wrote:
> NXP LPC32xx SoCs have two simple independent PWM controllers with a single
> output each, in this case there is no need to specify PWM channel argument
> on client side, one cell for setting PWM output frequency is sufficient.
>
> The change adds private of_xlate() handling of a single cell value given
> with a PWM phandle on client side, the handling is taken from the PXA PWM
> driver.
>
> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
> drivers/pwm/pwm-lpc32xx.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
Reviewed-by: Sylvain Lemieux <slemieux.tyco@gmail.com>
^ permalink raw reply
* [PATCH 1/3] dt: pwm: lpc32xx: add description of clocks and #pwm-cells properties
From: Sylvain Lemieux @ 2016-12-07 17:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205014237.1689-2-vz@mleia.com>
On Mon, 2016-12-05 at 03:42 +0200, Vladimir Zapolskiy wrote:
> NXP LPC32xx SoCs have two simple independent PWM controllers with a single
> output each, in this case there is no need to specify PWM channel argument
> on client side, one cell for setting PWM output frequency is sufficient.
>
> Another added to the description property 'clocks' has a standard meaning
> of a controller supply clock, in the LPC32xx User's Manual the clock is
> denoted as PWM1_CLK or PWM2_CLK clock.
>
> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
> Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt | 7 +++++++
> 1 file changed, 7 insertions(+)
>
Reviewed-by: Sylvain Lemieux <slemieux.tyco@gmail.com>
^ permalink raw reply
* [PATCH 4/9] arm64: dts: rockchip: support dwc3 USB for rk3399
From: Brian Norris @ 2016-12-07 17:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2947180.ggfADt6cbn@phil>
Hi,
On Wed, Dec 07, 2016 at 06:09:16PM +0100, Heiko Stuebner wrote:
> Am Donnerstag, 1. Dezember 2016, 18:27:28 CET schrieb Brian Norris:
> > Add the dwc3 usb needed node information for rk3399.
> >
> > Signed-off-by: Brian Norris <briannorris@chromium.org>
> > ---
> > Somewhat rewritten from Caesar's reposting (v2) of my patch.
> >
> > Changes:
> > * Include USB2 PHY (which is now in -next)
> > * Don't include USB3 PHY, as extcon support is not ready yet
> > * Drop non-upstream properties
> > * Fixup whitespace a bit
> > ---
> > arch/arm64/boot/dts/rockchip/rk3399.dtsi | 60
> > ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> > b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 4ca8f9a7601c..1e97fb8c6415
> > 100644
> > --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> > +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> > @@ -316,6 +316,66 @@
> > };
> > };
> >
> > + usbdrd3_0: usb at fe800000 {
>
> insert location above usb at fe380000 is sorted wrong
So, *how* do you think things are sorted here? Alphabetical by label? Or
by node name? Or by unit address? I guess I'm seeing you meant unit
address. But pcie at f8000000 is also out of order then. I guess maybe
that's the only one then.
> > + compatible = "rockchip,rk3399-dwc3";
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > + ranges;
> > + clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
> > + <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
> > + <&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
> > + clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
> > + "aclk_usb3otg0", "aclk_usb3_rksoc_axi_perf",
> > + "aclk_usb3", "aclk_usb3_grf";
>
> clock-names do not match binding. The dwc3-of-simple does not care, as it just
> enables all of them it seems, but binding doc states the clock names as
>
> - clock-names: Should contain the following:
> "ref_clk" Controller reference clk, have to be 24 MHz
> "suspend_clk" Controller suspend clk, have to be 24 MHz or 32 KHz
> "bus_clk" Master/Core clock, have to be >= 62.5 MHz for SS
> operation and >= 30MHz for HS operation
> "grf_clk" Controller grf clk
Ah, sorry. I'll try to go with the rockchip,dwc3.txt names better.
There are a few extra clocks here now, but I think those might only be
for USB3 support, which isn't really working yet. I'll either document
them or drop them.
> > + resets = <&cru SRST_A_USB3_OTG0>;
> > + reset-names = "usb3-otg";
>
> you could update the binding documentation to list this one.
Similar story; this is only used for some of the hacky stuff Rockchip is
doing for USB3/TypeC stuff out of tree. I'll either document it or drop
it (as I'm not actually using it yet).
Thanks,
Brian
> Heiko
>
> > + status = "disabled";
> > +
> > + usbdrd_dwc3_0: dwc3 {
> > + compatible = "snps,dwc3";
> > + reg = <0x0 0xfe800000 0x0 0x100000>;
> > + interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
> > + dr_mode = "otg";
> > + phys = <&u2phy0_otg>;
> > + phy-names = "usb2-phy";
> > + snps,dis_enblslpm_quirk;
> > + snps,dis-u2-freeclk-exists-quirk;
> > + snps,dis_u2_susphy_quirk;
> > + snps,dis-del-phy-power-chg-quirk;
> > + status = "disabled";
> > + };
> > + };
[...]
^ permalink raw reply
* [PATCH 6/9] dt-bindings: Document rk3399 Gru/Kevin
From: Brian Norris @ 2016-12-07 17:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1720836.rjtWqG8OD3@phil>
On Wed, Dec 07, 2016 at 06:12:13PM +0100, Heiko Stuebner wrote:
> Hi Brian,
>
> Am Donnerstag, 1. Dezember 2016, 18:27:30 CET schrieb Brian Norris:
> > Gru is a base dev board for a family of devices, including Kevin. Both
> > utilize Rockchip RK3399, and they share much of their design.
> >
> > Signed-off-by: Brian Norris <briannorris@chromium.org>
> > ---
> > Documentation/devicetree/bindings/arm/rockchip.txt | 20
> > ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt
> > b/Documentation/devicetree/bindings/arm/rockchip.txt index
> > cc4ace6397ab..830e13f5890c 100644
> > --- a/Documentation/devicetree/bindings/arm/rockchip.txt
> > +++ b/Documentation/devicetree/bindings/arm/rockchip.txt
> > @@ -99,6 +99,26 @@ Rockchip platforms device tree bindings
> > "google,veyron-speedy-rev3", "google,veyron-speedy-rev2",
> > "google,veyron-speedy", "google,veyron", "rockchip,rk3288";
> >
> > +- Google Gru (dev-board):
>
> boards sorted alphabetically please
>
> Brian, Gru, Jaq, ... Kevin, ...
>
> While the sorting of old boards is not right yet, new boards should be sorted.
I got the idea that there was some attempt to group logically before
alphabetically. Like keeping board/SoC families together. But maybe not.
I can do as you suggested, if you don't care about keeping actual
similar boards together (i.e., veyron/3288 vs gru/3399).
Brian
^ permalink raw reply
* [PATCH v5 4/5] [media] dt-bindings: add TI VPIF documentation
From: Kevin Hilman @ 2016-12-07 17:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7493249.S63p6GTauu@avalon>
Laurent Pinchart <laurent.pinchart@ideasonboard.com> writes:
> Hi Kevin,
>
> Thank you for the patch.
>
> On Tuesday 06 Dec 2016 21:08:25 Kevin Hilman wrote:
>> Acked-by: Rob Herring <robh@kernel.org>
>> Signed-off-by: Kevin Hilman <khilman@baylibre.com>
>> ---
>> .../devicetree/bindings/media/ti,da850-vpif.txt | 67 +++++++++++++++++++
>> 1 file changed, 67 insertions(+)
>> create mode 100644
>> Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>> b/Documentation/devicetree/bindings/media/ti,da850-vpif.txt new file mode
>> 100644
>> index 000000000000..fa06dfdb6898
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>> @@ -0,0 +1,67 @@
>> +Texas Instruments VPIF
>> +----------------------
>> +
>> +The TI Video Port InterFace (VPIF) is the primary component for video
>> +capture and display on the DA850/AM18x family of TI DaVinci/Sitara
>> +SoCs.
>> +
>> +TI Document reference: SPRUH82C, Chapter 35
>> +http://www.ti.com/lit/pdf/spruh82
>> +
>> +Required properties:
>> +- compatible: must be "ti,da850-vpif"
>> +- reg: physical base address and length of the registers set for the
>> device;
>> +- interrupts: should contain IRQ line for the VPIF
>> +
>> +Video Capture:
>> +
>> +VPIF has a 16-bit parallel bus input, supporting 2 8-bit channels or a
>> +single 16-bit channel. It should contain at least one port child node
>> +with child 'endpoint' node. Please refer to the bindings defined in
>> +Documentation/devicetree/bindings/media/video-interfaces.txt.
>
> You might want to clarify how endpoints are use in the two cases. Apart from
> that,
OK, I'll add another example for the 16-bit case. Something like...
>> +Example using 2 8-bit input channels, one of which is connected to an
>> +I2C-connected TVP5147 decoder:
>> +
>> + vpif: vpif at 217000 {
>> + compatible = "ti,da850-vpif";
>> + reg = <0x217000 0x1000>;
>> + interrupts = <92>;
>> +
>> + port {
>> + vpif_ch0: endpoint at 0 {
>> + reg = <0>;
>> + bus-width = <8>;
>> + remote-endpoint = <&composite>;
>> + };
>> +
>> + vpif_ch1: endpoint at 1 {
>> + reg = <1>;
>> + bus-width = <8>;
>> + data-shift = <8>;
>> + };
>> + };
>> + };
>> +
>> +[ ... ]
>> +
>> +&i2c0 {
>> +
>> + tvp5147 at 5d {
>> + compatible = "ti,tvp5147";
>> + reg = <0x5d>;
>> + status = "okay";
>> +
>> + port {
>> + composite: endpoint {
>> + hsync-active = <1>;
>> + vsync-active = <1>;
>> + pclk-sample = <0>;
>> +
>> + /* VPIF channel 0 (lower 8-bits) */
>> + remote-endpoint = <&vpif_ch0>;
>> + bus-width = <8>;
>> + };
>> + };
>> + };
>> +};
...this, at the end of the binding doc:
Alternatively, an example when the bus is configured as a single
16-bit input (e.g. for raw-capture mode):
vpif: vpif at 217000 {
compatible = "ti,da850-vpif";
reg = <0x217000 0x1000>;
interrupts = <92>;
port {
vpif_ch0: endpoint {
bus-width = <16>;
};
};
};
Thanks for the review,
Kevin
^ permalink raw reply
* [Linaro-acpi] [PATCH v17 08/15] clocksource/drivers/arm_arch_timer: move arch_timer_needs_of_probing into DT init call
From: Timur Tabi @ 2016-12-07 17:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CADyBb7uAObQn_JVp_qw9+7POiqUctdzy3cYLsb0rk-JMX5W1uw@mail.gmail.com>
On Fri, Nov 25, 2016 at 9:06 AM, Fu Wei <fu.wei@linaro.org> wrote:
>
> a "+ int ret;" should be move from [12/15] to here, I have fix the
> problem in my repo, it would happen in next patchset
>
> https://git.linaro.org/people/fu.wei/linux.git/log/?h=topic-gtdt-wakeup-timer_upstream_v18_devel
Fu, please post v18 to the mailing list so that it can be picked up
for 4.10 (if it's not too late already).
--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH v5 3/5] [media] davinci: vpif_capture: fix start/stop streaming locking
From: Kevin Hilman @ 2016-12-07 17:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5753609.tAY8Gxp3ld@avalon>
Laurent Pinchart <laurent.pinchart@ideasonboard.com> writes:
> Hi Kevin,
>
> Thank you for the patch.
>
> On Tuesday 06 Dec 2016 21:08:24 Kevin Hilman wrote:
>> Video capture subdevs may be over I2C and may sleep during xfer, so we
>> cannot do IRQ-disabled locking when calling the subdev.
>>
>> The IRQ-disabled locking is meant to protect the DMA queue list
>> throughout the rest of the driver, so update the locking in
>> [start|stop]_streaming to protect just this list.
>>
>> Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> Signed-off-by: Kevin Hilman <khilman@baylibre.com>
>
> I would also add a comment to document the irqlock field as protecting the
> dma_queue list only. Something like
>
> - /* Used in video-buf */
> + /* Protects the dma_queue field */
> spinlock_t irqlock;
>
> With that,
>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
OK, will update the comment. Thanks for the review,
Kevin
^ permalink raw reply
* [PATCH] MAINTAINERS: Add Patchwork URL to Samsung Exynos entry
From: Javier Martinez Canillas @ 2016-12-07 17:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481131115-11143-1-git-send-email-krzk@kernel.org>
Hello Krzysztof,
On 12/07/2016 02:18 PM, Krzysztof Kozlowski wrote:
> I use Patchwork for handling incoming patches. Put its address here so
> submitters could know what is in the queue.
>
> Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
> ---
> MAINTAINERS | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 191887bdc49b..ec5137c39572 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1689,6 +1689,7 @@ M: Krzysztof Kozlowski <krzk@kernel.org>
> R: Javier Martinez Canillas <javier@osg.samsung.com>
> L: linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
> L: linux-samsung-soc at vger.kernel.org (moderated for non-subscribers)
> +Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/
> S: Maintained
> F: arch/arm/boot/dts/s3c*
> F: arch/arm/boot/dts/s5p*
>
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Best regards,
--
Javier Martinez Canillas
Open Source Group
Samsung Research America
^ permalink raw reply
* [PATCH V2 2/5] ARM: BCM5301X: Specify USB controllers in DT
From: Ray Jui @ 2016-12-07 17:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161207075655.7396-2-zajec5@gmail.com>
On 12/6/2016 11:56 PM, Rafa? Mi?ecki wrote:
> From: Rafa? Mi?ecki <rafal@milecki.pl>
>
> There are 3 separated controllers, one per USB /standard/. With PHY
> drivers in place they can be simply supported with generic drivers.
>
> Signed-off-by: Rafa? Mi?ecki <rafal@milecki.pl>
> ---
> V2: Fix node names and reorder ehci with ohci. Thanks Ray!
> ---
> arch/arm/boot/dts/bcm5301x.dtsi | 33 ++++++++++++++++++++++++++++++++-
> 1 file changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi
> index f09a2bb..a4614c9 100644
> --- a/arch/arm/boot/dts/bcm5301x.dtsi
> +++ b/arch/arm/boot/dts/bcm5301x.dtsi
> @@ -248,8 +248,26 @@
>
> #address-cells = <1>;
> #size-cells = <1>;
> + ranges;
>
> - phys = <&usb2_phy>;
> + interrupt-parent = <&gic>;
> +
> + ehci: ehci at 21000 {
> + #usb-cells = <0>;
> +
> + compatible = "generic-ehci";
> + reg = <0x00021000 0x1000>;
> + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
> + phys = <&usb2_phy>;
> + };
> +
> + ohci: ohci at 22000 {
> + #usb-cells = <0>;
> +
> + compatible = "generic-ohci";
> + reg = <0x00022000 0x1000>;
> + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
> + };
> };
>
> usb3: usb3 at 23000 {
> @@ -257,6 +275,19 @@
>
> #address-cells = <1>;
> #size-cells = <1>;
> + ranges;
> +
> + interrupt-parent = <&gic>;
> +
> + xhci: xhci at 23000 {
> + #usb-cells = <0>;
> +
> + compatible = "generic-xhci";
> + reg = <0x00023000 0x1000>;
> + interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
> + phys = <&usb3_phy>;
> + phy-names = "usb";
> + };
> };
>
> spi at 29000 {
>
Looks good to me! Thanks!
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
^ permalink raw reply
* [PATCH] MAINTAINERS: Add Patchwork URL to Samsung Exynos entry
From: Krzysztof Kozlowski @ 2016-12-07 17:18 UTC (permalink / raw)
To: linux-arm-kernel
I use Patchwork for handling incoming patches. Put its address here so
submitters could know what is in the queue.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 191887bdc49b..ec5137c39572 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1689,6 +1689,7 @@ M: Krzysztof Kozlowski <krzk@kernel.org>
R: Javier Martinez Canillas <javier@osg.samsung.com>
L: linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
L: linux-samsung-soc at vger.kernel.org (moderated for non-subscribers)
+Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/
S: Maintained
F: arch/arm/boot/dts/s3c*
F: arch/arm/boot/dts/s5p*
--
2.7.4
^ permalink raw reply related
* [PATCH 6/9] dt-bindings: Document rk3399 Gru/Kevin
From: Heiko Stuebner @ 2016-12-07 17:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480645653-36943-7-git-send-email-briannorris@chromium.org>
Hi Brian,
Am Donnerstag, 1. Dezember 2016, 18:27:30 CET schrieb Brian Norris:
> Gru is a base dev board for a family of devices, including Kevin. Both
> utilize Rockchip RK3399, and they share much of their design.
>
> Signed-off-by: Brian Norris <briannorris@chromium.org>
> ---
> Documentation/devicetree/bindings/arm/rockchip.txt | 20
> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt
> b/Documentation/devicetree/bindings/arm/rockchip.txt index
> cc4ace6397ab..830e13f5890c 100644
> --- a/Documentation/devicetree/bindings/arm/rockchip.txt
> +++ b/Documentation/devicetree/bindings/arm/rockchip.txt
> @@ -99,6 +99,26 @@ Rockchip platforms device tree bindings
> "google,veyron-speedy-rev3", "google,veyron-speedy-rev2",
> "google,veyron-speedy", "google,veyron", "rockchip,rk3288";
>
> +- Google Gru (dev-board):
boards sorted alphabetically please
Brian, Gru, Jaq, ... Kevin, ...
While the sorting of old boards is not right yet, new boards should be sorted.
Thanks
Heiko
> + Required root node properties:
> + - compatible = "google,gru-rev15", "google,gru-rev14",
> + "google,gru-rev13", "google,gru-rev12",
> + "google,gru-rev11", "google,gru-rev10",
> + "google,gru-rev9", "google,gru-rev8",
> + "google,gru-rev7", "google,gru-rev6",
> + "google,gru-rev5", "google,gru-rev4",
> + "google,gru-rev3", "google,gru-rev2",
> + "google,gru", "rockchip,rk3399";
> +
> +- Google Kevin:
> + Required root node properties:
> + - compatible = "google,kevin-rev15", "google,kevin-rev14",
> + "google,kevin-rev13", "google,kevin-rev12",
> + "google,kevin-rev11", "google,kevin-rev10",
> + "google,kevin-rev9", "google,kevin-rev8",
> + "google,kevin-rev7", "google,kevin-rev6",
> + "google,kevin", "google,gru", "rockchip,rk3399";
> +
> - mqmaker MiQi:
> Required root node properties:
> - compatible = "mqmaker,miqi", "rockchip,rk3288";
^ permalink raw reply
* [PATCH v6 2/2] ARM: davinci: da8xx: Fix sleeping function called from invalid context
From: Alexandre Bailon @ 2016-12-07 17:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481130567-27829-1-git-send-email-abailon@baylibre.com>
Everytime the usb20 phy is enabled, there is a
"sleeping function called from invalid context" BUG.
In addition, there is a recursive locking happening
because of the recurse call to clk_enable().
clk_enable() from arch/arm/mach-davinci/clock.c uses spin_lock_irqsave()
before to invoke the callback usb20_phy_clk_enable().
usb20_phy_clk_enable() uses clk_get() and clk_enable_prepapre()
which may sleep.
replace clk_prepare_enable() by davinci_clk_enable().
Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
Suggested-by: David Lechner <david@lechnology.com>
---
arch/arm/mach-davinci/usb-da8xx.c | 33 +++++++++++++++------------------
1 file changed, 15 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index c6feecf..9edd2d8 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -22,6 +22,8 @@
#define DA8XX_USB0_BASE 0x01e00000
#define DA8XX_USB1_BASE 0x01e25000
+static struct clk *usb20_clk;
+
static struct platform_device da8xx_usb_phy = {
.name = "da8xx-usb-phy",
.id = -1,
@@ -158,26 +160,14 @@ int __init da8xx_register_usb_refclkin(int rate)
static void usb20_phy_clk_enable(struct clk *clk)
{
- struct clk *usb20_clk;
int err;
u32 val;
u32 timeout = 500000; /* 500 msec */
val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
- usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
- if (IS_ERR(usb20_clk)) {
- pr_err("could not get usb20 clk: %ld\n", PTR_ERR(usb20_clk));
- return;
- }
-
/* The USB 2.O PLL requires that the USB 2.O PSC is enabled as well. */
- err = clk_prepare_enable(usb20_clk);
- if (err) {
- pr_err("failed to enable usb20 clk: %d\n", err);
- clk_put(usb20_clk);
- return;
- }
+ davinci_clk_enable(usb20_clk);
/*
* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1
@@ -197,8 +187,7 @@ static void usb20_phy_clk_enable(struct clk *clk)
pr_err("Timeout waiting for USB 2.0 PHY clock good\n");
done:
- clk_disable_unprepare(usb20_clk);
- clk_put(usb20_clk);
+ davinci_clk_disable(usb20_clk);
}
static void usb20_phy_clk_disable(struct clk *clk)
@@ -285,11 +274,19 @@ static struct clk_lookup usb20_phy_clk_lookup =
int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin)
{
struct clk *parent;
- int ret = 0;
+ int ret;
+
+ usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
+ ret = PTR_ERR_OR_ZERO(usb20_clk);
+ if (ret)
+ return ret;
parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "pll0_aux");
- if (IS_ERR(parent))
- return PTR_ERR(parent);
+ ret = PTR_ERR_OR_ZERO(parent);
+ if (ret) {
+ clk_put(usb20_clk);
+ return ret;
+ }
usb20_phy_clk.parent = parent;
ret = clk_register(&usb20_phy_clk);
--
2.7.3
^ permalink raw reply related
* [PATCH v6 1/2] ARM: davinci: Export two clocks function
From: Alexandre Bailon @ 2016-12-07 17:09 UTC (permalink / raw)
To: linux-arm-kernel
Rename and export __clk_enable() and __clk_disable() in order
to use them from usb-da8xx.c. This file implements the usb20 phy clock
that must be able to enable or disable usb20 clock.
To prevent a recurssive call to clk_enable() that would cause a recursive
locking issue, we must use __clk_enable() and __clk_disable().
Rename these methods in davinci_clk_enable() and davinci_clk_disable(),
and export them.
Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
Suggested-by: David Lechner <david@lechnology.com>
---
arch/arm/mach-davinci/clock.c | 14 ++++++++------
arch/arm/mach-davinci/clock.h | 2 ++
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index df42c93..0f967c3 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -31,10 +31,10 @@ static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
static DEFINE_SPINLOCK(clockfw_lock);
-static void __clk_enable(struct clk *clk)
+void davinci_clk_enable(struct clk *clk)
{
if (clk->parent)
- __clk_enable(clk->parent);
+ davinci_clk_enable(clk->parent);
if (clk->usecount++ == 0) {
if (clk->flags & CLK_PSC)
davinci_psc_config(clk->domain, clk->gpsc, clk->lpsc,
@@ -43,8 +43,9 @@ static void __clk_enable(struct clk *clk)
clk->clk_enable(clk);
}
}
+EXPORT_SYMBOL(davinci_clk_enable);
-static void __clk_disable(struct clk *clk)
+void davinci_clk_disable(struct clk *clk)
{
if (WARN_ON(clk->usecount == 0))
return;
@@ -56,8 +57,9 @@ static void __clk_disable(struct clk *clk)
clk->clk_disable(clk);
}
if (clk->parent)
- __clk_disable(clk->parent);
+ davinci_clk_disable(clk->parent);
}
+EXPORT_SYMBOL(davinci_clk_disable);
int davinci_clk_reset(struct clk *clk, bool reset)
{
@@ -103,7 +105,7 @@ int clk_enable(struct clk *clk)
return -EINVAL;
spin_lock_irqsave(&clockfw_lock, flags);
- __clk_enable(clk);
+ davinci_clk_enable(clk);
spin_unlock_irqrestore(&clockfw_lock, flags);
return 0;
@@ -118,7 +120,7 @@ void clk_disable(struct clk *clk)
return;
spin_lock_irqsave(&clockfw_lock, flags);
- __clk_disable(clk);
+ davinci_clk_disable(clk);
spin_unlock_irqrestore(&clockfw_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index e2a5437..fa2b837 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -132,6 +132,8 @@ int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate);
int davinci_set_refclk_rate(unsigned long rate);
int davinci_simple_set_rate(struct clk *clk, unsigned long rate);
int davinci_clk_reset(struct clk *clk, bool reset);
+void davinci_clk_enable(struct clk *clk);
+void davinci_clk_disable(struct clk *clk);
extern struct platform_device davinci_wdt_device;
extern void davinci_watchdog_reset(struct platform_device *);
--
2.7.3
^ permalink raw reply related
* [PATCH 8/9] arm64: dts: rockchip: partially describe PWM regulators for Gru
From: Brian Norris @ 2016-12-07 17:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2418784.7dMdkAyuIx@phil>
Hi Heiko,
On Wed, Dec 07, 2016 at 05:48:24PM +0100, Heiko Stuebner wrote:
> Am Donnerstag, 1. Dezember 2016, 18:27:32 CET schrieb Brian Norris:
> > We need to add regulators to the CPU nodes, so cpufreq doesn't think it
> > can crank up the clock speed without changing the voltage. However, we
> > don't yet have the DT bindings to fully describe the Over Voltage
> > Protection (OVP) circuits on these boards. Without that description, we
> > might end up changing the voltage too much, too fast.
> >
> > Add the pwm-regulator descriptions and associate the CPU OPPs, but leave
> > them disabled.
> >
> > Signed-off-by: Brian Norris <briannorris@chromium.org>
>
> is there a specific reason for keeping this change separate?
Maybe not a great one. I figured they were somewhat controversial, so I
at least wanted to split the "cpufreq patches" (i.e., this and the
previous) from the main DTS(I) additions. I also figured we typically
like to keep the base SoC changes separate from the board DTS(I)
changes.
> While it is nice for documentation reasons, as it stands now the previous
> patch introduces a regression (cpufreq trying to scale without regulators) and
> immediately fixes it here.
Right. Additionally, as noted on the previous patch, we might do the
same with EVB. But I don't know what the regulators are like for EVB.
This is probably a bigger deal, since EVB has been working (allegedly)
upstream for a while now.
There's no way to split these up without either breaking compilation or
breaking bisectability. For Kevin/Gru, they don't function at all before
this series, so I figured some "settle" time wasn't a huge deal.
> So if you're ok with it, I'd like to merge this one back into the previous
> patch when applying.
That'd be OK with me, as long as we're also confident about EVB.
Maybe at a minimum, I should just patch in some empty regulator nodes,
so cpufreq doesn't think there's no need to handle voltage.
Brian
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox