* [PATCH/RFT v2 10/17] USB: da8xx: use flag instead of bitmask for over current change
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
The da8xx ohci has only one port connected. In hub_control we
check that the port is 1, or else we bail out early. There is no point
in passing as argument the port number, if we know, and check that it
will always be 1.
Simplify functions and callbacks, by removing the port parameter, and
converting the over current indicatior change form a mask to a flag.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 8 ++++----
arch/arm/mach-davinci/board-omapl138-hawk.c | 8 ++++----
drivers/usb/host/ohci-da8xx.c | 29 ++++++++++++++---------------
include/linux/platform_data/usb-davinci.h | 9 ++++-----
4 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index b33fc6b..d12fcf5 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -50,18 +50,18 @@
static da8xx_ocic_handler_t da830_evm_usb_ocic_handler;
-static int da830_evm_usb_set_power(unsigned port, int on)
+static int da830_evm_usb_set_power(int on)
{
gpio_set_value(ON_BD_USB_DRV, on);
return 0;
}
-static int da830_evm_usb_get_power(unsigned port)
+static int da830_evm_usb_get_power(void)
{
return gpio_get_value(ON_BD_USB_DRV);
}
-static int da830_evm_usb_get_oci(unsigned port)
+static int da830_evm_usb_get_oci(void)
{
return !gpio_get_value(ON_BD_USB_OVC);
}
@@ -100,7 +100,7 @@ static int da830_evm_usb_ocic_notify(da8xx_ocic_handler_t handler)
static irqreturn_t da830_evm_usb_ocic_irq(int irq, void *dev_id)
{
- da830_evm_usb_ocic_handler(&da830_evm_usb11_pdata, 1);
+ da830_evm_usb_ocic_handler(&da830_evm_usb11_pdata);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index c3ab7ea..1d31f45 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -189,18 +189,18 @@ static __init void omapl138_hawk_mmc_init(void)
-1
};
-static int hawk_usb_set_power(unsigned port, int on)
+static int hawk_usb_set_power(int on)
{
gpio_set_value(DA850_USB1_VBUS_PIN, on);
return 0;
}
-static int hawk_usb_get_power(unsigned port)
+static int hawk_usb_get_power(void)
{
return gpio_get_value(DA850_USB1_VBUS_PIN);
}
-static int hawk_usb_get_oci(unsigned port)
+static int hawk_usb_get_oci(void)
{
return !gpio_get_value(DA850_USB1_OC_PIN);
}
@@ -237,7 +237,7 @@ static int hawk_usb_ocic_notify(da8xx_ocic_handler_t handler)
static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id)
{
- hawk_usb_ocic_handler(&omapl138_hawk_usb11_pdata, 1);
+ hawk_usb_ocic_handler(&omapl138_hawk_usb11_pdata);
return IRQ_HANDLED;
}
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 3656d7c..e98066d 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -25,8 +25,8 @@
static struct clk *usb11_clk;
static struct phy *usb11_phy;
-/* Over-current indicator change bitmask */
-static volatile u16 ocic_mask;
+/* Over-current indicator change flag */
+static int ocic_flag;
static int ohci_da8xx_enable(void)
{
@@ -64,14 +64,13 @@ static void ohci_da8xx_disable(void)
/*
* Handle the port over-current indicator change.
*/
-static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
- unsigned port)
+static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub)
{
- ocic_mask |= 1 << port;
+ ocic_flag = 1;
/* Once over-current is detected, the port needs to be powered down */
- if (hub->get_oci(port) > 0)
- hub->set_power(port, 0);
+ if (hub->get_oci() > 0)
+ hub->set_power(0);
}
static int ohci_da8xx_init(struct usb_hcd *hcd)
@@ -147,8 +146,8 @@ static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
{
int length = ohci_hub_status_data(hcd, buf);
- /* See if we have OCIC bit set on port 1 */
- if (ocic_mask & (1 << 1)) {
+ /* See if we have OCIC flag set */
+ if (ocic_flag) {
dev_dbg(hcd->self.controller, "over-current indicator change "
"on port 1\n");
@@ -181,15 +180,15 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
/* The port power status (PPS) bit defaults to 1 */
- if (hub->get_power && hub->get_power(wIndex) == 0)
+ if (hub->get_power && hub->get_power() == 0)
temp &= ~RH_PS_PPS;
/* The port over-current indicator (POCI) bit is always 0 */
- if (hub->get_oci && hub->get_oci(wIndex) > 0)
+ if (hub->get_oci && hub->get_oci() > 0)
temp |= RH_PS_POCI;
/* The over-current indicator change (OCIC) bit is 0 too */
- if (ocic_mask & (1 << wIndex))
+ if (ocic_flag)
temp |= RH_PS_OCIC;
put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
@@ -213,16 +212,16 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (!hub->set_power)
return -EPIPE;
- return hub->set_power(wIndex, temp) ? -EPIPE : 0;
+ return hub->set_power(temp) ? -EPIPE : 0;
case USB_PORT_FEAT_C_OVER_CURRENT:
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex,
"C_OVER_CURRENT");
if (temp)
- ocic_mask |= 1 << wIndex;
+ ocic_flag = 1;
else
- ocic_mask &= ~(1 << wIndex);
+ ocic_flag = 0;
return 0;
}
}
diff --git a/include/linux/platform_data/usb-davinci.h b/include/linux/platform_data/usb-davinci.h
index 0926e99..3217fbe 100644
--- a/include/linux/platform_data/usb-davinci.h
+++ b/include/linux/platform_data/usb-davinci.h
@@ -13,17 +13,16 @@
struct da8xx_ohci_root_hub;
-typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub,
- unsigned port);
+typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub);
/* Passed as the platform data to the OHCI driver */
struct da8xx_ohci_root_hub {
/* Switch the port power on/off */
- int (*set_power)(unsigned port, int on);
+ int (*set_power)(int on);
/* Read the port power status */
- int (*get_power)(unsigned port);
+ int (*get_power)(void);
/* Read the port over-current indicator */
- int (*get_oci)(unsigned port);
+ int (*get_oci)(void);
/* Over-current indicator change notification (pass NULL to disable) */
int (*ocic_notify)(da8xx_ocic_handler_t handler);
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 09/17] regulator: fixed: Add over current event
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
Some regulator supplies have an over-current pin that is
activated when the hw detects an over current condition.
When this happens, the hardware enters a current limited
mode.
Extend the fixed regulator driver with the ability
to handle irq's from the over-current pin and report
an over current event to the consumers via a regulator
notifier. Also, add device tree bindings to allow to
pass a gpio for over current monitoring.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
.../bindings/regulator/fixed-regulator.txt | 4 ++
drivers/regulator/fixed.c | 64 ++++++++++++++++++++++
include/linux/regulator/consumer.h | 5 ++
include/linux/regulator/fixed.h | 3 +
4 files changed, 76 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
index 4fae41d..d20bf67 100644
--- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -11,6 +11,8 @@ If this property is missing, the default assumed is Active low.
- gpio-open-drain: GPIO is open drain type.
If this property is missing then default assumption is false.
-vin-supply: Input supply name.
+- oc-gpio: Input gpio that signals an over current condition
+- oc-active-high: The polarity of the over current pin is high
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
@@ -26,9 +28,11 @@ Example:
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio1 16 0>;
+ oc-gpio = <&gpio1 18 0>;
startup-delay-us = <70000>;
enable-active-high;
regulator-boot-on;
gpio-open-drain;
+ oc-active-high;
vin-supply = <&parent_reg>;
};
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 988a747..e7964bb 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -30,10 +30,14 @@
#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/interrupt.h>
struct fixed_voltage_data {
struct regulator_desc desc;
struct regulator_dev *dev;
+ int oc_gpio;
+ unsigned has_oc_gpio:1;
+ unsigned oc_high:1;
};
@@ -82,6 +86,14 @@ struct fixed_voltage_data {
if ((config->gpio < 0) && (config->gpio != -ENOENT))
return ERR_PTR(config->gpio);
+ config->oc_gpio = of_get_named_gpio(np, "oc-gpio", 0);
+ if (config->oc_gpio >= 0)
+ config->has_oc_gpio = true;
+ else if (config->oc_gpio != -ENOENT)
+ return ERR_PTR(config->oc_gpio);
+
+ config->oc_high = of_property_read_bool(np, "oc-active-high");
+
of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
config->enable_high = of_property_read_bool(np, "enable-active-high");
@@ -94,7 +106,34 @@ struct fixed_voltage_data {
return config;
}
+static irqreturn_t reg_fixed_overcurrent_irq(int irq, void *data)
+{
+ struct fixed_voltage_data *drvdata = data;
+
+ regulator_notifier_call_chain(drvdata->dev,
+ REGULATOR_EVENT_OVER_CURRENT, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int reg_fixed_get_mode(struct regulator_dev *rdev)
+{
+ struct fixed_voltage_data *drvdata = rdev_get_drvdata(rdev);
+ unsigned int ret = REGULATOR_MODE_NORMAL;
+ int oc_value;
+
+ if (!drvdata->has_oc_gpio)
+ return ret;
+
+ oc_value = gpio_get_value(drvdata->oc_gpio);
+ if ((oc_value && drvdata->oc_high) || (!oc_value && !drvdata->oc_high))
+ ret = REGULATOR_MODE_OVERCURRENT;
+
+ return ret;
+}
+
static struct regulator_ops fixed_voltage_ops = {
+ .get_mode = reg_fixed_get_mode,
};
static int reg_fixed_voltage_probe(struct platform_device *pdev)
@@ -175,6 +214,31 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
cfg.driver_data = drvdata;
cfg.of_node = pdev->dev.of_node;
+ if (config->has_oc_gpio && gpio_is_valid(config->oc_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev,
+ config->oc_gpio,
+ GPIOF_DIR_IN, "oc_gpio");
+ if (ret) {
+ pr_err("Failed to request gpio: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev,
+ gpio_to_irq(config->oc_gpio), NULL,
+ reg_fixed_overcurrent_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "over_current", drvdata);
+ if (ret) {
+ pr_err("Failed to request irq: %d\n", ret);
+ return ret;
+ }
+
+ drvdata->oc_gpio = config->oc_gpio;
+ drvdata->oc_high = config->oc_high;
+ drvdata->has_oc_gpio = config->has_oc_gpio;
+ }
+
drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
&cfg);
if (IS_ERR(drvdata->dev)) {
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 6921082..9269217 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -74,6 +74,10 @@
* the most noisy and may not be able to handle fast load
* switching.
*
+ * OVERCURRENT Regulator has detected an overcurrent condition, and
+ * may be limiting the supply output.
+ *
+ *
* NOTE: Most regulators will only support a subset of these modes. Some
* will only just support NORMAL.
*
@@ -84,6 +88,7 @@
#define REGULATOR_MODE_NORMAL 0x2
#define REGULATOR_MODE_IDLE 0x4
#define REGULATOR_MODE_STANDBY 0x8
+#define REGULATOR_MODE_OVERCURRENT 0x10
/*
* Regulator notifier events.
diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h
index 48918be..79357be 100644
--- a/include/linux/regulator/fixed.h
+++ b/include/linux/regulator/fixed.h
@@ -50,10 +50,13 @@ struct fixed_voltage_config {
const char *input_supply;
int microvolts;
int gpio;
+ int oc_gpio;
unsigned startup_delay;
unsigned gpio_is_open_drain:1;
unsigned enable_high:1;
unsigned enabled_at_boot:1;
+ unsigned has_oc_gpio:1;
+ unsigned oc_high:1;
struct regulator_init_data *init_data;
};
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 08/17] ARM: davinci: hawk: add full constraints for ohci plat boot
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
The phy framework requests an optional "phy" regulator. If it does
not find one, it returns -EPROBE_DEFER. In the case of non-DT based boot
for the omap138-lcdk board, this would prevent the usb11 phy to probe
correctly and ohci would not enumerate.
By calling "regulator_has_full_constraints", An error would be returned
instead of DEFER for the "optional" regulator, and the probe of
the phy driver can continue normally without a regulator.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 3 +++
arch/arm/mach-davinci/board-omapl138-hawk.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index c62766e..b33fc6b 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -26,6 +26,7 @@
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
#include <linux/platform_data/spi-davinci.h>
+#include <linux/regulator/machine.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -631,6 +632,8 @@ static __init void da830_evm_init(void)
ret = da8xx_register_spi_bus(0, ARRAY_SIZE(da830evm_spi_info));
if (ret)
pr_warn("%s: spi 0 registration failed: %d\n", __func__, ret);
+
+ regulator_has_full_constraints();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index c5cb8d9..c3ab7ea 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -14,6 +14,7 @@
#include <linux/console.h>
#include <linux/gpio.h>
#include <linux/platform_data/gpio-davinci.h>
+#include <linux/regulator/machine.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -328,6 +329,8 @@ static __init void omapl138_hawk_init(void)
if (ret)
pr_warn("%s: dsp/rproc registration failed: %d\n",
__func__, ret);
+
+ regulator_has_full_constraints();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 07/17] ARM: davinci: da8xx: Enable the usb20 "per" clk on phy_clk_enable
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
While probing ochi phy with usb20 phy as a parent clock for usb11_phy,
the usb20_phy clock enable would time out. This is because the usb20
module clock needs to enabled while trying to lock the usb20_phy PLL.
Call clk enable and get for the usb20 peripheral before trying to
enable the phy PLL.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/usb-da8xx.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index 9e41a7f..982e105 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -53,11 +53,19 @@ int __init da8xx_register_usb_refclkin(int rate)
static void usb20_phy_clk_enable(struct clk *clk)
{
+ struct clk *usb20_clk;
u32 val;
u32 timeout = 500000; /* 500 msec */
val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ usb20_clk = clk_get(NULL, "usb20");
+ if (IS_ERR(usb20_clk)) {
+ pr_err("could not get usb20 clk\n");
+ return;
+ }
+
+ clk_prepare_enable(usb20_clk);
/*
* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1
* host may use the PLL clock without USB 2.0 OTG being used.
@@ -70,11 +78,14 @@ static void usb20_phy_clk_enable(struct clk *clk)
while (--timeout) {
val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
if (val & CFGCHIP2_PHYCLKGD)
- return;
+ goto done;
udelay(1);
}
pr_err("Timeout waiting for USB 2.0 PHY clock good.\n");
+done:
+ clk_disable_unprepare(usb20_clk);
+ clk_put(usb20_clk);
}
static void usb20_phy_clk_disable(struct clk *clk)
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 06/17] ARM: davinci: da8xx: Fix some redefined symbol warnings
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Alexandre Bailon <abailon@baylibre.com>
Some macro for DA8xx CFGCHIP are defined in usb-davinci.h,
but da8xx-cfgchip.h intend to replace them.
The usb-da8xx.c is using both headers, causing redefined symbol warnings.
Remove the old macros.
Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
---
include/linux/platform_data/usb-davinci.h | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/include/linux/platform_data/usb-davinci.h b/include/linux/platform_data/usb-davinci.h
index e0bc4ab..0926e99 100644
--- a/include/linux/platform_data/usb-davinci.h
+++ b/include/linux/platform_data/usb-davinci.h
@@ -11,29 +11,6 @@
#ifndef __ASM_ARCH_USB_H
#define __ASM_ARCH_USB_H
-/* DA8xx CFGCHIP2 (USB 2.0 PHY Control) register bits */
-#define CFGCHIP2_PHYCLKGD (1 << 17)
-#define CFGCHIP2_VBUSSENSE (1 << 16)
-#define CFGCHIP2_RESET (1 << 15)
-#define CFGCHIP2_OTGMODE (3 << 13)
-#define CFGCHIP2_NO_OVERRIDE (0 << 13)
-#define CFGCHIP2_FORCE_HOST (1 << 13)
-#define CFGCHIP2_FORCE_DEVICE (2 << 13)
-#define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13)
-#define CFGCHIP2_USB1PHYCLKMUX (1 << 12)
-#define CFGCHIP2_USB2PHYCLKMUX (1 << 11)
-#define CFGCHIP2_PHYPWRDN (1 << 10)
-#define CFGCHIP2_OTGPWRDN (1 << 9)
-#define CFGCHIP2_DATPOL (1 << 8)
-#define CFGCHIP2_USB1SUSPENDM (1 << 7)
-#define CFGCHIP2_PHY_PLLON (1 << 6) /* override PLL suspend */
-#define CFGCHIP2_SESENDEN (1 << 5) /* Vsess_end comparator */
-#define CFGCHIP2_VBDTCTEN (1 << 4) /* Vbus comparator */
-#define CFGCHIP2_REFFREQ (0xf << 0)
-#define CFGCHIP2_REFFREQ_12MHZ (1 << 0)
-#define CFGCHIP2_REFFREQ_24MHZ (2 << 0)
-#define CFGCHIP2_REFFREQ_48MHZ (3 << 0)
-
struct da8xx_ohci_root_hub;
typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub,
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 05/17] ARM: DTS: da850: Add usb phy node
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
Add a node for the new usb phy driver.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/boot/dts/da850.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 6bbf20d..33fcdce 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -376,6 +376,11 @@
>;
status = "disabled";
};
+ usb_phy: usb-phy {
+ compatible = "ti,da830-usb-phy";
+ #phy-cells = <1>;
+ status = "disabled";
+ };
gpio: gpio at 226000 {
compatible = "ti,dm6441-gpio";
gpio-controller;
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 04/17] ARM: DTS: da850: Add cfgchip syscon node
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
Add a syscon node for the SoC CFGCHIPn registers. This is needed for
the new usb phy driver.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/boot/dts/da850.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index f79e1b9..6bbf20d 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -188,6 +188,10 @@
};
};
+ cfgchip: cfgchip at 1417c {
+ compatible = "ti,da830-cfgchip", "syscon";
+ reg = <0x1417c 0x14>;
+ };
edma0: edma at 0 {
compatible = "ti,edma3-tpcc";
/* eDMA3 CC0: 0x01c0 0000 - 0x01c0 7fff */
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 03/17] ARM: davinci: da8xx: Add USB PHY platform declaration
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
There is now a proper phy driver for the DA8xx SoC USB PHY. This adds the
platform device declarations needed to use it.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 28 +++++-----------------------
arch/arm/mach-davinci/board-omapl138-hawk.c | 5 +++++
arch/arm/mach-davinci/include/mach/da8xx.h | 1 +
arch/arm/mach-davinci/usb-da8xx.c | 11 +++++++++++
4 files changed, 22 insertions(+), 23 deletions(-)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 3051cb6..c62766e 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -26,7 +26,6 @@
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
#include <linux/platform_data/spi-davinci.h>
-#include <linux/platform_data/usb-davinci.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -106,30 +105,8 @@ static irqreturn_t da830_evm_usb_ocic_irq(int irq, void *dev_id)
static __init void da830_evm_usb_init(void)
{
- u32 cfgchip2;
int ret;
- /*
- * Set up USB clock/mode in the CFGCHIP2 register.
- * FYI: CFGCHIP2 is 0x0000ef00 initially.
- */
- cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
-
- /*
- * We have to override VBUS/ID signals when MUSB is configured into the
- * host-only mode -- ID pin will float if no cable is connected, so the
- * controller won't be able to drive VBUS thinking that it's a B-device.
- * Otherwise, we want to use the OTG mode and enable VBUS comparators.
- */
- cfgchip2 &= ~CFGCHIP2_OTGMODE;
-#ifdef CONFIG_USB_MUSB_HOST
- cfgchip2 |= CFGCHIP2_FORCE_HOST;
-#else
- cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN;
-#endif
-
- __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
-
/* USB_REFCLKIN is not used. */
ret = da8xx_register_usb20_phy_clk(false);
if (ret)
@@ -141,6 +118,11 @@ static __init void da830_evm_usb_init(void)
pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
__func__, ret);
+ ret = da8xx_register_usb_phy();
+ if (ret)
+ pr_warn("%s: USB PHY registration failed: %d\n",
+ __func__, ret);
+
ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
if (ret)
pr_warn("%s: USB 2.0 PinMux setup failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 8691a25..c5cb8d9 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -260,6 +260,11 @@ static __init void omapl138_hawk_usb_init(void)
pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
__func__, ret);
+ ret = da8xx_register_usb_phy();
+ if (ret)
+ pr_warn("%s: USB PHY registration failed: %d\n",
+ __func__, ret);
+
ret = gpio_request_one(DA850_USB1_VBUS_PIN,
GPIOF_DIR_OUT, "USB1 VBUS");
if (ret < 0) {
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index c32444b..38d932e 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -92,6 +92,7 @@
int da8xx_register_usb_refclkin(int rate);
int da8xx_register_usb20_phy_clk(bool use_usb_refclkin);
int da8xx_register_usb11_phy_clk(bool use_usb_refclkin);
+int da8xx_register_usb_phy(void);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
int da8xx_register_emac(void);
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index c524d9e..9e41a7f 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -7,6 +7,7 @@
#include <linux/platform_data/usb-davinci.h>
#include <linux/platform_device.h>
#include <linux/mfd/da8xx-cfgchip.h>
+#include <linux/phy/phy.h>
#include <linux/usb/musb.h>
#include <mach/clock.h>
@@ -230,6 +231,16 @@ int __init da8xx_register_usb11_phy_clk(bool use_usb_refclkin)
return ret;
}
+static struct platform_device da8xx_usb_phy = {
+ .name = "da8xx-usb-phy",
+ .id = 0,
+};
+
+int __init da8xx_register_usb_phy(void)
+{
+ return platform_device_register(&da8xx_usb_phy);
+}
+
#if IS_ENABLED(CONFIG_USB_MUSB_HDRC)
static struct musb_hdrc_config musb_config = {
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 02/17] ARM: davinci: da8xx: Add CFGCHIP syscon platform declaration.
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
The CFGCHIP registers are used by a number of devices, so using a syscon
device to share them. The first consumer of this will by the phy-da8xx-usb
driver.
Signed-off-by: David Lechner <david@lechnology.com>
[Axel: minor fix: change id to -1]
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 4 ++++
arch/arm/mach-davinci/board-da850-evm.c | 4 ++++
arch/arm/mach-davinci/board-mityomapl138.c | 4 ++++
arch/arm/mach-davinci/board-omapl138-hawk.c | 4 ++++
arch/arm/mach-davinci/devices-da8xx.c | 28 ++++++++++++++++++++++++++++
arch/arm/mach-davinci/include/mach/da8xx.h | 2 ++
6 files changed, 46 insertions(+)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 605d444..3051cb6 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -586,6 +586,10 @@ static __init void da830_evm_init(void)
struct davinci_soc_info *soc_info = &davinci_soc_info;
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
ret = da830_register_gpio();
if (ret)
pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 8e4539f..ec5cb10 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1345,6 +1345,10 @@ static __init void da850_evm_init(void)
{
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
ret = da850_register_gpio();
if (ret)
pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
index bc4e63f..1a6d430 100644
--- a/arch/arm/mach-davinci/board-mityomapl138.c
+++ b/arch/arm/mach-davinci/board-mityomapl138.c
@@ -514,6 +514,10 @@ static void __init mityomapl138_init(void)
{
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
/* for now, no special EDMA channels are reserved */
ret = da850_register_edma(NULL);
if (ret)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index d4930b6..8691a25 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -294,6 +294,10 @@ static __init void omapl138_hawk_init(void)
{
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
ret = da850_register_gpio();
if (ret)
pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index add3771..31a99db 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -11,6 +11,7 @@
* (at your option) any later version.
*/
#include <linux/init.h>
+#include <linux/platform_data/syscon.h>
#include <linux/platform_device.h>
#include <linux/dma-contiguous.h>
#include <linux/serial_8250.h>
@@ -1089,3 +1090,30 @@ int __init da850_register_sata(unsigned long refclkpn)
return platform_device_register(&da850_sata_device);
}
#endif
+
+static struct syscon_platform_data da8xx_cfgchip_platform_data = {
+ .label = "cfgchip",
+};
+
+static struct resource da8xx_cfgchip_resources[] = {
+ {
+ .start = DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP0_REG,
+ .end = DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP4_REG + 3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device da8xx_cfgchip_device = {
+ .name = "syscon",
+ .id = -1,
+ .dev = {
+ .platform_data = &da8xx_cfgchip_platform_data,
+ },
+ .num_resources = ARRAY_SIZE(da8xx_cfgchip_resources),
+ .resource = da8xx_cfgchip_resources,
+};
+
+int __init da8xx_register_cfgchip(void)
+{
+ return platform_device_register(&da8xx_cfgchip_device);
+}
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index c367530..c32444b 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -61,6 +61,7 @@
#define DA8XX_CFGCHIP1_REG 0x180
#define DA8XX_CFGCHIP2_REG 0x184
#define DA8XX_CFGCHIP3_REG 0x188
+#define DA8XX_CFGCHIP4_REG 0x18c
#define DA8XX_SYSCFG1_BASE (IO_PHYS + 0x22C000)
#define DA8XX_SYSCFG1_VIRT(x) (da8xx_syscfg1_base + (x))
@@ -116,6 +117,7 @@
int da8xx_register_rproc(void);
int da850_register_gpio(void);
int da830_register_gpio(void);
+int da8xx_register_cfgchip(void);
extern struct platform_device da8xx_serial_device[];
extern struct emac_platform_data da8xx_emac_pdata;
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 01/17] ARM: davinci: da8xx: add usb phy clocks
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
Up to this point, the USB phy clock configuration was handled manually in
the board files and in the usb drivers. This adds proper clocks so that
the usb drivers can use clk_get and clk_enable and not have to worry about
the details. Also, the related code is removed from the board files and
replaced with the new clock registration functions.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 22 ++-
arch/arm/mach-davinci/board-omapl138-hawk.c | 16 +-
arch/arm/mach-davinci/include/mach/da8xx.h | 3 +
arch/arm/mach-davinci/usb-da8xx.c | 219 +++++++++++++++++++++++++++-
4 files changed, 239 insertions(+), 21 deletions(-)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 3d8cf8c..605d444 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -115,18 +115,6 @@ static __init void da830_evm_usb_init(void)
*/
cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
- /* USB2.0 PHY reference clock is 24 MHz */
- cfgchip2 &= ~CFGCHIP2_REFFREQ;
- cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
-
- /*
- * Select internal reference clock for USB 2.0 PHY
- * and use it as a clock source for USB 1.1 PHY
- * (this is the default setting anyway).
- */
- cfgchip2 &= ~CFGCHIP2_USB1PHYCLKMUX;
- cfgchip2 |= CFGCHIP2_USB2PHYCLKMUX;
-
/*
* We have to override VBUS/ID signals when MUSB is configured into the
* host-only mode -- ID pin will float if no cable is connected, so the
@@ -143,6 +131,16 @@ static __init void da830_evm_usb_init(void)
__raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
/* USB_REFCLKIN is not used. */
+ ret = da8xx_register_usb20_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 2.0 PHY CLK registration failed: %d\n",
+ __func__, ret);
+
+ ret = da8xx_register_usb11_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
+ __func__, ret);
+
ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
if (ret)
pr_warn("%s: USB 2.0 PinMux setup failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index ee62486..d4930b6 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -243,7 +243,6 @@ static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id)
static __init void omapl138_hawk_usb_init(void)
{
int ret;
- u32 cfgchip2;
ret = davinci_cfg_reg_list(da850_hawk_usb11_pins);
if (ret) {
@@ -251,12 +250,15 @@ static __init void omapl138_hawk_usb_init(void)
return;
}
- /* Setup the Ref. clock frequency for the HAWK at 24 MHz. */
-
- cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
- cfgchip2 &= ~CFGCHIP2_REFFREQ;
- cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
- __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ /* USB_REFCLKIN is not used. */
+ ret = da8xx_register_usb20_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 2.0 PHY CLK registration failed: %d\n",
+ __func__, ret);
+ ret = da8xx_register_usb11_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
+ __func__, ret);
ret = gpio_request_one(DA850_USB1_VBUS_PIN,
GPIOF_DIR_OUT, "USB1 VBUS");
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index f9f9713..c367530 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -88,6 +88,9 @@
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
int da8xx_register_spi_bus(int instance, unsigned num_chipselect);
int da8xx_register_watchdog(void);
+int da8xx_register_usb_refclkin(int rate);
+int da8xx_register_usb20_phy_clk(bool use_usb_refclkin);
+int da8xx_register_usb11_phy_clk(bool use_usb_refclkin);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
int da8xx_register_emac(void);
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index f141f51..c524d9e 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -1,20 +1,235 @@
/*
* DA8xx USB
*/
-#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <linux/platform_data/usb-davinci.h>
#include <linux/platform_device.h>
+#include <linux/mfd/da8xx-cfgchip.h>
#include <linux/usb/musb.h>
+#include <mach/clock.h>
#include <mach/common.h>
#include <mach/cputype.h>
#include <mach/da8xx.h>
-#include <mach/irqs.h>
+
+#include "clock.h"
#define DA8XX_USB0_BASE 0x01e00000
#define DA8XX_USB1_BASE 0x01e25000
+static struct clk usb_refclkin = {
+ .name = "usb_refclkin",
+ .set_rate = davinci_simple_set_rate,
+};
+
+static struct clk_lookup usb_refclkin_lookup =
+ CLK(NULL, "usb_refclkin", &usb_refclkin);
+
+/**
+ * da8xx_register_usb_refclkin - register USB_REFCLKIN clock
+ *
+ * @rate: The clock rate in Hz
+ *
+ * This clock is only needed if the board provides an external USB_REFCLKIN
+ * signal, in which case it will be used as the parent of usb20_phy_clk and/or
+ * usb11_phy_clk.
+ */
+int __init da8xx_register_usb_refclkin(int rate)
+{
+ int ret;
+
+ usb_refclkin.rate = rate;
+ ret = clk_register(&usb_refclkin);
+ if (ret)
+ return ret;
+
+ clkdev_add(&usb_refclkin_lookup);
+
+ return 0;
+}
+
+static void usb20_phy_clk_enable(struct clk *clk)
+{
+ u32 val;
+ u32 timeout = 500000; /* 500 msec */
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /*
+ * Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1
+ * host may use the PLL clock without USB 2.0 OTG being used.
+ */
+ val &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN);
+ val |= CFGCHIP2_PHY_PLLON;
+
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ while (--timeout) {
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ if (val & CFGCHIP2_PHYCLKGD)
+ return;
+ udelay(1);
+ }
+
+ pr_err("Timeout waiting for USB 2.0 PHY clock good.\n");
+}
+
+static void usb20_phy_clk_disable(struct clk *clk)
+{
+ u32 val;
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ val |= CFGCHIP2_PHYPWRDN;
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+}
+
+static int usb20_phy_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 val;
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /* Set the mux depending on the parent clock. */
+ if (parent == &usb_refclkin) {
+ val &= ~CFGCHIP2_USB2PHYCLKMUX;
+ } else if (strcmp(parent->name, "pll0_aux_clk") == 0) {
+ val |= CFGCHIP2_USB2PHYCLKMUX;
+ } else {
+ pr_err("Bad parent on USB 2.0 PHY clock.\n");
+ return -EINVAL;
+ }
+
+ /* reference frequency also comes from parent clock */
+ val &= ~CFGCHIP2_REFFREQ_MASK;
+ switch (clk_get_rate(parent)) {
+ case 12000000:
+ val |= CFGCHIP2_REFFREQ_12MHZ;
+ break;
+ case 13000000:
+ val |= CFGCHIP2_REFFREQ_13MHZ;
+ break;
+ case 19200000:
+ val |= CFGCHIP2_REFFREQ_19_2MHZ;
+ break;
+ case 20000000:
+ val |= CFGCHIP2_REFFREQ_20MHZ;
+ break;
+ case 24000000:
+ val |= CFGCHIP2_REFFREQ_24MHZ;
+ break;
+ case 26000000:
+ val |= CFGCHIP2_REFFREQ_26MHZ;
+ break;
+ case 38400000:
+ val |= CFGCHIP2_REFFREQ_38_4MHZ;
+ break;
+ case 40000000:
+ val |= CFGCHIP2_REFFREQ_40MHZ;
+ break;
+ case 48000000:
+ val |= CFGCHIP2_REFFREQ_48MHZ;
+ break;
+ default:
+ pr_err("Bad parent clock rate on USB 2.0 PHY clock.\n");
+ return -EINVAL;
+ }
+
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ return 0;
+}
+
+static struct clk usb20_phy_clk = {
+ .name = "usb20_phy",
+ .clk_enable = usb20_phy_clk_enable,
+ .clk_disable = usb20_phy_clk_disable,
+ .set_parent = usb20_phy_clk_set_parent,
+};
+
+static struct clk_lookup usb20_phy_clk_lookup =
+ CLK(NULL, "usb20_phy", &usb20_phy_clk);
+
+/**
+ * da8xx_register_usb20_phy_clk - register USB0PHYCLKMUX clock
+ *
+ * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true
+ * or "pll0_aux" if false.
+ */
+int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin)
+{
+ struct clk *parent;
+ int ret = 0;
+
+ parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "pll0_aux");
+ if (IS_ERR(parent))
+ return PTR_ERR(parent);
+
+ usb20_phy_clk.parent = parent;
+ ret = clk_register(&usb20_phy_clk);
+ if (!ret)
+ clkdev_add(&usb20_phy_clk_lookup);
+
+ clk_put(parent);
+
+ return ret;
+}
+
+static int usb11_phy_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 val;
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /* Set the USB 1.1 PHY clock mux based on the parent clock. */
+ if (parent == &usb20_phy_clk) {
+ val &= ~CFGCHIP2_USB1PHYCLKMUX;
+ } else if (parent == &usb_refclkin) {
+ val |= CFGCHIP2_USB1PHYCLKMUX;
+ } else {
+ pr_err("Bad parent on USB 1.1 PHY clock.\n");
+ return -EINVAL;
+ }
+
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ return 0;
+}
+
+static struct clk usb11_phy_clk = {
+ .name = "usb11_phy",
+ .set_parent = usb11_phy_clk_set_parent,
+};
+
+static struct clk_lookup usb11_phy_clk_lookup =
+ CLK(NULL, "usb11_phy", &usb11_phy_clk);
+
+/**
+ * da8xx_register_usb11_phy_clk - register USB1PHYCLKMUX clock
+ *
+ * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true
+ * or "usb20_phy" if false.
+ */
+int __init da8xx_register_usb11_phy_clk(bool use_usb_refclkin)
+{
+ struct clk *parent;
+ int ret = 0;
+
+ parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "usb20_phy");
+ if (IS_ERR(parent))
+ return PTR_ERR(parent);
+
+ usb11_phy_clk.parent = parent;
+ ret = clk_register(&usb11_phy_clk);
+ if (!ret)
+ clkdev_add(&usb11_phy_clk_lookup);
+
+ clk_put(parent);
+
+ return ret;
+}
+
#if IS_ENABLED(CONFIG_USB_MUSB_HDRC)
static struct musb_hdrc_config musb_config = {
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 00/17] Add DT support for ohci-da8xx
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
From: Axel Haslam <ahaslam@baylibre.com>
The purpose of this patch series is to add DT support and modernize
the ohci-da8xx glue driver without breaking the non-DT boot,
which is still used in unconverted davinci devices.
The first couple of patches, are the recent and ongoing efforts from
David Lechner to clean up davinci-mach code and the ochi-da8xx driver,
Im including these patches on this series for completeness sake.
Then I re-based an old patch by Manjunath Goudar[4] to be able to build
the driver as a module. We can now add this patch because we removed
references to sysconf registers by using David's patches.
Then I prepare the stage for a DT boot which does not depend on any
mach-arch/* callbacks by using a regulator to handle the vbus and
over current gpios. For this, i extended the fixed regulator driver to
register for an irq and send a regulator notification if an over curent
pin is specified.
The only dependency left for this series is the recently re-posted patch
by David to remove references to mach-code[1], which is approved and
should be picked up soon.
Note 1: Testing was done on a omap138-lcdk board, using DT, and non-DT boot,
and checking that in both cases the hub, usb mass storage and an input
device are correctly enumerated and working. The omap138-lcdk does not
have gpios to control vbus and get over current interrupt notifications.
If anyone has a da830-evm based board and could confirm that ohci is
correctly working, i would appreciate it.
(the OHCI option needs to be enabled in menuconfig)
Note 2: It seems that the davinci-gpio driver is broken for DT based boot
and any gpio > 32. (luckly none of the DT based boards use gpios yet)
The issue is discussed here [2]
Note 3: A git branch based on tag: next-20161021 with the dependencies
is available in my github here [3].
[1] usb: ohci-da8xx: Remove code that references mach
http://marc.info/?l=linux-kernel&m=147632744323084&w=4
[2] thread about invalid gpio in davinci
http://www.gossamer-threads.com/lists/linux/kernel/2550178
[3] Git branch:
https://github.com/axelhaslamx/linux-axel/commits/ohci-da8xx-dt-v2.1
[4] Separate ohci-da8xx driver patch
https://patches.linaro.org/patch/18234/
Changes from v1->v2
* Rebased and added patch to make ohci a separate driver
* Use a regulator instead of handling Gpios (David Lechner)
* Add an overcurrent mode to regulator framework
* Fixed regulator is able to register for and overcurrent irq
* Added patch by Alexandre to remove build warnings
* Moved global variables into private hcd structure.
Alexandre Bailon (1):
ARM: davinci: da8xx: Fix some redefined symbol warnings
Axel Haslam (10):
ARM: davinci: da8xx: Enable the usb20 "per" clk on phy_clk_enable
ARM: davinci: hawk: add full constraints for ohci plat boot
regulator: fixed: Add over current event
USB: da8xx: use flag instead of bitmask for over current change
USB: ochi-da8xx: Use a regulator for vbus/overcurrent
USB: da8xx: use ohci priv data instead of globals
ARM: davinci: register the usb20_phy clock on the DT file
usb: host: ohci-da8xx: Add devicetree bindings documentation
USB: ohci-da8xx: Allow probing from DT
ARM: dts: da850: add usb device node
David Lechner (5):
ARM: davinci: da8xx: add usb phy clocks
ARM: davinci: da8xx: Add CFGCHIP syscon platform declaration.
ARM: davinci: da8xx: Add USB PHY platform declaration
ARM: DTS: da850: Add cfgchip syscon node
ARM: DTS: da850: Add usb phy node
Manjunath Goudar (1):
USB: OHCI: make ohci-da8xx a separate driver
.../bindings/regulator/fixed-regulator.txt | 4 +
.../devicetree/bindings/usb/ohci-da8xx.txt | 39 +++
arch/arm/boot/dts/da850-lcdk.dts | 8 +
arch/arm/boot/dts/da850.dtsi | 17 +
arch/arm/mach-davinci/board-da830-evm.c | 152 +++-----
arch/arm/mach-davinci/board-da850-evm.c | 4 +
arch/arm/mach-davinci/board-mityomapl138.c | 4 +
arch/arm/mach-davinci/board-omapl138-hawk.c | 122 ++-----
arch/arm/mach-davinci/da8xx-dt.c | 2 +
arch/arm/mach-davinci/devices-da8xx.c | 28 ++
arch/arm/mach-davinci/include/mach/da8xx.h | 8 +-
arch/arm/mach-davinci/usb-da8xx.c | 244 ++++++++++++-
drivers/regulator/fixed.c | 64 ++++
drivers/usb/host/Kconfig | 2 +-
drivers/usb/host/Makefile | 1 +
drivers/usb/host/ohci-da8xx.c | 382 +++++++++++----------
drivers/usb/host/ohci-hcd.c | 18 -
include/linux/platform_data/usb-davinci.h | 43 ---
include/linux/regulator/consumer.h | 5 +
include/linux/regulator/fixed.h | 3 +
20 files changed, 703 insertions(+), 447 deletions(-)
create mode 100644 Documentation/devicetree/bindings/usb/ohci-da8xx.txt
--
1.9.1
^ permalink raw reply
* [PATCH 3/4] iommu/arm-smmu: Add context save restore support
From: Mathieu Poirier @ 2016-10-24 16:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477070066-15044-4-git-send-email-sricharan@codeaurora.org>
On 21 October 2016 at 11:14, Sricharan R <sricharan@codeaurora.org> wrote:
> The smes registers and the context bank registers are
> the ones that are needs to be saved and restored.
> Fortunately the smes are already stored as a part
> of the smmu device structure. So just write that
> back. The data required to configure the context banks
> are the master's domain data and pgtable cfgs.
> So store them as a part of the context banks info
> and just reconfigure the context banks on the restore
> path.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
> drivers/iommu/arm-smmu.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 51 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index 45f2762..578cdc2 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -328,6 +328,11 @@ struct arm_smmu_master_cfg {
> #define for_each_cfg_sme(fw, i, idx) \
> for (i = 0; idx = __fwspec_cfg(fw)->smendx[i], i < fw->num_ids; ++i)
>
> +struct cbinfo {
> + struct arm_smmu_domain *domain;
> + struct io_pgtable_cfg pgtbl_cfg;
> +};
> +
> struct arm_smmu_device {
> struct device *dev;
>
> @@ -378,6 +383,9 @@ struct arm_smmu_device {
> struct clk **clocks;
>
> u32 cavium_id_base; /* Specific to Cavium */
> +
> + /* For save/restore of context bank registers */
> + struct cbinfo *cb_saved_ctx;
It's not that clear to me this will become an array - better
documentation would help reviewing the code.
> };
>
> enum arm_smmu_context_fmt {
> @@ -972,6 +980,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
>
> /* Initialise the context bank with our page table cfg */
> arm_smmu_init_context_bank(smmu_domain, &pgtbl_cfg);
> + smmu->cb_saved_ctx[cfg->cbndx].domain = smmu_domain;
> + smmu->cb_saved_ctx[cfg->cbndx].pgtbl_cfg = pgtbl_cfg;
>
> /*
> * Request context fault interrupt. Do this last to avoid the
> @@ -1861,6 +1871,10 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
> }
> dev_notice(smmu->dev, "\t%u context banks (%u stage-2 only)\n",
> smmu->num_context_banks, smmu->num_s2_context_banks);
> +
> + smmu->cb_saved_ctx = devm_kzalloc(smmu->dev,
> + sizeof(struct cbinfo) * smmu->num_context_banks,
> + GFP_KERNEL);
> /*
> * Cavium CN88xx erratum #27704.
> * Ensure ASID and VMID allocation is unique across all SMMUs in
> @@ -2115,8 +2129,44 @@ static int arm_smmu_resume(struct device *dev)
> {
> struct platform_device *pdev = to_platform_device(dev);
> struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
> + struct arm_smmu_domain *domain = NULL;
> + struct io_pgtable_cfg *pgtbl_cfg = NULL;
> + struct arm_smmu_smr *smrs = smmu->smrs;
> + int i = 0, idx, cb, ret, pcb = 0;
> +
> + ret = arm_smmu_enable_clocks(smmu);
> + if (ret)
> + return ret;
> +
> + arm_smmu_device_reset(smmu);
>
> - return arm_smmu_enable_clocks(smmu);
> + /* Restore the smes and the context banks */
> + for (idx = 0; idx < smmu->num_mapping_groups; ++idx) {
> + mutex_lock(&smmu->stream_map_mutex);
> + if (!smrs[idx].valid) {
> + mutex_unlock(&smmu->stream_map_mutex);
> + continue;
> + }
> +
> + arm_smmu_write_sme(smmu, idx);
> + cb = smmu->s2crs[idx].cbndx;
> + mutex_unlock(&smmu->stream_map_mutex);
> +
> + if (!i || (cb != pcb)) {
> + domain = smmu->cb_saved_ctx[cb].domain;
> + pgtbl_cfg = &smmu->cb_saved_ctx[cb].pgtbl_cfg;
> +
> + if (domain) {
> + mutex_lock(&domain->init_mutex);
> + arm_smmu_init_context_bank(domain, pgtbl_cfg);
> + mutex_unlock(&domain->init_mutex);
> + }
> + }
> + pcb = cb;
> + i++;
What are you doing with variable 'i'? Again, some comments would
greatly help with reviewing.
Thanks,
Mathieu
> + }
> +
> + return 0;
> }
>
> static int arm_smmu_suspend(struct device *dev)
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
>
>
> _______________________________________________
> 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] arm64: Neaten show_regs, remove KERN_CONT
From: Mark Rutland @ 2016-10-24 16:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477326477.1984.2.camel@perches.com>
On Mon, Oct 24, 2016 at 09:27:57AM -0700, Joe Perches wrote:
> On Mon, 2016-10-24 at 12:31 +0100, Mark Rutland wrote:
> > On Sun, Oct 23, 2016 at 01:40:49PM -0700, Joe Perches wrote:
> > > commit db4b0710fae9 ("arm64: fix show_regs fallout from KERN_CONT changes")
> > > corrected the KERN_CONT fallout from commit 4bcc595ccd80
> > > ("printk: reinstate KERN_CONT for printing continuation lines"), but
> > > the code still has unnecessary KERN_CONT uses. Remove them.
> >
> > Why are these unnecessary KERN_CONTs a larger problem than duplicating
> > the format string for a third time? Having to duplicate it at all was
> > annoying enough.
>
> Not printing partial lines is the best solution to avoiding
> message output interleaving.
Would you mind mentioning that explicitly in the commit message? That
makes it obvious what the benefit of avoiding KERN_CONT is.
> > Overall, to avoid messing with the KERN_CONT mess it'd be nicer to
> > format this all into a buffer (with the format string only existing the
> > once) and subsequently print it with one printk call
>
> A single printk call would get one timestamp which would
> make for ragged/staggered reading.
That does not appear to be the case; as fr as I can tell the core prints a
timestamp per line as required. If I run:
printk("TEST\nLINE1\nLINE2\nLINE3\nLINE4\n");
... with "printk.time=1", over the UART:
[ 41.201864] TEST
[ 41.201864] LINE1
[ 41.201864] LINE2
[ 41.201864] LINE3
[ 41.201864] LINE4
... with "printk.time=1", via the $(dmesg):
[ 41.201864] TEST
[ 41.201864] LINE1
[ 41.201864] LINE2
[ 41.201864] LINE3
[ 41.201864] LINE4
... with "printk.time=0", over the UART:
TEST
LINE1
LINE2
LINE3
LINE4
... with "printk.time=0", via the $(dmesg):
TEST
LINE1
LINE2
LINE3
LINE4
... with "printk.time=0", via $(dmesg -T):
[Mon Oct 24 17:38:37 2016] TEST
[Mon Oct 24 17:38:37 2016] LINE1
[Mon Oct 24 17:38:37 2016] LINE2
[Mon Oct 24 17:38:37 2016] LINE3
[Mon Oct 24 17:38:37 2016] LINE4
Thanks,
Mark.
^ permalink raw reply
* [PATCH 2/4] iommu/arm-smmu: Add pm_runtime/sleep ops
From: Mathieu Poirier @ 2016-10-24 16:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477070066-15044-3-git-send-email-sricharan@codeaurora.org>
On 21 October 2016 at 11:14, Sricharan R <sricharan@codeaurora.org> wrote:
> The smmu needs to be functional when the respective
> master/s using it are active. As there is a device_link
> between the master and smmu, the pm runtime ops for the smmu
> gets invoked in sync with the master's runtime, thus the
> smmu remains powered only when needed.
>
> There are couple of places in the driver during probe,
> master attach, where the smmu needs to be clocked without
> the context of the master. So doing a pm_runtime_get/put sync
> in those places separately.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
> drivers/iommu/arm-smmu.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 108 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index 083489e4..45f2762 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -45,6 +45,7 @@
> #include <linux/of_iommu.h>
> #include <linux/pci.h>
> #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
>
> @@ -373,6 +374,8 @@ struct arm_smmu_device {
> u32 num_global_irqs;
> u32 num_context_irqs;
> unsigned int *irqs;
> + int num_clocks;
> + struct clk **clocks;
>
> u32 cavium_id_base; /* Specific to Cavium */
> };
> @@ -430,6 +433,31 @@ static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
> return container_of(dom, struct arm_smmu_domain, domain);
> }
>
> +static int arm_smmu_enable_clocks(struct arm_smmu_device *smmu)
> +{
> + int i, ret = 0;
> +
> + for (i = 0; i < smmu->num_clocks; ++i) {
> + ret = clk_prepare_enable(smmu->clocks[i]);
> + if (ret) {
> + dev_err(smmu->dev, "Couldn't enable clock #%d\n", i);
> + while (i--)
> + clk_disable_unprepare(smmu->clocks[i]);
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static void arm_smmu_disable_clocks(struct arm_smmu_device *smmu)
> +{
> + int i;
> +
> + for (i = 0; i < smmu->num_clocks; ++i)
> + clk_disable_unprepare(smmu->clocks[i]);
> +}
> +
> static void parse_driver_options(struct arm_smmu_device *smmu)
> {
> int i = 0;
> @@ -1187,11 +1215,13 @@ static void arm_smmu_master_free_smes(struct iommu_fwspec *fwspec)
> int i, idx;
>
> mutex_lock(&smmu->stream_map_mutex);
> + pm_runtime_get_sync(smmu->dev);
Since this is generic code it is probably a good idea to check the
return value, same for _put_sync() below.
> for_each_cfg_sme(fwspec, i, idx) {
> if (arm_smmu_free_sme(smmu, idx))
> arm_smmu_write_sme(smmu, idx);
> cfg->smendx[i] = INVALID_SMENDX;
> }
> + pm_runtime_put_sync(smmu->dev);
> mutex_unlock(&smmu->stream_map_mutex);
> }
>
> @@ -1424,9 +1454,11 @@ static int arm_smmu_add_device(struct device *dev)
> while (i--)
> cfg->smendx[i] = INVALID_SMENDX;
>
> + pm_runtime_get_sync(smmu->dev);
> ret = arm_smmu_master_alloc_smes(dev);
> if (ret)
> goto out_free;
> + pm_runtime_put_sync(smmu->dev);
>
> return 0;
>
> @@ -1650,6 +1682,44 @@ static int arm_smmu_id_size_to_bits(int size)
> }
> }
>
> +static int arm_smmu_init_clocks(struct arm_smmu_device *smmu)
> +{
> + const char *cname;
> + struct property *prop;
> + int i;
> + struct device *dev = smmu->dev;
> +
> + smmu->num_clocks =
> + of_property_count_strings(dev->of_node, "clock-names");
> +
> + if (smmu->num_clocks < 1)
> + return 0;
> +
> + smmu->clocks = devm_kzalloc(dev,
> + sizeof(*smmu->clocks) * smmu->num_clocks,
> + GFP_KERNEL);
> +
> + if (!smmu->clocks) {
> + dev_err(dev, "Failed to allocate memory for clocks\n");
> + return -ENODEV;
> + }
> +
> + i = 0;
Please do the initialisation above when you declare the variable.
> + of_property_for_each_string(dev->of_node, "clock-names", prop, cname) {
> + struct clk *c = devm_clk_get(dev, cname);
> +
> + if (IS_ERR(c)) {
> + dev_err(dev, "Couldn't get clock: %s", cname);
> + return -EPROBE_DEFER;
> + }
> +
> + smmu->clocks[i] = c;
> + ++i;
> + }
> +
> + return 0;
> +}
> +
> static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
> {
> unsigned long size;
> @@ -1968,6 +2038,13 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
> smmu->irqs[i] = irq;
> }
>
> + err = arm_smmu_init_clocks(smmu);
> + if (err)
> + return err;
> +
> + platform_set_drvdata(pdev, smmu);
> + pm_runtime_enable(dev);
> + pm_runtime_get_sync(dev);
> err = arm_smmu_device_cfg_probe(smmu);
> if (err)
> return err;
> @@ -1996,8 +2073,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
> }
>
> of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
> - platform_set_drvdata(pdev, smmu);
> arm_smmu_device_reset(smmu);
> + pm_runtime_put_sync(dev);
>
> /* Oh, for a proper bus abstraction */
> if (!iommu_present(&platform_bus_type))
> @@ -2027,13 +2104,43 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
>
> /* Turn the thing off */
> writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
> +
> + pm_runtime_force_suspend(smmu->dev);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int arm_smmu_resume(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
> +
> + return arm_smmu_enable_clocks(smmu);
> +}
> +
> +static int arm_smmu_suspend(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
> +
> + arm_smmu_disable_clocks(smmu);
> +
> return 0;
> }
> +#endif
> +
> +static const struct dev_pm_ops arm_smmu_pm_ops = {
> + SET_RUNTIME_PM_OPS(arm_smmu_suspend, arm_smmu_resume, NULL)
> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> + pm_runtime_force_resume)
> +};
>
> static struct platform_driver arm_smmu_driver = {
> .driver = {
> .name = "arm-smmu",
> .of_match_table = of_match_ptr(arm_smmu_of_match),
> + .pm = &arm_smmu_pm_ops,
> },
> .probe = arm_smmu_device_dt_probe,
> .remove = arm_smmu_device_remove,
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
>
>
> _______________________________________________
> 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 2/6] thermal: bcm2835: add thermal driver for bcm2835 soc
From: Eric Anholt @ 2016-10-24 16:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <eaff4043-5a62-da2d-cee1-9962b8c4783a@i2se.com>
Stefan Wahren <stefan.wahren@i2se.com> writes:
> Hi Martin,
>
> Am 28.09.2016 um 23:10 schrieb Eric Anholt:
>> kernel at martin.sperl.org writes:
>>
>>> From: Martin Sperl <kernel@martin.sperl.org>
>>>
>>> Add basic thermal driver for bcm2835 SOC.
>>>
>>> This driver currently relies on the firmware setting up the
>>> tsense HW block and does not set it up itself.
>>>
>>> Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
>>> Acked-by: Eric Anholt <eric@anholt.net>
>>> Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
>> What's the status of merging this one? I'd like to merge the other
>> patches.
>
> i think it's necessary to rebase the whole series. Maybe we could get it
> into 4.10.
Why would it need to be rebased? The status, as far as I know, is that
we're still waiting for the subsystem maintainer to respond.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161024/5f37774f/attachment.sig>
^ permalink raw reply
* [PATCH 02/18] arm64: ilp32: add documentation on the ILP32 ABI for ARM64
From: Chris Metcalf @ 2016-10-24 16:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477081997-4770-3-git-send-email-ynorov@caviumnetworks.com>
On 10/21/2016 4:33 PM, Yury Norov wrote:
> Based on Andrew Pinski's patch-series.
>
> Signed-off-by: Yury Norov <ynorov@caviumnetworks.com>
> ---
> Documentation/arm64/ilp32.txt | 46 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 46 insertions(+)
> create mode 100644 Documentation/arm64/ilp32.txt
>
> diff --git a/Documentation/arm64/ilp32.txt b/Documentation/arm64/ilp32.txt
> new file mode 100644
> index 0000000..b96c18f
> --- /dev/null
> +++ b/Documentation/arm64/ilp32.txt
> @@ -0,0 +1,46 @@
> +ILP32 AARCH64 SYSCALL ABI
> +=========================
> +
> +This document describes the ILP32 syscall ABI and where it differs
> +from the generic compat linux syscall interface.
> +
> +AARCH64/ILP32 userspace can potentially access top halves of registers that
> +are passed as syscall arguments, so such registers (w0-w7) are deloused.
I'm not sure what "potentially access" here means: I think what you want to say
is that userspace can pass garbage in the top half, but you should be clearer about
what you mean here. Also, you shouldn't use "deloused" here, since it's not a term
that's defined elsewhere in the kernel, even though it's been used colloquially on LKML.
Provide an actual implementation definition, like "have their top 32 bits zeroed".
> +AARCH64/ILP32 provides next types turned to 64-bit (comparing to AARCH32):
What does "turned" mean here? And I "next types" isn't standard English; you want
to say something like "the following types". Likewise later with "next syscalls".
--
Chris Metcalf, Mellanox Technologies
http://www.mellanox.com
^ permalink raw reply
* [PATCH 01/18] 32-bit ABI: introduce ARCH_32BIT_OFF_T config option
From: Chris Metcalf @ 2016-10-24 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477081997-4770-2-git-send-email-ynorov@caviumnetworks.com>
On 10/21/2016 4:33 PM, Yury Norov wrote:
> All new 32-bit architectures should have 64-bit off_t type, but existing
> architectures has 32-bit ones.
>
> [...]
> For syscalls sys_openat() and sys_open_by_handle_at() force_o_largefile()
> is called, to set O_LARGEFILE flag, and this is the only difference
> comparing to compat versions. All compat ABIs are already turned to use
> 64-bit off_t, except tile. So, compat versions for this syscalls are not
> needed anymore. Tile is handled explicitly.
>
> [...]
> --- a/arch/tile/kernel/compat.c
> +++ b/arch/tile/kernel/compat.c
> @@ -103,6 +103,9 @@ COMPAT_SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned int, offset_high,
> #define compat_sys_readahead sys32_readahead
> #define sys_llseek compat_sys_llseek
>
> +#define sys_openat compat_sys_openat
> +#define sys_open_by_handle_at compat_sys_open_by_handle_at
> +
> /* Call the assembly trampolines where necessary. */
> #define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn
> #define sys_clone _sys_clone
This patch accomplishes two goals that could be completely separated.
It's confusing to have them mixed in the same patch without any
discussion of why they are in the same patch.
First, you want to modify the default <asm/unistd.h> behavior for
compat syscalls so that the default is sys_openat (etc) rather than
the existing compat_sys_openat, and then use that new behavior for
arm64 ILP32. This lets you force O_LARGEFILE for arm64 ILP32 to
support having a 64-bit off_t at all times. To do that, you fix the
asm-generic header, and then make tile have a special override.
This seems reasonable enough.
Second, you introduce ARCH_32BIT_OFF_T basically as a synonym for
"BITS_PER_WORD == 32", so that new 32-bit architectures can choose not
to enable it. This is fine in the abstract, but I'm a bit troubled by
the fact that you are not actually introducing a new 32-bit
architecture here (just a new 32-bit mode for the arm 64-bit kernel).
Shouldn't this part of the change wait until someone actually has a
new 32-bit kernel to drive this forward?
If you want to push forward the ARCH_32BIT_OFF_T change in the absence
of an architecture that supports it, I would think it would be a lot
less confusing to have these two in separate patches, and make it
clear that the ARCH_32BIT_OFF_T change is just laying groundwork
for some hypothetical future architecture.
The existing commit language itself is also confusing. You write "All
compat ABIs are already turned to use 64-bit off_t, except tile."
First, I'm not sure what you mean by "turned" here. And, tile is just
one of many compat ABIs that allow O_LARGEFILE not to be part of the
open call: see arm64's AArch32 ABI, MIPS o32, s390 31-bit emulation,
sparc64's 32-bit mode, and of course x86's 32-bit compat mode.
Presumably your point here is that tile is the only pre-existing
architecture that #includes <asm/unistd.h> to create its compat
syscall table, and so I think "all except tile" here is particularly
confusing, since there are no architectures except tile that use the
__SYSCALL_COMPAT functionality in the current tree.
--
Chris Metcalf, Mellanox Technologies
http://www.mellanox.com
^ permalink raw reply
* [PATCH] arm64: Neaten show_regs, remove KERN_CONT
From: Joe Perches @ 2016-10-24 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024113131.GH15620@leverpostej>
On Mon, 2016-10-24 at 12:31 +0100, Mark Rutland wrote:
> On Sun, Oct 23, 2016 at 01:40:49PM -0700, Joe Perches wrote:
> > commit db4b0710fae9 ("arm64: fix show_regs fallout from KERN_CONT changes")
> > corrected the KERN_CONT fallout from commit 4bcc595ccd80
> > ("printk: reinstate KERN_CONT for printing continuation lines"), but
> > the code still has unnecessary KERN_CONT uses. Remove them.
>
> Why are these unnecessary KERN_CONTs a larger problem than duplicating
> the format string for a third time? Having to duplicate it at all was
> annoying enough.
Not printing partial lines is the best solution to avoiding
message output interleaving.
> Overall, to avoid messing with the KERN_CONT mess it'd be nicer to
> format this all into a buffer (with the format string only existing the
> once) and subsequently print it with one printk call
A single printk call would get one timestamp which would
make for ragged/staggered reading.
^ permalink raw reply
* [PATCH v5 2/4] arm64: dts: add Allwinner A64 SoC .dtsi
From: Maxime Ripard @ 2016-10-24 16:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <a0b71433-8302-8ac2-a695-60ac813b380f@arm.com>
Hi Andr?,
On Mon, Oct 24, 2016 at 12:57:04AM +0100, Andr? Przywara wrote:
> > + pio: pinctrl at 1c20800 {
> > + compatible = "allwinner,sun50i-a64-pinctrl";
> > + reg = <0x01c20800 0x400>;
> > + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
> > + <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
> > + <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_PIO>;
> > + gpio-controller;
> > + #gpio-cells = <3>;
> > + interrupt-controller;
> > + #interrupt-cells = <3>;
> > +
> > + i2c1_pins: i2c1_pins {
> > + allwinner,pins = "PH2", "PH3";
> > + allwinner,function = "i2c1";
>
> So as Icenowy pointed out, we are missing the drive and pull properties
> here, at least as long as we don't have your patch (series) in place to
> cope with that.
Yeah sorry, we noticed first with Chen-Yu that the binding should not
need it, and then we realised that the driver was making the
assumption that they were... Sorry :/
> But if we rely on this series (which seems OK to me), shouldn't we then
> use the generic properties for pins and function here as well?
Definitely. I'll update this.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161024/2b6d6f3f/attachment.sig>
^ permalink raw reply
* [PATCH V7 2/6] thermal: bcm2835: add thermal driver for bcm2835 soc
From: Stefan Wahren @ 2016-10-24 16:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87twczg27x.fsf@eliezer.anholt.net>
Hi Martin,
Am 28.09.2016 um 23:10 schrieb Eric Anholt:
> kernel at martin.sperl.org writes:
>
>> From: Martin Sperl <kernel@martin.sperl.org>
>>
>> Add basic thermal driver for bcm2835 SOC.
>>
>> This driver currently relies on the firmware setting up the
>> tsense HW block and does not set it up itself.
>>
>> Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
>> Acked-by: Eric Anholt <eric@anholt.net>
>> Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
> What's the status of merging this one? I'd like to merge the other
> patches.
i think it's necessary to rebase the whole series. Maybe we could get it
into 4.10.
Stefan
^ permalink raw reply
* [PATCH 37/37] perf coresight: Removing miscellaneous debug output
From: Arnaldo Carvalho de Melo @ 2016-10-24 16:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477326057-24080-1-git-send-email-acme@kernel.org>
From: Mathieu Poirier <mathieu.poirier@linaro.org>
Printing the full path of the selected link is obviously not needed,
hence removing.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-arm-kernel at lists.infradead.org
Link: http://lkml.kernel.org/r/1476913323-6836-1-git-send-email-mathieu.poirier at linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/arch/arm/util/cs-etm.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 47d584da5819..dfea6b635525 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -575,8 +575,6 @@ static FILE *cs_device__open_file(const char *name)
snprintf(path, PATH_MAX,
"%s" CS_BUS_DEVICE_PATH "%s", sysfs, name);
- printf("path: %s\n", path);
-
if (stat(path, &st) < 0)
return NULL;
--
2.7.4
^ permalink raw reply related
* [PATCH] arm/arm64: KVM: Perform local TLB invalidation when multiplexing vcpus on a single CPU
From: Mark Rutland @ 2016-10-24 16:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477323088-18768-1-git-send-email-marc.zyngier@arm.com>
Hi Marc,
On Mon, Oct 24, 2016 at 04:31:28PM +0100, Marc Zyngier wrote:
> Architecturally, TLBs are private to the (physical) CPU they're
> associated with. But when multiple vcpus from the same VM are
> being multiplexed on the same CPU, the TLBs are not private
> to the vcpus (and are actually shared across the VMID).
>
> Let's consider the following scenario:
>
> - vcpu-0 maps PA to VA
> - vcpu-1 maps PA' to VA
>
> If run on the same physical CPU, vcpu-1 can hit TLB entries generated
> by vcpu-0 accesses, and access the wrong physical page.
It might be worth noting that this could also lead to TLB conflicts and
other such fun usually associated with missing TLB maintenance,
depending on the two mappings (or the intermediate stages thereof).
> The solution to this is to keep a per-VM map of which vcpu ran last
> on each given physical CPU, and invalidate local TLBs when switching
> to a different vcpu from the same VM.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Modulo my comment on preemptiblity of kvm_arch_sched_in, everything
below is a nit. Assuming that's not preemptible, this looks right to me.
FWIW, with or without the other comments considered:
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
> ---
> arch/arm/include/asm/kvm_host.h | 5 +++++
> arch/arm/include/asm/kvm_hyp.h | 1 +
> arch/arm/kvm/arm.c | 35 ++++++++++++++++++++++++++++++++++-
> arch/arm/kvm/hyp/switch.c | 9 +++++++++
> arch/arm64/include/asm/kvm_host.h | 6 +++++-
> arch/arm64/kvm/hyp/switch.c | 8 ++++++++
> 6 files changed, 62 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 2d19e02..035e744 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -57,6 +57,8 @@ struct kvm_arch {
> /* VTTBR value associated with below pgd and vmid */
> u64 vttbr;
>
> + int __percpu *last_vcpu_ran;
> +
> /* Timer */
> struct arch_timer_kvm timer;
>
> @@ -174,6 +176,9 @@ struct kvm_vcpu_arch {
> /* vcpu power-off state */
> bool power_off;
>
> + /* TLBI required */
> + bool requires_tlbi;
A bit of a nit, but it's not clear which class of TLBI is required, or
why. It's probably worth a comment (and perhaps a bikeshed), like:
/*
* Local TLBs potentially contain conflicting entries from
* another vCPU within this VMID. All entries for this VMID must
* be invalidated from (local) TLBs before we run this vCPU.
*/
bool tlb_vmid_stale;
[...]
> +void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
> +{
> + int *last_ran;
> +
> + last_ran = per_cpu_ptr(vcpu->kvm->arch.last_vcpu_ran, cpu);
> +
> + /*
> + * If we're very unlucky and get preempted before having ran
> + * this vcpu for real, we'll end-up in a situation where any
> + * vcpu that gets scheduled will perform an invalidation (this
> + * vcpu explicitely requires it, and all the others will have
> + * a different vcpu_id).
> + */
Nit: s/explicitely/explicitly/
To bikeshed a little further, perhaps:
/*
* We might get preempted before the vCPU actually runs, but
* this is fine. Our TLBI stays pending until we actually make
* it to __activate_vm, so we won't miss a TLBI. If another vCPU
* gets scheduled, it will see our vcpu_id in last_ran, and pend
* a TLBI for itself.
*/
> + if (*last_ran != vcpu->vcpu_id) {
> + if (*last_ran != -1)
> + vcpu->arch.requires_tlbi = true;
> +
> + *last_ran = vcpu->vcpu_id;
> + }
> +}
I take it this function is run in some non-preemptible context; if so,
this looks correct to me.
If this is preemptible, then this looks racy.
Thanks,
Mark.
^ permalink raw reply
* [PATCH v3 [fix]] PM / doc: Update device documentation for devices in IRQ safe PM domains
From: Lina Iyer @ 2016-10-24 16:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1900178.E2KGyKAlTm@vostro.rjw.lan>
On Sat, Oct 22 2016 at 18:19 -0600, Rafael J. Wysocki wrote:
>On Friday, October 21, 2016 03:52:55 PM Lina Iyer wrote:
>> Update documentation to reflect the changes made to support IRQ safe PM
>> domains.
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
>> ---
>> Changes since v3:
>> - Moved para to the end of the section
>> - Added clause for all IRQ safe devices in a domain
>> - Cleanup explanation of nested domains
>> ---
>> Documentation/power/devices.txt | 11 ++++++++++-
>> 1 file changed, 10 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
>> index 8ba6625..9218ce6 100644
>> --- a/Documentation/power/devices.txt
>> +++ b/Documentation/power/devices.txt
>> @@ -607,7 +607,9 @@ individually. Instead, a set of devices sharing a power resource can be put
>> into a low-power state together at the same time by turning off the shared
>> power resource. Of course, they also need to be put into the full-power state
>> together, by turning the shared power resource on. A set of devices with this
>> -property is often referred to as a power domain.
>> +property is often referred to as a power domain. A power domain may also be
>> +nested inside another power domain. The nested domain is referred to as the
>> +sub-domain of the parent domain.
>>
>> Support for power domains is provided through the pm_domain field of struct
>> device. This field is a pointer to an object of type struct dev_pm_domain,
>> @@ -629,6 +631,13 @@ support for power domains into subsystem-level callbacks, for example by
>> modifying the platform bus type. Other platforms need not implement it or take
>> it into account in any way.
>>
>> +Devices and PM domains may be defined as IRQ-safe, if they can be powered
>> +on/off even when the IRQs are disabled.
>
>What IRQ-safe means for devices is that their runtime PM callbacks may be
>invoked with interrupts disabled on the local CPU. I guess the meaning of
>IRQ-safe for PM domains is analogous, but the above isn't precise enough to me.
>
>> An IRQ-safe device in a domain will
>> +disallow power management on the domain, unless the domain is also defined as
>> +IRQ-safe. In other words, a domain containing all IRQ-safe devices must also
>> +be defined as IRQ-safe. Another restriction this framework imposes on the
>> +parent domain of an IRQ-safe domain is that the parent domain must also be
>> +defined as IRQ-safe.
>
>What about this:
>
>"Devices may be defined as IRQ-safe which indicates to the PM core that their
>runtime PM callbacks may be invoked with disabled interrupts (see
>Documentation/power/runtime_pm.txt for more information). If an IRQ-safe
>device belongs to a PM domain, the runtime PM of the domain will be disallowed,
>unless the domain itself is defined as IRQ-safe. However, a PM domain can only
>be defined as IRQ-safe if all of the devices in it are IRQ-safe.
>
This is correct. But the last line may need a bit of modification. If
all devices in a PM domain are IRQ-safe and the domain is NOT, then it
it is a valid combination just that the domain would never do runtime
PM.
> Moreover, if
>an IRQ-safe domain has a parent domain, the runtime PM of the parent is only
>allowed if the parent itself is IRQ-safe too with the additional restriction
>that all child domains of an IRQ-safe parent must also be IRQ-safe."
>
>Does it actually reflect what the code does?
>
Yes, this precisely reflects the code.
Thanks,
Lina
^ permalink raw reply
* Disabling an interrupt in the handler locks the system up
From: Mason @ 2016-10-24 16:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <580BF1D4.2030509@free.fr>
On 23/10/2016 01:10, Mason wrote:
> Maybe the fact that disable_irq locks the system up is an orthogonal
> issue that needs to be fixed anyway.
disable_irq_nosync() eventually calls irq_disable()
void irq_disable(struct irq_desc *desc)
{
irq_state_set_disabled(desc);
if (desc->irq_data.chip->irq_disable) {
desc->irq_data.chip->irq_disable(&desc->irq_data);
irq_state_set_masked(desc);
} else if (irq_settings_disable_unlazy(desc)) {
mask_irq(desc);
}
}
irq_disable() is a NOP on my platform, because the intc driver does
not implement irq_disable, and the second test is false as well in
this instance.
The function's description is interesting.
/**
* irq_disable - Mark interrupt disabled
* @desc: irq descriptor which should be disabled
*
* If the chip does not implement the irq_disable callback, we
* use a lazy disable approach. That means we mark the interrupt
* disabled, but leave the hardware unmasked. That's an
* optimization because we avoid the hardware access for the
* common case where no interrupt happens after we marked it
* disabled. If an interrupt happens, then the interrupt flow
* handler masks the line at the hardware level and marks it
* pending.
*
* If the interrupt chip does not implement the irq_disable callback,
* a driver can disable the lazy approach for a particular irq line by
* calling 'irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)'. This can
* be used for devices which cannot disable the interrupt at the
* device level under certain circumstances and have to use
* disable_irq[_nosync] instead.
*/
(I assume "chip" and "interrupt chip" refer to the same abstraction.)
I took a look at commit e9849777d0e27, but my brain dumped core on
the notions of "disabling unlazy" and "disabling a disable".
* IRQ_DISABLE_UNLAZY - Disable lazy irq disable
For the record, setting the IRQ_DISABLE_UNLAZY flag for this device
makes the system lock-up disappear.
Regards.
^ permalink raw reply
* [PATCH v4 4/9] clk: sunxi-ng: Add minimums for all the relevant structures and clocks
From: Maxime Ripard @ 2016-10-24 16:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <72be1b2a-e2db-7220-aa49-96d22860100c@arm.com>
On Fri, Oct 21, 2016 at 11:57:11PM +0100, Andr? Przywara wrote:
> Salut,
>
> On 11/10/16 15:28, Maxime Ripard wrote:
> > Modify the current clocks we have to be able to specify the minimum for
> > each clocks we support, just like we support the max.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> > drivers/clk/sunxi-ng/ccu_mult.c | 7 ++++++-
> > drivers/clk/sunxi-ng/ccu_nk.c | 12 ++++++++----
> > drivers/clk/sunxi-ng/ccu_nkm.c | 18 ++++++++++++------
> > drivers/clk/sunxi-ng/ccu_nkmp.c | 16 ++++++++++++----
> > drivers/clk/sunxi-ng/ccu_nm.c | 12 ++++++++----
> > 5 files changed, 46 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c
> > index 32a1964439a2..6a02ffee5386 100644
> > --- a/drivers/clk/sunxi-ng/ccu_mult.c
> > +++ b/drivers/clk/sunxi-ng/ccu_mult.c
> > @@ -14,7 +14,7 @@
> > #include "ccu_mult.h"
> >
> > struct _ccu_mult {
> > - unsigned long mult, max;
> > + unsigned long mult, min, max;
> > };
> >
> > static void ccu_mult_find_best(unsigned long parent, unsigned long rate,
> > @@ -23,6 +23,9 @@ static void ccu_mult_find_best(unsigned long parent, unsigned long rate,
> > int _mult;
> >
> > _mult = rate / parent;
> > + if (_mult < mult->min)
> > + _mult = mult->min;
> > +
> > if (_mult > mult->max)
> > _mult = mult->max;
> >
> > @@ -37,6 +40,7 @@ static unsigned long ccu_mult_round_rate(struct ccu_mux_internal *mux,
> > struct ccu_mult *cm = data;
> > struct _ccu_mult _cm;
> >
> > + _cm.min = 1;
> > _cm.max = 1 << cm->mult.width;
> > ccu_mult_find_best(parent_rate, rate, &_cm);
> >
> > @@ -101,6 +105,7 @@ static int ccu_mult_set_rate(struct clk_hw *hw, unsigned long rate,
> > ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1,
> > &parent_rate);
> >
> > + _cm.min = 1;
> > _cm.max = 1 << cm->mult.width;
> > ccu_mult_find_best(parent_rate, rate, &_cm);
> >
> > diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c
> > index e7e2e75618ef..a42d870ba0ef 100644
> > --- a/drivers/clk/sunxi-ng/ccu_nk.c
> > +++ b/drivers/clk/sunxi-ng/ccu_nk.c
> > @@ -14,8 +14,8 @@
> > #include "ccu_nk.h"
> >
> > struct _ccu_nk {
> > - unsigned long n, max_n;
> > - unsigned long k, max_k;
> > + unsigned long n, min_n, max_n;
> > + unsigned long k, min_k, max_k;
> > };
> >
> > static void ccu_nk_find_best(unsigned long parent, unsigned long rate,
> > @@ -25,8 +25,8 @@ static void ccu_nk_find_best(unsigned long parent, unsigned long rate,
> > unsigned int best_k = 0, best_n = 0;
> > unsigned int _k, _n;
> >
> > - for (_k = 1; _k <= nk->max_k; _k++) {
> > - for (_n = 1; _n <= nk->max_n; _n++) {
> > + for (_k = nk->min_k; _k <= nk->max_k; _k++) {
> > + for (_n = nk->min_n; _n <= nk->max_n; _n++) {
> > unsigned long tmp_rate = parent * _n * _k;
> >
> > if (tmp_rate > rate)
> > @@ -97,7 +97,9 @@ static long ccu_nk_round_rate(struct clk_hw *hw, unsigned long rate,
> > if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
> > rate *= nk->fixed_post_div;
> >
> > + _nk.min_n = 1;
> > _nk.max_n = 1 << nk->n.width;
> > + _nk.min_k = 1;
> > _nk.max_k = 1 << nk->k.width;
> >
> > ccu_nk_find_best(*parent_rate, rate, &_nk);
> > @@ -120,7 +122,9 @@ static int ccu_nk_set_rate(struct clk_hw *hw, unsigned long rate,
> > if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
> > rate = rate * nk->fixed_post_div;
> >
> > + _nk.min_n = 1;
> > _nk.max_n = 1 << nk->n.width;
> > + _nk.min_k = 1;
> > _nk.max_k = 1 << nk->k.width;
> >
> > ccu_nk_find_best(parent_rate, rate, &_nk);
> > diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
> > index 0b08d000eb38..b2a5fccf2f8c 100644
> > --- a/drivers/clk/sunxi-ng/ccu_nkm.c
> > +++ b/drivers/clk/sunxi-ng/ccu_nkm.c
> > @@ -14,9 +14,9 @@
> > #include "ccu_nkm.h"
> >
> > struct _ccu_nkm {
> > - unsigned long n, max_n;
> > - unsigned long k, max_k;
> > - unsigned long m, max_m;
> > + unsigned long n, min_n, max_n;
> > + unsigned long k, min_k, max_k;
> > + unsigned long m, min_m, max_m;
> > };
> >
> > static void ccu_nkm_find_best(unsigned long parent, unsigned long rate,
> > @@ -26,9 +26,9 @@ static void ccu_nkm_find_best(unsigned long parent, unsigned long rate,
> > unsigned long best_n = 0, best_k = 0, best_m = 0;
> > unsigned long _n, _k, _m;
> >
> > - for (_k = 1; _k <= nkm->max_k; _k++) {
> > - for (_n = 1; _n <= nkm->max_n; _n++) {
> > - for (_m = 1; _n <= nkm->max_m; _m++) {
> > + for (_k = nkm->min_k; _k <= nkm->max_k; _k++) {
> > + for (_n = nkm->min_n; _n <= nkm->max_n; _n++) {
> > + for (_m = nkm->min_m; _n <= nkm->max_m; _m++) {
>
> should be _m in the condition
>
> > unsigned long tmp_rate;
> >
> > tmp_rate = parent * _n * _k / _m;
> > @@ -100,8 +100,11 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
> > struct ccu_nkm *nkm = data;
> > struct _ccu_nkm _nkm;
> >
> > + _nkm.min_n = 1;
> > _nkm.max_n = 1 << nkm->n.width;
> > + _nkm.min_k = 1;
> > _nkm.max_k = 1 << nkm->k.width;
> > + _nkm.min_m = 1;
> > _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width;
> >
> > ccu_nkm_find_best(parent_rate, rate, &_nkm);
> > @@ -126,8 +129,11 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
> > unsigned long flags;
> > u32 reg;
> >
> > + _nkm.min_n = 1;
> > _nkm.max_n = 1 << nkm->n.width;
> > + _nkm.min_k = 1;
> > _nkm.max_k = 1 << nkm->k.width;
> > + _nkm.min_m = 1;
> > _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width;
> >
> > ccu_nkm_find_best(parent_rate, rate, &_nkm);
> > diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
> > index 4b457d8cce11..2c1398192e48 100644
> > --- a/drivers/clk/sunxi-ng/ccu_nkmp.c
> > +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
> > @@ -27,10 +27,10 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
> > unsigned long best_n = 0, best_k = 0, best_m = 0, best_p = 0;
> > unsigned long _n, _k, _m, _p;
> >
> > - for (_k = 1; _k <= nkmp->max_k; _k++) {
> > - for (_n = 1; _n <= nkm->max_n; _n++) {
> > - for (_m = 1; _n <= nkm->max_m; _m++) {
> > - for (_p = 1; _p <= nkmp->max_p; _p <<= 1) {
> > + for (_k = nkmp->min_k; _k <= nkmp->max_k; _k++) {
> > + for (_n = nkmp->min_n; _n <= nkmp->max_n; _n++) {
> > + for (_m = nkmp->min_m; _n <= nkmp->max_m; _m++) {
>
> Same here: _m <= ...
>
> > + for (_p = nkmp->min_p; _p <= nkmp->max_p; _p <<= 1) {
> > unsigned long tmp_rate;
> >
> > tmp_rate = parent * _n * _k / (_m * _p);
> > @@ -107,9 +107,13 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
> > struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
> > struct _ccu_nkmp _nkmp;
> >
> > + _nkmp.min_n = 1;
> > _nkmp.max_n = 1 << nkmp->n.width;
> > + _nkmp.min_k = 1;
> > _nkmp.max_k = 1 << nkmp->k.width;
> > + _nkmp.min_m = 1;
> > _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width;
> > + _nkmp.min_p = 1;
> > _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1);
> >
> > ccu_nkmp_find_best(*parent_rate, rate, &_nkmp);
> > @@ -125,9 +129,13 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
> > unsigned long flags;
> > u32 reg;
> >
> > + _nkmp.min_n = 1;
> > _nkmp.max_n = 1 << nkmp->n.width;
> > + _nkmp.min_k = 1;
> > _nkmp.max_k = 1 << nkmp->k.width;
> > + _nkmp.min_m = 1;
> > _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width;
> > + _nkmp.min_p = 1;
> > _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1);
> >
> > ccu_nkmp_find_best(parent_rate, rate, &_nkmp);
> > diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
> > index c6d652289320..2a190bc032a9 100644
> > --- a/drivers/clk/sunxi-ng/ccu_nm.c
> > +++ b/drivers/clk/sunxi-ng/ccu_nm.c
> > @@ -15,8 +15,8 @@
> > #include "ccu_nm.h"
> >
> > struct _ccu_nm {
> > - unsigned long n, max_n;
> > - unsigned long m, max_m;
> > + unsigned long n, min_n, max_n;
> > + unsigned long m, min_m, max_m;
> > };
> >
> > static void ccu_nm_find_best(unsigned long parent, unsigned long rate,
> > @@ -26,8 +26,8 @@ static void ccu_nm_find_best(unsigned long parent, unsigned long rate,
> > unsigned long best_n = 0, best_m = 0;
> > unsigned long _n, _m;
> >
> > - for (_n = 1; _n <= nm->max_n; _n++) {
> > - for (_m = 1; _n <= nm->max_m; _m++) {
> > + for (_n = nm->min_n; _n <= nm->max_n; _n++) {
> > + for (_m = nm->min_m; _n <= nm->max_m; _m++) {
>
> And here: _m <= ...
>
> Interestingly those typos were already in the code before.
Good catches, I've amended the commit in my branch (since I apparently
forgot to push...). Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161024/c7ee7fb8/attachment.sig>
^ 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