* [PATCH v2 0/7] counter: Simplify count_read/count_write/signal_read
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
Changes in v2:
- Update the rest of the drivers under drivers/counter
The changes in this patchset will not affect the userspace interface.
Rather, these changes are intended to simplify the kernelspace Counter
callbacks for counter device driver authors.
The following main changes are proposed:
* Retire the opaque counter_count_read_value/counter_count_write_value
structures and simply represent count data as an unsigned integer.
* Retire the opaque counter_signal_read_value structure and represent
Signal data as a counter_signal_value enum.
These changes should reduce some complexity and code in the use and
implementation of the count_read, count_write, and signal_read
callbacks.
The opaque structures for Count data and Signal data were introduced
originally in anticipation of supporting various representations of
counter data (e.g. arbitrary-precision tallies, floating-point spherical
coordinate positions, etc). However, with the counter device drivers
that have appeared, it's become apparent that utilizing opaque
structures in kernelspace is not the best approach to take.
I believe it is best to let userspace applications decide how to
interpret the count data they receive. There are a couple of reasons why
it would be good to do so:
* Users use their devices in unexpected ways.
For example, a quadrature encoder counter device is typically used to
keep track of the position of a motor, but a user could set the device
in a pulse-direction mode and instead use it to count sporadic rising
edges from an arbitrary signal line unrelated to positioning. Users
should have the freedom to decide what their data represents.
* Most counter devices represent data as unsigned integers anyway.
For example, whether the device is a tally counter or position
counter, the count data is represented to the user as an unsigned
integer value. So specifying that one device is representing tallies
while the other specifies positions does not provide much utility from
an interface perspective.
For these reasons, the count_read and count_write callbacks have been
redefined to pass count data directly as unsigned long instead of passed
via opaque structures:
count_read(struct counter_device *counter,
struct counter_count *count, unsigned long *val);
count_write(struct counter_device *counter,
struct counter_count *count, unsigned long val);
Similarly, the signal_read is redefined to pass Signal data directly as
a counter_signal_value enum instead of via an opaque structure:
signal_read(struct counter_device *counter,
struct counter_signal *signal,
enum counter_signal_value *val);
The counter_signal_value enum is simply the counter_signal_level enum
redefined to remove the references to the Signal data "level" data type.
William Breathitt Gray (7):
counter: Simplify the count_read and count_write callbacks
counter: Simplify the signal_read callback
docs: driver-api: generic-counter: Update Count and Signal data types
counter: 104-quad-8: Update count_read/count_write/signal_read
callbacks
counter: ftm-quaddec: Update count_read and count_write callbacks
counter: stm32-lptimer-cnt: Update count_read callback
counter: stm32-timer-cnt: Update count_read and count_write callbacks
Documentation/driver-api/generic-counter.rst | 22 ++--
drivers/counter/104-quad-8.c | 33 ++----
drivers/counter/counter.c | 101 +++----------------
drivers/counter/ftm-quaddec.c | 14 +--
drivers/counter/stm32-lptimer-cnt.c | 5 +-
drivers/counter/stm32-timer-cnt.c | 17 +---
include/linux/counter.h | 74 ++------------
7 files changed, 53 insertions(+), 213 deletions(-)
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 1/7] counter: Simplify the count_read and count_write callbacks
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
The count_read and count_write callbacks are simplified to pass val as
unsigned long rather than as an opaque data structure. The opaque
counter_count_read_value and counter_count_write_value structures,
counter_count_value_type enum, and relevant counter_count_read_value_set
and counter_count_write_value_get functions, are removed as they are no
longer used.
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/counter/counter.c | 66 +++++----------------------------------
include/linux/counter.h | 43 +++----------------------
2 files changed, 12 insertions(+), 97 deletions(-)
diff --git a/drivers/counter/counter.c b/drivers/counter/counter.c
index 106bc7180cd8..1d08f1437b1b 100644
--- a/drivers/counter/counter.c
+++ b/drivers/counter/counter.c
@@ -246,60 +246,6 @@ void counter_signal_read_value_set(struct counter_signal_read_value *const val,
}
EXPORT_SYMBOL_GPL(counter_signal_read_value_set);
-/**
- * counter_count_read_value_set - set counter_count_read_value data
- * @val: counter_count_read_value structure to set
- * @type: property Count data represents
- * @data: Count data
- *
- * This function sets an opaque counter_count_read_value structure with the
- * provided Count data.
- */
-void counter_count_read_value_set(struct counter_count_read_value *const val,
- const enum counter_count_value_type type,
- void *const data)
-{
- switch (type) {
- case COUNTER_COUNT_POSITION:
- val->len = sprintf(val->buf, "%lu\n", *(unsigned long *)data);
- break;
- default:
- val->len = 0;
- }
-}
-EXPORT_SYMBOL_GPL(counter_count_read_value_set);
-
-/**
- * counter_count_write_value_get - get counter_count_write_value data
- * @data: Count data
- * @type: property Count data represents
- * @val: counter_count_write_value structure containing data
- *
- * This function extracts Count data from the provided opaque
- * counter_count_write_value structure and stores it at the address provided by
- * @data.
- *
- * RETURNS:
- * 0 on success, negative error number on failure.
- */
-int counter_count_write_value_get(void *const data,
- const enum counter_count_value_type type,
- const struct counter_count_write_value *const val)
-{
- int err;
-
- switch (type) {
- case COUNTER_COUNT_POSITION:
- err = kstrtoul(val->buf, 0, data);
- if (err)
- return err;
- break;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(counter_count_write_value_get);
-
struct counter_attr_parm {
struct counter_device_attr_group *group;
const char *prefix;
@@ -788,13 +734,13 @@ static ssize_t counter_count_show(struct device *dev,
const struct counter_count_unit *const component = devattr->component;
struct counter_count *const count = component->count;
int err;
- struct counter_count_read_value val = { .buf = buf };
+ unsigned long val;
err = counter->ops->count_read(counter, count, &val);
if (err)
return err;
- return val.len;
+ return sprintf(buf, "%lu\n", val);
}
static ssize_t counter_count_store(struct device *dev,
@@ -806,9 +752,13 @@ static ssize_t counter_count_store(struct device *dev,
const struct counter_count_unit *const component = devattr->component;
struct counter_count *const count = component->count;
int err;
- struct counter_count_write_value val = { .buf = buf };
+ unsigned long val;
+
+ err = kstrtoul(buf, 0, &val);
+ if (err)
+ return err;
- err = counter->ops->count_write(counter, count, &val);
+ err = counter->ops->count_write(counter, count, val);
if (err)
return err;
diff --git a/include/linux/counter.h b/include/linux/counter.h
index a061cdcdef7c..7e40796598a6 100644
--- a/include/linux/counter.h
+++ b/include/linux/counter.h
@@ -300,24 +300,6 @@ struct counter_signal_read_value {
size_t len;
};
-/**
- * struct counter_count_read_value - Opaque Count read value
- * @buf: string representation of Count read value
- * @len: length of string in @buf
- */
-struct counter_count_read_value {
- char *buf;
- size_t len;
-};
-
-/**
- * struct counter_count_write_value - Opaque Count write value
- * @buf: string representation of Count write value
- */
-struct counter_count_write_value {
- const char *buf;
-};
-
/**
* struct counter_ops - Callbacks from driver
* @signal_read: optional read callback for Signal attribute. The read
@@ -328,15 +310,10 @@ struct counter_count_write_value {
* signal_read callback.
* @count_read: optional read callback for Count attribute. The read
* value of the respective Count should be passed back via
- * the val parameter. val points to an opaque type which
- * should be set only by calling the
- * counter_count_read_value_set function from within the
- * count_read callback.
+ * the val parameter.
* @count_write: optional write callback for Count attribute. The write
* value for the respective Count is passed in via the val
- * parameter. val points to an opaque type which should be
- * accessed only by calling the
- * counter_count_write_value_get function.
+ * parameter.
* @function_get: function to get the current count function mode. Returns
* 0 on success and negative error code on error. The index
* of the respective Count's returned function mode should
@@ -357,11 +334,9 @@ struct counter_ops {
struct counter_signal *signal,
struct counter_signal_read_value *val);
int (*count_read)(struct counter_device *counter,
- struct counter_count *count,
- struct counter_count_read_value *val);
+ struct counter_count *count, unsigned long *val);
int (*count_write)(struct counter_device *counter,
- struct counter_count *count,
- struct counter_count_write_value *val);
+ struct counter_count *count, unsigned long val);
int (*function_get)(struct counter_device *counter,
struct counter_count *count, size_t *function);
int (*function_set)(struct counter_device *counter,
@@ -486,19 +461,9 @@ enum counter_signal_value_type {
COUNTER_SIGNAL_LEVEL = 0
};
-enum counter_count_value_type {
- COUNTER_COUNT_POSITION = 0,
-};
-
void counter_signal_read_value_set(struct counter_signal_read_value *const val,
const enum counter_signal_value_type type,
void *const data);
-void counter_count_read_value_set(struct counter_count_read_value *const val,
- const enum counter_count_value_type type,
- void *const data);
-int counter_count_write_value_get(void *const data,
- const enum counter_count_value_type type,
- const struct counter_count_write_value *const val);
int counter_register(struct counter_device *const counter);
void counter_unregister(struct counter_device *const counter);
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 2/7] counter: Simplify the signal_read callback
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
The signal_read callback is simplified to pass val as a
counter_signal_val enum rather than as an opaque data structure. The
opaque counter_signal_read_value structure and relevant
counter_signal_read_value_set function are removed as they are no longer
used. In addition, the counter_signal_level enum is replaced by the
similar counter_signal_value enum.
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/counter/counter.c | 35 +++++++----------------------------
include/linux/counter.h | 31 +++++--------------------------
2 files changed, 12 insertions(+), 54 deletions(-)
diff --git a/drivers/counter/counter.c b/drivers/counter/counter.c
index 1d08f1437b1b..6a683d086008 100644
--- a/drivers/counter/counter.c
+++ b/drivers/counter/counter.c
@@ -220,32 +220,6 @@ ssize_t counter_device_enum_available_read(struct counter_device *counter,
}
EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
-static const char *const counter_signal_level_str[] = {
- [COUNTER_SIGNAL_LEVEL_LOW] = "low",
- [COUNTER_SIGNAL_LEVEL_HIGH] = "high"
-};
-
-/**
- * counter_signal_read_value_set - set counter_signal_read_value data
- * @val: counter_signal_read_value structure to set
- * @type: property Signal data represents
- * @data: Signal data
- *
- * This function sets an opaque counter_signal_read_value structure with the
- * provided Signal data.
- */
-void counter_signal_read_value_set(struct counter_signal_read_value *const val,
- const enum counter_signal_value_type type,
- void *const data)
-{
- if (type == COUNTER_SIGNAL_LEVEL)
- val->len = sprintf(val->buf, "%s\n",
- counter_signal_level_str[*(enum counter_signal_level *)data]);
- else
- val->len = 0;
-}
-EXPORT_SYMBOL_GPL(counter_signal_read_value_set);
-
struct counter_attr_parm {
struct counter_device_attr_group *group;
const char *prefix;
@@ -315,6 +289,11 @@ struct counter_signal_unit {
struct counter_signal *signal;
};
+static const char *const counter_signal_value_str[] = {
+ [COUNTER_SIGNAL_LOW] = "low",
+ [COUNTER_SIGNAL_HIGH] = "high"
+};
+
static ssize_t counter_signal_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -323,13 +302,13 @@ static ssize_t counter_signal_show(struct device *dev,
const struct counter_signal_unit *const component = devattr->component;
struct counter_signal *const signal = component->signal;
int err;
- struct counter_signal_read_value val = { .buf = buf };
+ enum counter_signal_value val;
err = counter->ops->signal_read(counter, signal, &val);
if (err)
return err;
- return val.len;
+ return sprintf(buf, "%s\n", counter_signal_value_str[val]);
}
struct counter_name_unit {
diff --git a/include/linux/counter.h b/include/linux/counter.h
index 7e40796598a6..32fb4d8cc3fd 100644
--- a/include/linux/counter.h
+++ b/include/linux/counter.h
@@ -290,24 +290,16 @@ struct counter_device_state {
const struct attribute_group **groups;
};
-/**
- * struct counter_signal_read_value - Opaque Signal read value
- * @buf: string representation of Signal read value
- * @len: length of string in @buf
- */
-struct counter_signal_read_value {
- char *buf;
- size_t len;
+enum counter_signal_value {
+ COUNTER_SIGNAL_LOW = 0,
+ COUNTER_SIGNAL_HIGH
};
/**
* struct counter_ops - Callbacks from driver
* @signal_read: optional read callback for Signal attribute. The read
* value of the respective Signal should be passed back via
- * the val parameter. val points to an opaque type which
- * should be set only by calling the
- * counter_signal_read_value_set function from within the
- * signal_read callback.
+ * the val parameter.
* @count_read: optional read callback for Count attribute. The read
* value of the respective Count should be passed back via
* the val parameter.
@@ -332,7 +324,7 @@ struct counter_signal_read_value {
struct counter_ops {
int (*signal_read)(struct counter_device *counter,
struct counter_signal *signal,
- struct counter_signal_read_value *val);
+ enum counter_signal_value *val);
int (*count_read)(struct counter_device *counter,
struct counter_count *count, unsigned long *val);
int (*count_write)(struct counter_device *counter,
@@ -452,19 +444,6 @@ struct counter_device {
void *priv;
};
-enum counter_signal_level {
- COUNTER_SIGNAL_LEVEL_LOW = 0,
- COUNTER_SIGNAL_LEVEL_HIGH
-};
-
-enum counter_signal_value_type {
- COUNTER_SIGNAL_LEVEL = 0
-};
-
-void counter_signal_read_value_set(struct counter_signal_read_value *const val,
- const enum counter_signal_value_type type,
- void *const data);
-
int counter_register(struct counter_device *const counter);
void counter_unregister(struct counter_device *const counter);
int devm_counter_register(struct device *dev,
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 3/7] docs: driver-api: generic-counter: Update Count and Signal data types
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
Count data is now always represented as an unsigned integer, while
Signal data is either SIGNAL_LOW or SIGNAL_HIGH.
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
Documentation/driver-api/generic-counter.rst | 22 +++++++-------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/Documentation/driver-api/generic-counter.rst b/Documentation/driver-api/generic-counter.rst
index 8382f01a53e3..161652fc1025 100644
--- a/Documentation/driver-api/generic-counter.rst
+++ b/Documentation/driver-api/generic-counter.rst
@@ -39,10 +39,7 @@ There are three core components to a counter:
COUNT
-----
A Count represents the count data for a set of Signals. The Generic
-Counter interface provides the following available count data types:
-
-* COUNT_POSITION:
- Unsigned integer value representing position.
+Counter interface represents the count data as an unsigned integer.
A Count has a count function mode which represents the update behavior
for the count data. The Generic Counter interface provides the following
@@ -93,19 +90,16 @@ SIGNAL
A Signal represents a counter input data; this is the input data that is
evaluated by the counter to determine the count data; e.g. a quadrature
signal output line of a rotary encoder. Not all counter devices provide
-user access to the Signal data.
-
-The Generic Counter interface provides the following available signal
-data types for when the Signal data is available for user access:
+user access to the Signal data, so exposure is optional for drivers.
-* SIGNAL_LEVEL:
- Signal line state level. The following states are possible:
+When the Signal data is available for user access, the Generic Counter
+interface provides the following available signal values:
- - SIGNAL_LEVEL_LOW:
- Signal line is in a low state.
+* SIGNAL_LOW:
+ Signal line is in a low state.
- - SIGNAL_LEVEL_HIGH:
- Signal line is in a high state.
+* SIGNAL_HIGH:
+ Signal line is in a high state.
A Signal may be associated with one or more Counts.
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 4/7] counter: 104-quad-8: Update count_read/count_write/signal_read callbacks
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
The count_read and count_write callbacks pass unsigned long now, while
the signal_read callback passes an enum counter_signal_value.
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/counter/104-quad-8.c | 33 ++++++++++-----------------------
1 file changed, 10 insertions(+), 23 deletions(-)
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 00b113f4b958..17e67a84777d 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -562,11 +562,10 @@ static const struct iio_chan_spec quad8_channels[] = {
};
static int quad8_signal_read(struct counter_device *counter,
- struct counter_signal *signal, struct counter_signal_read_value *val)
+ struct counter_signal *signal, enum counter_signal_value *val)
{
const struct quad8_iio *const priv = counter->priv;
unsigned int state;
- enum counter_signal_level level;
/* Only Index signal levels can be read */
if (signal->id < 16)
@@ -575,22 +574,19 @@ static int quad8_signal_read(struct counter_device *counter,
state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
& BIT(signal->id - 16);
- level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
-
- counter_signal_read_value_set(val, COUNTER_SIGNAL_LEVEL, &level);
+ *val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
return 0;
}
static int quad8_count_read(struct counter_device *counter,
- struct counter_count *count, struct counter_count_read_value *val)
+ struct counter_count *count, unsigned long *val)
{
const struct quad8_iio *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id;
unsigned int flags;
unsigned int borrow;
unsigned int carry;
- unsigned long position;
int i;
flags = inb(base_offset + 1);
@@ -598,36 +594,27 @@ static int quad8_count_read(struct counter_device *counter,
carry = !!(flags & QUAD8_FLAG_CT);
/* Borrow XOR Carry effectively doubles count range */
- position = (unsigned long)(borrow ^ carry) << 24;
+ *val = (unsigned long)(borrow ^ carry) << 24;
/* Reset Byte Pointer; transfer Counter to Output Latch */
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
base_offset + 1);
for (i = 0; i < 3; i++)
- position |= (unsigned long)inb(base_offset) << (8 * i);
-
- counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &position);
+ *val |= (unsigned long)inb(base_offset) << (8 * i);
return 0;
}
static int quad8_count_write(struct counter_device *counter,
- struct counter_count *count, struct counter_count_write_value *val)
+ struct counter_count *count, unsigned long val)
{
const struct quad8_iio *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id;
- int err;
- unsigned long position;
int i;
- err = counter_count_write_value_get(&position, COUNTER_COUNT_POSITION,
- val);
- if (err)
- return err;
-
/* Only 24-bit values are supported */
- if (position > 0xFFFFFF)
+ if (val > 0xFFFFFF)
return -EINVAL;
/* Reset Byte Pointer */
@@ -635,7 +622,7 @@ static int quad8_count_write(struct counter_device *counter,
/* Counter can only be set via Preset Register */
for (i = 0; i < 3; i++)
- outb(position >> (8 * i), base_offset);
+ outb(val >> (8 * i), base_offset);
/* Transfer Preset Register to Counter */
outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
@@ -644,9 +631,9 @@ static int quad8_count_write(struct counter_device *counter,
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
/* Set Preset Register back to original value */
- position = priv->preset[count->id];
+ val = priv->preset[count->id];
for (i = 0; i < 3; i++)
- outb(position >> (8 * i), base_offset);
+ outb(val >> (8 * i), base_offset);
/* Reset Borrow, Carry, Compare, and Sign flags */
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 5/7] counter: ftm-quaddec: Update count_read and count_write callbacks
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
The count_read and count_write callbacks pass unsigned long now.
Cc: Patrick Havelange <patrick.havelange@essensium.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/counter/ftm-quaddec.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
index 4046aa9f9234..c2b3fdfd8b77 100644
--- a/drivers/counter/ftm-quaddec.c
+++ b/drivers/counter/ftm-quaddec.c
@@ -178,31 +178,25 @@ static const enum counter_count_function ftm_quaddec_count_functions[] = {
static int ftm_quaddec_count_read(struct counter_device *counter,
struct counter_count *count,
- struct counter_count_read_value *val)
+ unsigned long *val)
{
struct ftm_quaddec *const ftm = counter->priv;
uint32_t cntval;
ftm_read(ftm, FTM_CNT, &cntval);
- counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cntval);
+ *val = cntval;
return 0;
}
static int ftm_quaddec_count_write(struct counter_device *counter,
struct counter_count *count,
- struct counter_count_write_value *val)
+ const unsigned long val)
{
struct ftm_quaddec *const ftm = counter->priv;
- u32 cnt;
- int err;
- err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
- if (err)
- return err;
-
- if (cnt != 0) {
+ if (val != 0) {
dev_warn(&ftm->pdev->dev, "Can only accept '0' as new counter value\n");
return -EINVAL;
}
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 6/7] counter: stm32-lptimer-cnt: Update count_read callback
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
The count_read callback passes unsigned long now.
Cc: Fabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/counter/stm32-lptimer-cnt.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c
index bbc930a5962c..73bb773f5e6d 100644
--- a/drivers/counter/stm32-lptimer-cnt.c
+++ b/drivers/counter/stm32-lptimer-cnt.c
@@ -377,8 +377,7 @@ static enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
};
static int stm32_lptim_cnt_read(struct counter_device *counter,
- struct counter_count *count,
- struct counter_count_read_value *val)
+ struct counter_count *count, unsigned long *val)
{
struct stm32_lptim_cnt *const priv = counter->priv;
u32 cnt;
@@ -388,7 +387,7 @@ static int stm32_lptim_cnt_read(struct counter_device *counter,
if (ret)
return ret;
- counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt);
+ *val = cnt;
return 0;
}
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 7/7] counter: stm32-timer-cnt: Update count_read and count_write callbacks
From: William Breathitt Gray @ 2019-09-18 7:52 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
William Breathitt Gray, mcoquelin.stm32, fabrice.gasnier,
linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
The count_read and count_write callbacks pass unsigned long now.
Cc: Fabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/counter/stm32-timer-cnt.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c
index 644ba18a72ad..839083543323 100644
--- a/drivers/counter/stm32-timer-cnt.c
+++ b/drivers/counter/stm32-timer-cnt.c
@@ -48,34 +48,27 @@ static enum counter_count_function stm32_count_functions[] = {
};
static int stm32_count_read(struct counter_device *counter,
- struct counter_count *count,
- struct counter_count_read_value *val)
+ struct counter_count *count, unsigned long *val)
{
struct stm32_timer_cnt *const priv = counter->priv;
u32 cnt;
regmap_read(priv->regmap, TIM_CNT, &cnt);
- counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt);
+ *val = cnt;
return 0;
}
static int stm32_count_write(struct counter_device *counter,
struct counter_count *count,
- struct counter_count_write_value *val)
+ const unsigned long val)
{
struct stm32_timer_cnt *const priv = counter->priv;
- u32 cnt;
- int err;
-
- err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
- if (err)
- return err;
- if (cnt > priv->ceiling)
+ if (val > priv->ceiling)
return -EINVAL;
- return regmap_write(priv->regmap, TIM_CNT, cnt);
+ return regmap_write(priv->regmap, TIM_CNT, val);
}
static int stm32_count_function_get(struct counter_device *counter,
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH] of: restore old handling of cells_name=NULL in of_*_phandle_with_args()
From: Peter Rosin @ 2019-09-18 8:01 UTC (permalink / raw)
To: Uwe Kleine-König, Rob Herring, Frank Rowand
Cc: devicetree@vger.kernel.org, Geert Uytterhoeven,
Uwe Kleine-König, Robin Murphy, Joerg Roedel,
linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
kernel@pengutronix.de, Matthias Brugger, Geert Uytterhoeven,
Will Deacon, linux-arm-kernel@lists.infradead.org,
Marek Szyprowski
In-Reply-To: <20190918063837.8196-1-u.kleine-koenig@pengutronix.de>
On 2019-09-18 08:38, Uwe Kleine-König wrote:
> From: Uwe Kleine-König <uwe@kleine-koenig.org>
>
> Before commit e42ee61017f5 ("of: Let of_for_each_phandle fallback to
> non-negative cell_count") the iterator functions calling
> of_for_each_phandle assumed a cell count of 0 if cells_name was NULL.
> This corner case was missed when implementing the fallback logic in
> e42ee61017f5 and resulted in an endless loop.
>
> Restore the old behaviour of of_count_phandle_with_args() and
> of_parse_phandle_with_args() and add a check to
> of_phandle_iterator_init() to prevent a similar failure as a safety
> precaution. of_parse_phandle_with_args_map() doesn't need a similar fix
> as cells_name isn't NULL there.
>
> Affected drivers are:
> - drivers/base/power/domain.c
> - drivers/base/power/domain.c
> - drivers/clk/ti/clk-dra7-atl.c
> - drivers/hwmon/ibmpowernv.c
> - drivers/i2c/muxes/i2c-demux-pinctrl.c
> - drivers/iommu/mtk_iommu.c
> - drivers/net/ethernet/freescale/fman/mac.c
> - drivers/opp/of.c
> - drivers/perf/arm_dsu_pmu.c
> - drivers/regulator/of_regulator.c
> - drivers/remoteproc/imx_rproc.c
> - drivers/soc/rockchip/pm_domains.c
> - sound/soc/fsl/imx-audmix.c
> - sound/soc/fsl/imx-audmix.c
> - sound/soc/meson/axg-card.c
> - sound/soc/samsung/tm2_wm5110.c
> - sound/soc/samsung/tm2_wm5110.c
>
> Thanks to Geert Uytterhoeven for reporting the issue, Peter Rosin for
> helping pinpoint the actual problem and the testers for confirming this
> fix.
>
> Fixes: e42ee61017f5 ("of: Let of_for_each_phandle fallback to non-negative cell_count")
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
> Hello,
>
> compared to the untested patch I sent yesterday I also fixed
> of_parse_phandle_with_args which has three users that pass
> cells_name=NULL. (i.e. drivers/clk/ti/clk-dra7-atl.c,
> sound/soc/fsl/imx-audmix.c, sound/soc/samsung/tm2_wm5110.c) I didn't
> look closely, but maybe these could be converted to use of_parse_phandle
> as there are no arguments to be processed with no cells_name?!
>
> Best regards
> Uwe
>
> drivers/of/base.c | 30 ++++++++++++++++++++++++++++--
> 1 file changed, 28 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index 2f25d2dfecfa..25ee07c0a3cd 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1286,6 +1286,13 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
>
> memset(it, 0, sizeof(*it));
>
> + /*
> + * one of cell_count or cells_name must be provided to determine the
> + * argument length.
> + */
> + if (cell_count < 0 && !cells_name)
> + return -EINVAL;
> +
> list = of_get_property(np, list_name, &size);
> if (!list)
> return -ENOENT;
> @@ -1512,10 +1519,17 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
> const char *cells_name, int index,
> struct of_phandle_args *out_args)
> {
> + int cell_count = -1;
> +
> if (index < 0)
> return -EINVAL;
> - return __of_parse_phandle_with_args(np, list_name, cells_name, -1,
> - index, out_args);
> +
> + /* If cells_name if NULL we assume a cell count of 0 */
> + if (!cells_name)
> + cell_count = 0;
> +
> + return __of_parse_phandle_with_args(np, list_name, cells_name,
> + cell_count, index, out_args);
> }
> EXPORT_SYMBOL(of_parse_phandle_with_args);
>
> @@ -1765,6 +1779,18 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na
> struct of_phandle_iterator it;
> int rc, cur_index = 0;
>
> + /* If cells_name is NULL we assume a cell count of 0 */
> + if (cells_name == NULL) {
A couple of nits.
I don't know if there are other considerations, but in the previous two
hunks you use !cells_name instead of comparing explicitly with NULL.
Personally, I find the shorter form more readable, and in the name of
consistency bla bla...
Also, the comment explaining this NULL-check didn't really make sense
to me until I realized that knowing the cell count to be zero makes
counting trivial. Something along those lines should perhaps be in the
comment?
But as I said, these are nits. Feel free to ignore.
Cheers,
Peter
> + const __be32 *list;
> + int size;
> +
> + list = of_get_property(np, list_name, &size);
> + if (!list)
> + return -ENOENT;
> +
> + return size / sizeof(*list);
> + }
> +
> rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1);
> if (rc)
> return rc;
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [RFC PATCH v3 0/6] Enable ptp_kvm for arm64
From: Jianyong Wu @ 2019-09-18 8:07 UTC (permalink / raw)
To: netdev, yangbo.lu, john.stultz, tglx, pbonzini,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin,
nd, linux-arm-kernel
kvm ptp targets to provide high precision time sync between guest
and host in virtualization environment. This patch enable kvm ptp
for arm64.
This patch set base on [1][2][3]
change log:
from v2 to v3:
(1) fix some issues in commit log.
(2) add some receivers in send list.
from v1 to v2:
(1) move arch-specific code from arch/ to driver/ptp/
(2) offer mechanism to inform userspace if ptp_kvm service is
available.
(3) separate ptp_kvm code for arm64 into hypervisor part and
guest part.
(4) add API to expose monotonic clock and counter value.
(5) refine code: remove no necessary part and reconsitution.
[1]https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/
commit/?h=kvm/hvc&id=125ea89e4a21e2fc5235410f966a996a1a7148bf
[2]https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/
commit/?h=kvm/hvc&id=464f5a1741e5959c3e4d2be1966ae0093b4dce06
[3]https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/
commit/?h=kvm/hvc&id=6597490e005d0eeca8ed8c1c1d7b4318ee014681
Jianyong Wu (6):
psci: Export psci_ops.conduit symbol as modules will use it.
ptp: Reorganize ptp_kvm modules to make it arch-independent.
timekeeping: Expose API allowing retrival of current clocksource and
counter value
psci: Add hvc call service for ptp_kvm.
ptp: arm64: Enable ptp_kvm for arm64
kvm: arm64: Add capability check extension for ptp_kvm
drivers/firmware/psci/psci.c | 6 ++
drivers/ptp/Kconfig | 2 +-
drivers/ptp/Makefile | 1 +
drivers/ptp/{ptp_kvm.c => kvm_ptp.c} | 77 ++++++------------------
drivers/ptp/ptp_kvm_arm64.c | 82 ++++++++++++++++++++++++++
drivers/ptp/ptp_kvm_x86.c | 87 ++++++++++++++++++++++++++++
include/asm-generic/ptp_kvm.h | 12 ++++
include/linux/arm-smccc.h | 14 ++++-
include/linux/psci.h | 1 +
include/linux/timekeeping.h | 3 +
include/uapi/linux/kvm.h | 1 +
kernel/time/timekeeping.c | 13 +++++
virt/kvm/arm/arm.c | 1 +
virt/kvm/arm/psci.c | 17 ++++++
14 files changed, 256 insertions(+), 61 deletions(-)
rename drivers/ptp/{ptp_kvm.c => kvm_ptp.c} (63%)
create mode 100644 drivers/ptp/ptp_kvm_arm64.c
create mode 100644 drivers/ptp/ptp_kvm_x86.c
create mode 100644 include/asm-generic/ptp_kvm.h
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [RFC PATCH v3 1/6] psci: Export psci_ops.conduit symbol as modules will use it.
From: Jianyong Wu @ 2019-09-18 8:07 UTC (permalink / raw)
To: netdev, yangbo.lu, john.stultz, tglx, pbonzini,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin,
nd, linux-arm-kernel
In-Reply-To: <20190918080716.64242-1-jianyong.wu@arm.com>
If arm_smccc_1_1_invoke used in modules, psci_ops.conduit should
be export.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
drivers/firmware/psci/psci.c | 6 ++++++
include/linux/arm-smccc.h | 2 +-
include/linux/psci.h | 1 +
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index f82ccd39a913..35c4eaab1451 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -212,6 +212,12 @@ static unsigned long psci_migrate_info_up_cpu(void)
0, 0, 0);
}
+enum psci_conduit psci_get_conduit(void)
+{
+ return psci_ops.conduit;
+}
+EXPORT_SYMBOL(psci_get_conduit);
+
static void set_conduit(enum psci_conduit conduit)
{
switch (conduit) {
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 552cbd49abe8..a6e4d3e3d10a 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -357,7 +357,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
* The return value also provides the conduit that was used.
*/
#define arm_smccc_1_1_invoke(...) ({ \
- int method = psci_ops.conduit; \
+ int method = psci_get_conduit(); \
switch (method) { \
case PSCI_CONDUIT_HVC: \
arm_smccc_1_1_hvc(__VA_ARGS__); \
diff --git a/include/linux/psci.h b/include/linux/psci.h
index a8a15613c157..e5cedc986049 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -42,6 +42,7 @@ struct psci_operations {
enum smccc_version smccc_version;
};
+extern enum psci_conduit psci_get_conduit(void);
extern struct psci_operations psci_ops;
#if defined(CONFIG_ARM_PSCI_FW)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v3 2/6] ptp: Reorganize ptp_kvm modules to make it arch-independent.
From: Jianyong Wu @ 2019-09-18 8:07 UTC (permalink / raw)
To: netdev, yangbo.lu, john.stultz, tglx, pbonzini,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin,
nd, linux-arm-kernel
In-Reply-To: <20190918080716.64242-1-jianyong.wu@arm.com>
Currently, ptp_kvm modules implementation is only for x86 which includs
large part of arch-specific code. This patch move all of those code
into sole arch related file in the same directory.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
drivers/ptp/Makefile | 1 +
drivers/ptp/{ptp_kvm.c => kvm_ptp.c} | 77 ++++++------------------
drivers/ptp/ptp_kvm_x86.c | 87 ++++++++++++++++++++++++++++
include/asm-generic/ptp_kvm.h | 12 ++++
4 files changed, 118 insertions(+), 59 deletions(-)
rename drivers/ptp/{ptp_kvm.c => kvm_ptp.c} (63%)
create mode 100644 drivers/ptp/ptp_kvm_x86.c
create mode 100644 include/asm-generic/ptp_kvm.h
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index 677d1d178a3e..8f27ba302e31 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -4,6 +4,7 @@
#
ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o
+ptp_kvm-y := ptp_kvm_$(ARCH).o kvm_ptp.o
obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o
obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o
obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o
diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/kvm_ptp.c
similarity index 63%
rename from drivers/ptp/ptp_kvm.c
rename to drivers/ptp/kvm_ptp.c
index fc7d0b77e118..d8f215186904 100644
--- a/drivers/ptp/ptp_kvm.c
+++ b/drivers/ptp/kvm_ptp.c
@@ -8,12 +8,12 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <uapi/linux/kvm_para.h>
#include <asm/kvm_para.h>
-#include <asm/pvclock.h>
-#include <asm/kvmclock.h>
#include <uapi/asm/kvm_para.h>
+#include <asm-generic/ptp_kvm.h>
#include <linux/ptp_clock_kernel.h>
@@ -24,56 +24,29 @@ struct kvm_ptp_clock {
DEFINE_SPINLOCK(kvm_ptp_lock);
-static struct pvclock_vsyscall_time_info *hv_clock;
-
-static struct kvm_clock_pairing clock_pair;
-static phys_addr_t clock_pair_gpa;
-
static int ptp_kvm_get_time_fn(ktime_t *device_time,
struct system_counterval_t *system_counter,
void *ctx)
{
- unsigned long ret;
+ unsigned long ret, cycle;
struct timespec64 tspec;
- unsigned version;
- int cpu;
- struct pvclock_vcpu_time_info *src;
+ struct clocksource *cs;
spin_lock(&kvm_ptp_lock);
preempt_disable_notrace();
- cpu = smp_processor_id();
- src = &hv_clock[cpu].pvti;
-
- do {
- /*
- * We are using a TSC value read in the hosts
- * kvm_hc_clock_pairing handling.
- * So any changes to tsc_to_system_mul
- * and tsc_shift or any other pvclock
- * data invalidate that measurement.
- */
- version = pvclock_read_begin(src);
-
- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
- clock_pair_gpa,
- KVM_CLOCK_PAIRING_WALLCLOCK);
- if (ret != 0) {
- pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
- spin_unlock(&kvm_ptp_lock);
- preempt_enable_notrace();
- return -EOPNOTSUPP;
- }
-
- tspec.tv_sec = clock_pair.sec;
- tspec.tv_nsec = clock_pair.nsec;
- ret = __pvclock_read_cycles(src, clock_pair.tsc);
- } while (pvclock_read_retry(src, version));
+ ret = kvm_arch_ptp_get_clock_fn(&cycle, &tspec, &cs);
+ if (ret != 0) {
+ pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
+ spin_unlock(&kvm_ptp_lock);
+ preempt_enable_notrace();
+ return -EOPNOTSUPP;
+ }
preempt_enable_notrace();
- system_counter->cycles = ret;
- system_counter->cs = &kvm_clock;
+ system_counter->cycles = cycle;
+ system_counter->cs = cs;
*device_time = timespec64_to_ktime(tspec);
@@ -116,17 +89,13 @@ static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
spin_lock(&kvm_ptp_lock);
- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
- clock_pair_gpa,
- KVM_CLOCK_PAIRING_WALLCLOCK);
+ ret = kvm_arch_ptp_get_clock(&tspec);
if (ret != 0) {
pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);
spin_unlock(&kvm_ptp_lock);
return -EOPNOTSUPP;
}
- tspec.tv_sec = clock_pair.sec;
- tspec.tv_nsec = clock_pair.nsec;
spin_unlock(&kvm_ptp_lock);
memcpy(ts, &tspec, sizeof(struct timespec64));
@@ -166,21 +135,11 @@ static void __exit ptp_kvm_exit(void)
static int __init ptp_kvm_init(void)
{
- long ret;
-
- if (!kvm_para_available())
- return -ENODEV;
-
- clock_pair_gpa = slow_virt_to_phys(&clock_pair);
- hv_clock = pvclock_get_pvti_cpu0_va();
+ int ret;
- if (!hv_clock)
- return -ENODEV;
-
- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
- KVM_CLOCK_PAIRING_WALLCLOCK);
- if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
- return -ENODEV;
+ ret = kvm_arch_ptp_init();
+ if (!ret)
+ return -EOPNOTSUPP;
kvm_ptp_clock.caps = ptp_kvm_caps;
diff --git a/drivers/ptp/ptp_kvm_x86.c b/drivers/ptp/ptp_kvm_x86.c
new file mode 100644
index 000000000000..632733989d59
--- /dev/null
+++ b/drivers/ptp/ptp_kvm_x86.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ */
+
+#include <asm/pvclock.h>
+#include <asm/kvmclock.h>
+#include <linux/module.h>
+#include <uapi/asm/kvm_para.h>
+#include <uapi/linux/kvm_para.h>
+#include <linux/ptp_clock_kernel.h>
+
+phys_addr_t clock_pair_gpa;
+struct kvm_clock_pairing clock_pair;
+struct pvclock_vsyscall_time_info *hv_clock;
+
+int kvm_arch_ptp_init(void)
+{
+ int ret;
+
+ if (!kvm_para_available())
+ return -ENODEV;
+
+ clock_pair_gpa = slow_virt_to_phys(&clock_pair);
+ hv_clock = pvclock_get_pvti_cpu0_va();
+ if (!hv_clock)
+ return -ENODEV;
+
+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
+ KVM_CLOCK_PAIRING_WALLCLOCK);
+ if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
+ return -ENODEV;
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock(struct timespec64 *ts)
+{
+ long ret;
+
+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
+ clock_pair_gpa,
+ KVM_CLOCK_PAIRING_WALLCLOCK);
+ if (ret != 0)
+ return -EOPNOTSUPP;
+
+ ts->tv_sec = clock_pair.sec;
+ ts->tv_nsec = clock_pair.nsec;
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock_fn(long *cycle, struct timespec64 *tspec,
+ struct clocksource **cs)
+{
+ unsigned long ret;
+ unsigned int version;
+ int cpu;
+ struct pvclock_vcpu_time_info *src;
+
+ cpu = smp_processor_id();
+ src = &hv_clock[cpu].pvti;
+
+ do {
+ /*
+ * We are using a TSC value read in the hosts
+ * kvm_hc_clock_pairing handling.
+ * So any changes to tsc_to_system_mul
+ * and tsc_shift or any other pvclock
+ * data invalidate that measurement.
+ */
+ version = pvclock_read_begin(src);
+
+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
+ clock_pair_gpa,
+ KVM_CLOCK_PAIRING_WALLCLOCK);
+ tspec->tv_sec = clock_pair.sec;
+ tspec->tv_nsec = clock_pair.nsec;
+ *cycle = __pvclock_read_cycles(src, clock_pair.tsc);
+ } while (pvclock_read_retry(src, version));
+
+ *cs = &kvm_clock;
+
+ return 0;
+}
diff --git a/include/asm-generic/ptp_kvm.h b/include/asm-generic/ptp_kvm.h
new file mode 100644
index 000000000000..208e842bfa64
--- /dev/null
+++ b/include/asm-generic/ptp_kvm.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ *
+ * Copyright (C) 2019 ARM Ltd.
+ * All Rights Reserved
+ */
+
+int kvm_arch_ptp_init(void);
+int kvm_arch_ptp_get_clock(struct timespec64 *ts);
+int kvm_arch_ptp_get_clock_fn(long *cycle,
+ struct timespec64 *tspec, void *cs);
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v3 3/6] timekeeping: Expose API allowing retrival of current clocksource and counter value
From: Jianyong Wu @ 2019-09-18 8:07 UTC (permalink / raw)
To: netdev, yangbo.lu, john.stultz, tglx, pbonzini,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin,
nd, linux-arm-kernel
In-Reply-To: <20190918080716.64242-1-jianyong.wu@arm.com>
From Marc Zyngier <maz@kernel.org>
A number of PTP drivers (such as ptp-kvm) are assuming what the
current clock source is, which could lead to interesting effects on
systems where the clocksource can change depending on external events.
For this purpose, add a new API that retrives both the current
monotonic clock as well as its counter value.
From Jianyong Wu: export this API then modules can use it.
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
include/linux/timekeeping.h | 3 +++
kernel/time/timekeeping.c | 13 +++++++++++++
2 files changed, 16 insertions(+)
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index a8ab0f143ac4..a5389adaa8bc 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -247,6 +247,9 @@ extern int get_device_system_crosststamp(
struct system_time_snapshot *history,
struct system_device_crosststamp *xtstamp);
+/* Obtain current monotonic clock and its counter value */
+extern void get_current_counterval(struct system_counterval_t *sc);
+
/*
* Simultaneously snapshot realtime and monotonic raw clocks
*/
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 44b726bab4bd..07a0969625b1 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1098,6 +1098,19 @@ static bool cycle_between(u64 before, u64 test, u64 after)
return false;
}
+/**
+ * get_current_counterval - Snapshot the current clocksource and counter value
+ * @sc: Pointer to a struct containing the current clocksource and its value
+ */
+void get_current_counterval(struct system_counterval_t *sc)
+{
+ struct timekeeper *tk = &tk_core.timekeeper;
+
+ sc->cs = READ_ONCE(tk->tkr_mono.clock);
+ sc->cycles = sc->cs->read(sc->cs);
+}
+EXPORT_SYMBOL_GPL(get_current_counterval);
+
/**
* get_device_system_crosststamp - Synchronously capture system/device timestamp
* @get_time_fn: Callback to get simultaneous device time and
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v3 4/6] psci: Add hvc call service for ptp_kvm.
From: Jianyong Wu @ 2019-09-18 8:07 UTC (permalink / raw)
To: netdev, yangbo.lu, john.stultz, tglx, pbonzini,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin,
nd, linux-arm-kernel
In-Reply-To: <20190918080716.64242-1-jianyong.wu@arm.com>
This patch is the base of ptp_kvm for arm64.
ptp_kvm modules will call hvc to get this service.
The service offers real time and counter cycle of host for guest.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
include/linux/arm-smccc.h | 12 ++++++++++++
virt/kvm/arm/psci.c | 17 +++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index a6e4d3e3d10a..bc0cdad10f35 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -94,6 +94,7 @@
/* KVM "vendor specific" services */
#define ARM_SMCCC_KVM_FUNC_FEATURES 0
+#define ARM_SMCCC_KVM_PTP 1
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
#define ARM_SMCCC_KVM_NUM_FUNCS 128
@@ -103,6 +104,17 @@
ARM_SMCCC_OWNER_VENDOR_HYP, \
ARM_SMCCC_KVM_FUNC_FEATURES)
+/*
+ * This ID used for virtual ptp kvm clock and it will pass second value
+ * and nanosecond value of host real time and system counter by vcpu
+ * register to guest.
+ */
+#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_VENDOR_HYP, \
+ ARM_SMCCC_KVM_PTP)
+
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 0debf49bf259..2c5d53817a28 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -392,6 +392,8 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
u32 func_id = smccc_get_function(vcpu);
u32 val[4] = {};
u32 option;
+ struct timespec *ts;
+ struct system_counterval_t sc;
val[0] = SMCCC_RET_NOT_SUPPORTED;
@@ -431,6 +433,21 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
break;
+ /*
+ * This will used for virtual ptp kvm clock. three
+ * values will be passed back.
+ * reg0 stores seconds of host real time;
+ * reg1 stores nanoseconds of host real time;
+ * reg2 stores system counter cycle value.
+ */
+ case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+ getnstimeofday(ts);
+ get_current_counterval(&sc);
+ val[0] = ts->tv_sec;
+ val[1] = ts->tv_nsec;
+ val[2] = sc.cycles;
+ val[3] = 0;
+ break;
default:
return kvm_psci_call(vcpu);
}
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v3 5/6] ptp: arm64: Enable ptp_kvm for arm64
From: Jianyong Wu @ 2019-09-18 8:07 UTC (permalink / raw)
To: netdev, yangbo.lu, john.stultz, tglx, pbonzini,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin,
nd, linux-arm-kernel
In-Reply-To: <20190918080716.64242-1-jianyong.wu@arm.com>
Currently in arm64 virtualization environment, there is no mechanism to
keep time sync between guest and host. Time in guest will drift compared
with host after boot up as they may both use third party time sources
to correct their time respectively. The time deviation will be in order
of milliseconds but some scenarios ask for higher time precision, like
in cloud envirenment, we want all the VMs running in the host aquire the
same level accuracy from host clock.
Use of kvm ptp clock, which choose the host clock source clock as a
reference clock to sync time clock between guest and host has been adopted
by x86 which makes the time sync order from milliseconds to nanoseconds.
This patch enable kvm ptp on arm64 and we get the similar clock drift as
found with x86 with kvm ptp.
Test result comparison between with kvm ptp and without it in arm64 are
as follows. This test derived from the result of command 'chronyc
sources'. we should take more cure of the last sample column which shows
the offset between the local clock and the source at the last measurement.
no kvm ptp in guest:
MS Name/IP address Stratum Poll Reach LastRx Last sample
========================================================================
^* dns1.synet.edu.cn 2 6 377 13 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 21 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 29 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 37 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 45 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 53 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 61 +1040us[+1581us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 4 -130us[ +796us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 12 -130us[ +796us] +/- 21ms
^* dns1.synet.edu.cn 2 6 377 20 -130us[ +796us] +/- 21ms
in host:
MS Name/IP address Stratum Poll Reach LastRx Last sample
========================================================================
^* 120.25.115.20 2 7 377 72 -470us[ -603us] +/- 18ms
^* 120.25.115.20 2 7 377 92 -470us[ -603us] +/- 18ms
^* 120.25.115.20 2 7 377 112 -470us[ -603us] +/- 18ms
^* 120.25.115.20 2 7 377 2 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 22 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 43 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 63 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 83 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 103 +872ns[-6808ns] +/- 17ms
^* 120.25.115.20 2 7 377 123 +872ns[-6808ns] +/- 17ms
The dns1.synet.edu.cn is the network reference clock for guest and
120.25.115.20 is the network reference clock for host. we can't get the
clock error between guest and host directly, but a roughly estimated value
will be in order of hundreds of us to ms.
with kvm ptp in guest:
chrony has been disabled in host to remove the disturb by network clock.
MS Name/IP address Stratum Poll Reach LastRx Last sample
========================================================================
* PHC0 0 3 377 8 -7ns[ +1ns] +/- 3ns
* PHC0 0 3 377 8 +1ns[ +16ns] +/- 3ns
* PHC0 0 3 377 6 -4ns[ -0ns] +/- 6ns
* PHC0 0 3 377 6 -8ns[ -12ns] +/- 5ns
* PHC0 0 3 377 5 +2ns[ +4ns] +/- 4ns
* PHC0 0 3 377 13 +2ns[ +4ns] +/- 4ns
* PHC0 0 3 377 12 -4ns[ -6ns] +/- 4ns
* PHC0 0 3 377 11 -8ns[ -11ns] +/- 6ns
* PHC0 0 3 377 10 -14ns[ -20ns] +/- 4ns
* PHC0 0 3 377 8 +4ns[ +5ns] +/- 4ns
The PHC0 is the ptp clock which choose the host clock as its source
clock. So we can be sure to say that the clock error between host and guest
is in order of ns.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
---
drivers/ptp/Kconfig | 2 +-
drivers/ptp/kvm_ptp.c | 2 +-
drivers/ptp/ptp_kvm_arm64.c | 82 +++++++++++++++++++++++++++++++++++++
3 files changed, 84 insertions(+), 2 deletions(-)
create mode 100644 drivers/ptp/ptp_kvm_arm64.c
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 9b8fee5178e8..e032fafdafa7 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -110,7 +110,7 @@ config PTP_1588_CLOCK_PCH
config PTP_1588_CLOCK_KVM
tristate "KVM virtual PTP clock"
depends on PTP_1588_CLOCK
- depends on KVM_GUEST && X86
+ depends on KVM_GUEST && X86 || ARM64
default y
help
This driver adds support for using kvm infrastructure as a PTP
diff --git a/drivers/ptp/kvm_ptp.c b/drivers/ptp/kvm_ptp.c
index d8f215186904..c0b445fa6144 100644
--- a/drivers/ptp/kvm_ptp.c
+++ b/drivers/ptp/kvm_ptp.c
@@ -138,7 +138,7 @@ static int __init ptp_kvm_init(void)
int ret;
ret = kvm_arch_ptp_init();
- if (!ret)
+ if (ret)
return -EOPNOTSUPP;
kvm_ptp_clock.caps = ptp_kvm_caps;
diff --git a/drivers/ptp/ptp_kvm_arm64.c b/drivers/ptp/ptp_kvm_arm64.c
new file mode 100644
index 000000000000..630144186c08
--- /dev/null
+++ b/drivers/ptp/ptp_kvm_arm64.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ * Copyright (C) 2019 ARM Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <asm/hypervisor.h>
+#include <linux/module.h>
+#include <linux/psci.h>
+#include <linux/arm-smccc.h>
+#include <linux/timecounter.h>
+#include <linux/sched/clock.h>
+#include <asm/arch_timer.h>
+
+struct system_counterval_t ptp_sc;
+
+/*
+ * as trap call cause delay, this function will return the delay in nanosecond
+ */
+static u64 arm_smccc_1_1_invoke_delay(u32 id, struct arm_smccc_res *res)
+{
+ u64 t1, t2;
+
+ t1 = sched_clock();
+ arm_smccc_1_1_invoke(id, res);
+ t2 = sched_clock();
+ t2 -= t1;
+
+ return t2;
+}
+
+int kvm_arch_ptp_init(void)
+{
+ if (!kvm_arm_hyp_service_available(
+ ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID)) {
+ return -EOPNOTSUPP;
+ }
+ get_current_counterval(&ptp_sc);
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock_generic(struct timespec64 *ts,
+ struct arm_smccc_res *hvc_res)
+{
+ u64 ns;
+
+ ns = arm_smccc_1_1_invoke_delay(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID,
+ hvc_res);
+ if ((long)(hvc_res->a0) < 0)
+ return -EOPNOTSUPP;
+
+ ts->tv_sec = hvc_res->a0;
+ ts->tv_nsec = hvc_res->a1;
+ timespec64_add_ns(ts, ns);
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock(struct timespec64 *ts)
+{
+ struct arm_smccc_res hvc_res;
+
+ kvm_arch_ptp_get_clock_generic(ts, &hvc_res);
+
+ return 0;
+}
+
+int kvm_arch_ptp_get_clock_fn(long *cycle, struct timespec64 *ts,
+ struct clocksource **cs)
+{
+ struct arm_smccc_res hvc_res;
+
+ kvm_arch_ptp_get_clock_generic(ts, &hvc_res);
+ *cycle = hvc_res.a2;
+ *cs = ptp_sc.cs;
+
+ return 0;
+}
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH v3 6/6] kvm: arm64: Add capability check extension for ptp_kvm
From: Jianyong Wu @ 2019-09-18 8:07 UTC (permalink / raw)
To: netdev, yangbo.lu, john.stultz, tglx, pbonzini,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, jianyong.wu, linux-kernel, Kaly.Xin,
nd, linux-arm-kernel
In-Reply-To: <20190918080716.64242-1-jianyong.wu@arm.com>
Let userspace check if there is kvm ptp service in host.
before VMs migrate to a another host, VMM may check if this
cap is available to determine the migration behaviour.
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
Suggested-by: Marc Zyngier <maz@kernel.org>
---
include/uapi/linux/kvm.h | 1 +
virt/kvm/arm/arm.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 2fe12b40d503..a0bff6002bd9 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -993,6 +993,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_ARM_SVE 170
#define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
#define KVM_CAP_ARM_PTRAUTH_GENERIC 172
+#define KVM_CAP_ARM_KVM_PTP 173
#ifdef KVM_CAP_IRQ_ROUTING
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index bd5c55916d0d..80999985160b 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -201,6 +201,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_MP_STATE:
case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_VCPU_EVENTS:
+ case KVM_CAP_ARM_KVM_PTP:
r = 1;
break;
case KVM_CAP_ARM_SET_DEVICE_ADDR:
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v2 0/7] counter: Simplify count_read/count_write/signal_read
From: William Breathitt Gray @ 2019-09-18 8:11 UTC (permalink / raw)
To: jic23
Cc: alexandre.torgue, linux-iio, patrick.havelange, linux-kernel,
mcoquelin.stm32, fabrice.gasnier, linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1568792697.git.vilhelm.gray@gmail.com>
On Wed, Sep 18, 2019 at 04:52:41PM +0900, William Breathitt Gray wrote:
> Changes in v2:
> - Update the rest of the drivers under drivers/counter
Jonathan,
The TI eQEP driver also needs a patch for these changes if this patchset
is merged.
How would you like to handle the merge? We have an full cycle until the
5.5 merge window, so I can keep this patchset in my personal repository,
adding in the ChromeOS EC driver and Intel QEP driver when they are
ready, then send you a git pull request during the 5.5 merge window. Or
we can keep going as usual and merge this into your IIO repository, then
handle the TI eQEP driver when the time comes to merge.
William Breathitt Gray
> The changes in this patchset will not affect the userspace interface.
> Rather, these changes are intended to simplify the kernelspace Counter
> callbacks for counter device driver authors.
>
> The following main changes are proposed:
>
> * Retire the opaque counter_count_read_value/counter_count_write_value
> structures and simply represent count data as an unsigned integer.
>
> * Retire the opaque counter_signal_read_value structure and represent
> Signal data as a counter_signal_value enum.
>
> These changes should reduce some complexity and code in the use and
> implementation of the count_read, count_write, and signal_read
> callbacks.
>
> The opaque structures for Count data and Signal data were introduced
> originally in anticipation of supporting various representations of
> counter data (e.g. arbitrary-precision tallies, floating-point spherical
> coordinate positions, etc). However, with the counter device drivers
> that have appeared, it's become apparent that utilizing opaque
> structures in kernelspace is not the best approach to take.
>
> I believe it is best to let userspace applications decide how to
> interpret the count data they receive. There are a couple of reasons why
> it would be good to do so:
>
> * Users use their devices in unexpected ways.
>
> For example, a quadrature encoder counter device is typically used to
> keep track of the position of a motor, but a user could set the device
> in a pulse-direction mode and instead use it to count sporadic rising
> edges from an arbitrary signal line unrelated to positioning. Users
> should have the freedom to decide what their data represents.
>
> * Most counter devices represent data as unsigned integers anyway.
>
> For example, whether the device is a tally counter or position
> counter, the count data is represented to the user as an unsigned
> integer value. So specifying that one device is representing tallies
> while the other specifies positions does not provide much utility from
> an interface perspective.
>
> For these reasons, the count_read and count_write callbacks have been
> redefined to pass count data directly as unsigned long instead of passed
> via opaque structures:
>
> count_read(struct counter_device *counter,
> struct counter_count *count, unsigned long *val);
> count_write(struct counter_device *counter,
> struct counter_count *count, unsigned long val);
>
> Similarly, the signal_read is redefined to pass Signal data directly as
> a counter_signal_value enum instead of via an opaque structure:
>
> signal_read(struct counter_device *counter,
> struct counter_signal *signal,
> enum counter_signal_value *val);
>
> The counter_signal_value enum is simply the counter_signal_level enum
> redefined to remove the references to the Signal data "level" data type.
>
> William Breathitt Gray (7):
> counter: Simplify the count_read and count_write callbacks
> counter: Simplify the signal_read callback
> docs: driver-api: generic-counter: Update Count and Signal data types
> counter: 104-quad-8: Update count_read/count_write/signal_read
> callbacks
> counter: ftm-quaddec: Update count_read and count_write callbacks
> counter: stm32-lptimer-cnt: Update count_read callback
> counter: stm32-timer-cnt: Update count_read and count_write callbacks
>
> Documentation/driver-api/generic-counter.rst | 22 ++--
> drivers/counter/104-quad-8.c | 33 ++----
> drivers/counter/counter.c | 101 +++----------------
> drivers/counter/ftm-quaddec.c | 14 +--
> drivers/counter/stm32-lptimer-cnt.c | 5 +-
> drivers/counter/stm32-timer-cnt.c | 17 +---
> include/linux/counter.h | 74 ++------------
> 7 files changed, 53 insertions(+), 213 deletions(-)
>
> --
> 2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [RFC PATCH V4 1/4] media: platform: mtk-isp: Add Mediatek sensor interface driver
From: Sakari Ailus @ 2019-09-18 8:11 UTC (permalink / raw)
To: Louis Kuo
Cc: devicetree, Sean.Cheng, laurent.pinchart+renesas, Rynn.Wu,
christie.yu, srv_heupstream, Jerry-ch.Chen, tfiga, keiichiw,
jungo.lin, sj.huang, yuzhao, hans.verkuil, zwisler, frederic.chen,
matthias.bgg, linux-mediatek, mchehab, linux-arm-kernel,
linux-media
In-Reply-To: <20190915065004.20257-2-louis.kuo@mediatek.com>
Hi Luis,
On Sun, Sep 15, 2019 at 02:50:01PM +0800, Louis Kuo wrote:
> This patch adds Mediat:ek's sensor interface driver. Sensor interface
> driver
> is a MIPI-CSI2 host driver, namely, a HW camera interface controller.
> It support a widely adopted, simple, high-speed protocol primarily
> intended
> for point-to-point image and video transmission between cameras and host
> devices.
>
> The mtk-isp directory will contain drivers for multiple IP blocks found in
> Mediatek ISP system. It will include ISP Pass 1 driver, sensor interface
> driver, DIP driver and face detection driver.
>
> Signed-off-by: Louis Kuo <louis.kuo@mediatek.com>
> ---
> drivers/media/platform/Makefile | 2 +
> drivers/media/platform/mtk-isp/Makefile | 3 +
> .../media/platform/mtk-isp/isp_50/Makefile | 5 +
> .../platform/mtk-isp/isp_50/seninf/Makefile | 6 +
> .../mtk-isp/isp_50/seninf/mtk_seninf.c | 1011 +++++++++++++++++
> .../mtk-isp/isp_50/seninf/mtk_seninf_def.h | 59 +
> .../mtk-isp/isp_50/seninf/mtk_seninf_reg.h | 853 ++++++++++++++
> 7 files changed, 1939 insertions(+)
> create mode 100644 drivers/media/platform/mtk-isp/Makefile
> create mode 100644 drivers/media/platform/mtk-isp/isp_50/Makefile
> create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/Makefile
> create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c
> create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_def.h
> create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_reg.h
>
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index 7cbbd925124c..b0f4543f2f86 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -73,6 +73,8 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip/rga/
>
> obj-y += omap/
>
> +obj-y += mtk-isp/
> +
> obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
>
> obj-$(CONFIG_VIDEO_XILINX) += xilinx/
> diff --git a/drivers/media/platform/mtk-isp/Makefile b/drivers/media/platform/mtk-isp/Makefile
> new file mode 100644
> index 000000000000..c17fb3fc3340
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-y += isp_50/
> diff --git a/drivers/media/platform/mtk-isp/isp_50/Makefile b/drivers/media/platform/mtk-isp/isp_50/Makefile
> new file mode 100644
> index 000000000000..8b4a792328e5
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +ifeq ($(CONFIG_MTK_SENINF),y)
> +obj-y += seninf/
> +endif
> diff --git a/drivers/media/platform/mtk-isp/isp_50/seninf/Makefile b/drivers/media/platform/mtk-isp/isp_50/seninf/Makefile
> new file mode 100644
> index 000000000000..bf193feb0ce9
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/seninf/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +MODULE = mtk_seninf
> +LIB_FILES = mtk_seninf
> +
> +obj-$(CONFIG_MTK_SENINF) += mtk_seninf.o
> diff --git a/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c
> new file mode 100644
> index 000000000000..3253510cf7fd
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c
> @@ -0,0 +1,1011 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/of_graph.h>
> +#include <linux/of_irq.h>
> +#ifdef CONFIG_COMPAT
> +#include <linux/compat.h>
> +#endif
> +#include <linux/videodev2.h>
> +#include <media/v4l2-subdev.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-async.h>
> +#include "mtk_seninf_reg.h"
> +#include "mtk_seninf_def.h"
> +
> +static inline int is_4d1c(unsigned int port)
> +{
> + return (port < CFG_CSI_PORT_0A);
No need for parentheses; same below.
> +}
> +
> +static inline int is_cdphy_combo(unsigned int port)
> +{
> + return (port == CFG_CSI_PORT_0A ||
> + port == CFG_CSI_PORT_0B ||
> + port == CFG_CSI_PORT_0);
> +}
> +
> +struct sensor_cfg {
> + unsigned char clock_lane;
> + unsigned short num_data_lanes;
> +};
> +
> +struct mtk_seninf {
> + struct v4l2_subdev subdev;
> + struct v4l2_async_notifier notifier;
> + struct v4l2_ctrl_handler ctrl_handler;
> + struct v4l2_subdev_format fmt[NUM_PADS];
> + struct device *dev;
> + struct media_pad pads[NUM_PADS];
> + struct sensor_cfg sensor[NUM_SENSORS];
> + unsigned int num_clks;
> + struct clk_bulk_data *clks;
> + void __iomem *base_reg;
> + void __iomem *rx_reg;
> + unsigned char *csi2_rx[CFG_CSI_PORT_MAX_NUM];
> + unsigned int port;
> + unsigned int mux_sel;
> +};
> +
> +static unsigned int mtk_seninf_get_dpcm(struct mtk_seninf *priv)
> +{
> + int dpcm;
unsigned int
> +
> + switch (priv->fmt[priv->port].format.code) {
> + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
> + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
> + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
> + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
> + dpcm = 0x2a;
> + break;
> + default:
> + dpcm = 0;
> + break;
> + }
> +
> + return dpcm;
> +}
> +
> +static unsigned int mtk_seninf_map_fmt(struct mtk_seninf *priv)
> +{
> + int fmtidx = 0;
> +
> + switch (priv->fmt[priv->port].format.code) {
> + case MEDIA_BUS_FMT_SBGGR8_1X8:
> + case MEDIA_BUS_FMT_SGBRG8_1X8:
> + case MEDIA_BUS_FMT_SGRBG8_1X8:
> + case MEDIA_BUS_FMT_SRGGB8_1X8:
> + fmtidx = 0;
> + break;
> + case MEDIA_BUS_FMT_SGRBG10_1X10:
> + case MEDIA_BUS_FMT_SRGGB10_1X10:
> + case MEDIA_BUS_FMT_SBGGR10_1X10:
> + case MEDIA_BUS_FMT_SGBRG10_1X10:
> + fmtidx = 1;
> + break;
> + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
> + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
> + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
> + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
> + fmtidx = 0;
> + break;
> + case MEDIA_BUS_FMT_SBGGR12_1X12:
> + case MEDIA_BUS_FMT_SGBRG12_1X12:
> + case MEDIA_BUS_FMT_SGRBG12_1X12:
> + case MEDIA_BUS_FMT_SRGGB12_1X12:
> + fmtidx = 2;
> + break;
> + case MEDIA_BUS_FMT_UYVY8_1X16:
> + case MEDIA_BUS_FMT_VYUY8_1X16:
> + case MEDIA_BUS_FMT_YUYV8_1X16:
> + case MEDIA_BUS_FMT_YVYU8_1X16:
> + fmtidx = 3;
> + break;
> + case MEDIA_BUS_FMT_JPEG_1X8:
> + case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8:
> + fmtidx = 7;
There seem to be an enum for the formats. Is this the same
different? The users appear to be comparing the values returned by this
function to e.g. JPEG_FMT that is part of the enum.
> + break;
> + }
> +
> + return fmtidx;
> +}
> +
> +static u32 mtk_seninf_csi_port_to_seninf(u32 port)
> +{
> + static const u32 port_to_seninf[] = {
> + [CFG_CSI_PORT_0] = SENINF_1,
> + [CFG_CSI_PORT_1] = SENINF_3,
> + [CFG_CSI_PORT_2] = SENINF_5,
> + [CFG_CSI_PORT_0A] = SENINF_1,
> + [CFG_CSI_PORT_0B] = SENINF_2,
> + };
> + if (WARN_ON(port >= ARRAY_SIZE(port_to_seninf)))
> + return -EINVAL;
> +
> + return port_to_seninf[port];
> +}
> +
> +static void mtk_seninf_set_mux(struct mtk_seninf *priv,
> + int seninf)
> +{
> + unsigned int mux = priv->mux_sel;
> + void *pseninf_top = priv->base_reg;
> + void *pseninf = priv->base_reg + 0x1000 * mux;
> + unsigned int val;
> + unsigned int pix_sel_ext;
> + unsigned int pix_sel;
> + unsigned int hs_pol = 0;
> + unsigned int vs_pol = 0;
> + unsigned int pixel_mode = ONE_PIXEL_MODE;
> + unsigned int input_data_type;
> +
> + /* Enable mux */
> + writel(0x7fffffff & readl(pseninf + SENINF1_MUX_CTRL) |
> + 0x80000000, pseninf + SENINF1_MUX_CTRL);
> +
> + input_data_type = mtk_seninf_map_fmt(priv);
> + /* Set mux ctrl */
> + writel(0xffff0fff & readl(pseninf + SENINF1_MUX_CTRL) |
> + 0x8000, pseninf + SENINF1_MUX_CTRL);
> +
> + writel(0xfffffffc & readl(pseninf + SENINF1_MUX_CTRL_EXT) |
> + 0x1, pseninf + SENINF1_MUX_CTRL_EXT);
Could you add more descriptive #defines for these magic numbers, please?
Same for the values below.
> +
> + switch (pixel_mode) {
> + case 1: /* 2 Pixel */
> + pix_sel_ext = 0;
> + pix_sel = 1 << 8;
> + break;
> + case 2: /* 4 Pixel */
> + pix_sel_ext = 1 << 4;
> + pix_sel = 0;
> + break;
> + default: /* 1 Pixel */
> + pix_sel_ext = 0;
> + pix_sel = 0;
> + break;
> + }
> +
> + writel(0xffffffef & readl(pseninf + SENINF1_MUX_CTRL_EXT) |
> + pix_sel_ext, pseninf + SENINF1_MUX_CTRL_EXT);
> + writel(0xfffffeff & readl(pseninf + SENINF1_MUX_CTRL) |
> + pix_sel, pseninf + SENINF1_MUX_CTRL);
> +
> + val = 0;
> + if (input_data_type != JPEG_FMT)
> + val = 0x20000000;
> +
> + writel(0xcfffffff & readl(pseninf + SENINF1_MUX_CTRL) |
> + val, pseninf + SENINF1_MUX_CTRL);
> +
> + if (input_data_type != JPEG_FMT)
> + writel(0xf000ffff & readl(pseninf + SENINF1_MUX_CTRL) |
> + 0x6df0000, pseninf + SENINF1_MUX_CTRL);
> + else
> + writel(0xf000ffff & readl(pseninf + SENINF1_MUX_CTRL) |
> + 0x61e0000, pseninf + SENINF1_MUX_CTRL);
> +
> + writel((0xfffff9ff) & readl(pseninf + SENINF1_MUX_CTRL) |
> + (hs_pol << 10) | (vs_pol << 9), pseninf + SENINF1_MUX_CTRL);
> +
> + val = (readl(pseninf + SENINF1_MUX_CTRL) | 0x3) & 0xFFFFFFFC;
> + writel(val, pseninf + SENINF1_MUX_CTRL);
> +
> + /* Set top mux */
> + val = (readl(pseninf_top + SENINF_TOP_MUX_CTRL) &
> + (~(0xF << (mux * 4)))) | ((seninf & 0xF) << (mux * 4));
> + writel(val, pseninf + SENINF_TOP_MUX_CTRL);
> +}
> +
> +static void mtk_seninf_set_dphy(struct mtk_seninf *priv, unsigned int seninf)
> +{
> + void *pmipi_rx_base = priv->csi2_rx[CFG_CSI_PORT_0];
> + unsigned int port = priv->port;
> + void *pmipi_rx = priv->csi2_rx[port];
> + void *pmipi_rx_conf = priv->base_reg + 0x1000 * seninf;
> +
> + /* Set analog phy mode to DPHY */
> + if (is_cdphy_combo(port))
> + writel(0xfffffffe & readl(pmipi_rx + MIPI_RX_ANA00_CSI0A)
> + , pmipi_rx + MIPI_RX_ANA00_CSI0A);
> +
> + /* 4D1C: MIPIRX_ANALOG_A_BASE = 0x00001A40 */
> + if (is_4d1c(port))
> + writel((0xffffe49f & readl(pmipi_rx + MIPI_RX_ANA00_CSI0A)) |
> + 0x1a40, pmipi_rx + MIPI_RX_ANA00_CSI0A);
Ditto.
> + else /* MIPIRX_ANALOG_BASE = 0x100 */
> + writel((0xffffe49f & readl(pmipi_rx + MIPI_RX_ANA00_CSI0A)) |
> + 0x100, pmipi_rx + MIPI_RX_ANA00_CSI0A);
> +
> + if (is_cdphy_combo(port))
> + writel(0xfffffffe & readl(pmipi_rx + MIPI_RX_ANA00_CSI0B)
> + , pmipi_rx + MIPI_RX_ANA00_CSI0B);
> +
> + /* Only 4d1c need set CSIB: MIPIRX_ANALOG_B_BASE = 0x00001240 */
> + if (is_4d1c(port))
> + writel(0xffffe49f & readl(pmipi_rx + MIPI_RX_ANA00_CSI0B) |
> + 0x1240, pmipi_rx + MIPI_RX_ANA00_CSI0B);
> + else /* MIPIRX_ANALOG_BASE = 0x100 */
> + writel(0xffffe49f & readl(pmipi_rx + MIPI_RX_ANA00_CSI0B) |
> + 0x100, pmipi_rx + MIPI_RX_ANA00_CSI0B);
> +
> + /* Byte clock invert */
> + writel(0xfffffff8 & readl(pmipi_rx + MIPI_RX_ANAA8_CSI0A) |
> + 0x7, pmipi_rx + MIPI_RX_ANAA8_CSI0A);
> + if (is_4d1c(port))
> + writel(0xfffffff8 & readl(pmipi_rx + MIPI_RX_ANAA8_CSI0B) |
> + 0x7, pmipi_rx + MIPI_RX_ANAA8_CSI0B);
> +
> + /* Start ANA EQ tuning */
> + if (is_cdphy_combo(port)) {
> + writel(0xffffff0f & readl(pmipi_rx + MIPI_RX_ANA18_CSI0A) |
> + 0x50, pmipi_rx + MIPI_RX_ANA18_CSI0A);
> + writel(0xff0fffff & readl(pmipi_rx + MIPI_RX_ANA1C_CSI0A) |
> + 0x500000, pmipi_rx + MIPI_RX_ANA1C_CSI0A);
> + writel(0xff0fffff & readl(pmipi_rx + MIPI_RX_ANA20_CSI0A) |
> + 0x500000, pmipi_rx + MIPI_RX_ANA20_CSI0A);
> + if (is_4d1c(port)) { /* 4d1c */
> + writel(0xffffff0f &
> + readl(pmipi_rx + MIPI_RX_ANA18_CSI0B) |
> + 0x50, pmipi_rx + MIPI_RX_ANA18_CSI0B);
> + writel(0xff0fffff &
> + readl(pmipi_rx + MIPI_RX_ANA1C_CSI0B) |
> + 0x500000, pmipi_rx + MIPI_RX_ANA1C_CSI0B);
> + writel(0xff0fffff &
> + readl(pmipi_rx + MIPI_RX_ANA20_CSI0B) |
> + 0x500000, pmipi_rx + MIPI_RX_ANA20_CSI0B);
> + }
> + } else {
> + writel(0xff0fff0f & readl(pmipi_rx + MIPI_RX_ANA18_CSI1A) |
> + 0x500050, pmipi_rx + MIPI_RX_ANA18_CSI1A);
> + writel(0xffffff0f & readl(pmipi_rx + MIPI_RX_ANA1C_CSI1A) |
> + 0x50, pmipi_rx + MIPI_RX_ANA1C_CSI1A);
> +
> + if (is_4d1c(port)) { /* 4d1c */
> + writel(0xff0fff0f &
> + readl(pmipi_rx + MIPI_RX_ANA18_CSI1B) |
> + 0x500050, pmipi_rx + MIPI_RX_ANA18_CSI1B);
> + writel(0xffffff0f &
> + readl(pmipi_rx + MIPI_RX_ANA1C_CSI1B) |
> + 0x50, pmipi_rx + MIPI_RX_ANA1C_CSI1B);
> + }
> + }
> +
> + /* End ANA EQ tuning */
> + writel(0x90, pmipi_rx_base + MIPI_RX_ANA40_CSI0A);
> + writel(0xffffff & readl(pmipi_rx + MIPI_RX_ANA24_CSI0A) |
> + 0x40000000, pmipi_rx + MIPI_RX_ANA24_CSI0A);
> + if (is_4d1c(port))
> + writel(0xffffff & readl(pmipi_rx + MIPI_RX_ANA24_CSI0B) |
> + 0x40000000, pmipi_rx + MIPI_RX_ANA24_CSI0B);
> + writel(0xfffcffff & readl(pmipi_rx + MIPI_RX_WRAPPER80_CSI0A)
> + , pmipi_rx + MIPI_RX_WRAPPER80_CSI0A);
> + if (is_4d1c(port))
> + writel(0xfffcffff & readl(pmipi_rx + MIPI_RX_WRAPPER80_CSI0B)
> + , pmipi_rx + MIPI_RX_WRAPPER80_CSI0B);
> + /* ANA power on */
> + writel(0xfffffff7 & readl(pmipi_rx + MIPI_RX_ANA00_CSI0A) |
> + 0x8, pmipi_rx + MIPI_RX_ANA00_CSI0A);
> + if (is_4d1c(port))
> + writel(0xfffffff7 & readl(pmipi_rx + MIPI_RX_ANA00_CSI0B) |
> + 0x8, pmipi_rx + MIPI_RX_ANA00_CSI0B);
> +
> + usleep_range(20, 40);
> + writel(0xfffffff7 & readl(pmipi_rx + MIPI_RX_ANA00_CSI0A) |
> + 0x8, pmipi_rx + MIPI_RX_ANA00_CSI0A);
> + if (is_4d1c(port))
> + writel(0xfffffffb & readl(pmipi_rx + MIPI_RX_ANA00_CSI0B) |
> + 0x4, pmipi_rx + MIPI_RX_ANA00_CSI0B);
> +
> + udelay(1);
> + /* 4d1c: MIPIRX_CONFIG_CSI_BASE = 0xC9000000; */
> + if (is_4d1c(port)) {
> + writel(0xffffff &
> + readl(pmipi_rx_conf + MIPI_RX_CON24_CSI0) |
> + 0xc9000000, pmipi_rx_conf + MIPI_RX_CON24_CSI0);
> + } else { /* 2d1c: MIPIRX_CONFIG_CSI_BASE = 0xE4000000; */
> + writel(0xffffff &
> + readl(pmipi_rx_conf + MIPI_RX_CON24_CSI0) |
> + 0xe4000000, pmipi_rx_conf + MIPI_RX_CON24_CSI0);
> + }
> +}
> +
> +static void mtk_seninf_set_csi_mipi(struct mtk_seninf *priv,
> + unsigned int seninf)
> +{
> + void *seninf_base = priv->base_reg;
> + void *pseninf = priv->base_reg + 0x1000 * seninf;
> + unsigned int dpcm = mtk_seninf_get_dpcm(priv);
> + unsigned int data_lane_num = priv->sensor[priv->port].num_data_lanes;
> + unsigned int cal_sel;
> + unsigned int data_header_order = 1;
> + unsigned int pad_sel = PAD_10BIT;
> + unsigned int val = 0;
> +
> + dev_dbg(priv->dev, "IS_4D1C %d port %d\n",
> + is_4d1c(priv->port), priv->port);
> +
> + switch (priv->port) {
> + case CFG_CSI_PORT_1:
> + cal_sel = 1;
> + writel(0x7ffff8fe & readl(seninf_base +
Here, too.
> + SENINF_TOP_PHY_SENINF_CTL_CSI1) | 0x80000200
> + , seninf_base + SENINF_TOP_PHY_SENINF_CTL_CSI1);
> + break;
> + case CFG_CSI_PORT_2:
> + cal_sel = 2;
> + writel(0x7ffff8fe & readl(seninf_base +
> + SENINF_TOP_PHY_SENINF_CTL_CSI2) | 0x80000200
> + , seninf_base + SENINF_TOP_PHY_SENINF_CTL_CSI2);
> + break;
> + case CFG_CSI_PORT_0:
> + cal_sel = 0;
> + writel(0x7ffff8fe & readl(seninf_base +
> + SENINF_TOP_PHY_SENINF_CTL_CSI0) | 0x80000200
> + , seninf_base + SENINF_TOP_PHY_SENINF_CTL_CSI0);
> + break;
> + case CFG_CSI_PORT_0A:
> + case CFG_CSI_PORT_0B:
> + cal_sel = 0;
> + writel(0x7fffc8fe & readl(seninf_base +
> + SENINF_TOP_PHY_SENINF_CTL_CSI0) | 0x80001100
> + , seninf_base + SENINF_TOP_PHY_SENINF_CTL_CSI0);
> + break;
> + }
> +
> + /* First Enable Sensor interface and select pad (0x1a04_0200) */
> + writel(readl(pseninf + SENINF1_CTRL) | 0x1
> + , pseninf + SENINF1_CTRL);
> + writel(0x8fffffff & readl(pseninf + SENINF1_CTRL) |
> + (pad_sel << 28), pseninf + SENINF1_CTRL);
> + writel(0xffff0fff & readl(pseninf + SENINF1_CTRL)
> + , pseninf + SENINF1_CTRL);
> + writel(0xffffff9f & readl(pseninf + SENINF1_CTRL_EXT) |
> + 0x40, pseninf + SENINF1_CTRL_EXT);
> +
> + mtk_seninf_set_dphy(priv, seninf);
> +
> + /* DPCM Enable */
> + val = 1 << ((dpcm == 0x2a) ? 15 : ((dpcm & 0xF) + 7));
> + writel(val, pseninf + SENINF1_CSI2_DPCM);
> +
> + /* Settle delay */
> + writel(0xffff00ff & readl(pseninf + SENINF1_CSI2_LNRD_TIMING) |
> + (SENINF_SETTLE_DELAY << 8), pseninf + SENINF1_CSI2_LNRD_TIMING);
> + /* CSI2 control */
> + val = readl(pseninf + SENINF1_CSI2_CTL) | (data_header_order << 16) |
> + 0x10 | ((1 << data_lane_num) - 1);
> + writel(val, pseninf + SENINF1_CSI2_CTL);
> + writel(0xfffff3f8 & readl(pseninf + SENINF1_CSI2_RESYNC_MERGE_CTL) |
> + 0x3, pseninf + SENINF1_CSI2_RESYNC_MERGE_CTL);
> + writel(0xfffff800 & readl(pseninf + SENINF1_CSI2_MODE)
> + , pseninf + SENINF1_CSI2_MODE);
> + writel(0x1dff00, pseninf + SENINF1_CSI2_DPHY_SYNC);
> + writel(0xfffffffe & readl(pseninf + SENINF1_CSI2_SPARE0)
> + , pseninf + SENINF1_CSI2_SPARE0);
> + writel(0xf5ffff7f & readl(pseninf + SENINF1_CSI2_CTL) |
> + 0x2000000, pseninf + SENINF1_CSI2_CTL);
> + writel(0xffffff00 & readl(pseninf + SENINF1_CSI2_HS_TRAIL) |
> + SENINF_HS_TRAIL_PARAMETER, pseninf + SENINF1_CSI2_HS_TRAIL);
> +
> + /* Set debug port to output packet number */
> + writel(0x8000001A, pseninf + SENINF1_CSI2_DGB_SEL);
> + /* Enable CSI2 IRQ mask */
> + /* Turn on all interrupt */
> + writel(0xffffffff, pseninf + SENINF1_CSI2_INT_EN);
> + /* Write clear CSI2 IRQ */
> + writel(0xffffffff, pseninf + SENINF1_CSI2_INT_STATUS);
> + /* Enable CSI2 Extend IRQ mask */
> + /* Turn on all interrupt */
> + writel(0x0000001f, pseninf + SENINF1_CSI2_INT_EN_EXT);
> + writel(0xffffff7f & readl(pseninf + SENINF1_CTRL) |
> + 0x80, pseninf + SENINF1_CTRL);
> +
> + udelay(1);
> + writel(0xffffff7f & readl(pseninf + SENINF1_CTRL)
> + , pseninf + SENINF1_CTRL);
> +}
> +
> +static int mtk_seninf_power_on(struct mtk_seninf *priv)
> +{
> + void *pseninf = priv->base_reg;
> + struct device *dev = priv->dev;
> + int seninf;
> + int ret;
> +
> + seninf = mtk_seninf_csi_port_to_seninf(priv->port);
> + if (seninf < 0) {
> + dev_err(dev, "seninf port mapping fail\n");
> + return -EINVAL;
> + }
> +
> + ret = pm_runtime_get_sync(priv->dev);
> + if (ret < 0) {
> + dev_err(priv->dev, "Failed to pm_runtime_get_sync: %d\n", ret);
> + pm_runtime_put(priv->dev);
pm_runtime_put_noidle(priv->dev);
> + return ret;
> + }
> +
> + /* Configure timestamp */
> + writel(readl(pseninf + SENINF1_CTRL) | 0x1
> + , pseninf + SENINF1_CTRL);
> + writel(0xffffffbfU & readl(pseninf + SENINF1_CTRL_EXT) |
> + 0x40, pseninf + SENINF1_CTRL_EXT);
> + writel(SENINF_TIMESTAMP_STEP, pseninf + SENINF_TG1_TM_STP);
> +
> + mtk_seninf_set_csi_mipi(priv, (unsigned int)seninf);
> +
> + mtk_seninf_set_mux(priv, (unsigned int)seninf);
> +
> + writel(0x0, pseninf + SENINF_TOP_CAM_MUX_CTRL);
> +
> + return 0;
> +}
> +
> +static void mtk_seninf_power_off(struct mtk_seninf *priv)
> +{
> + void *pmipi_rx = priv->csi2_rx[priv->port];
> + unsigned int seninf = mtk_seninf_csi_port_to_seninf(priv->port);
> + void *pseninf = priv->base_reg + 0x1000 * seninf;
> +
> + /* Disable CSI2(2.5G) first */
> + writel(readl(pseninf + SENINF1_CSI2_CTL) & 0xFFFFFFE0
> + , pseninf + SENINF1_CSI2_CTL);
Misplaced comma and there are more below. Please run checkpatch.pl on the
set.
> + /* Disable mipi BG */
> + switch (priv->port) {
> + case CFG_CSI_PORT_0A:
> + writel(0xfffffff3 & readl(pmipi_rx + MIPI_RX_ANA00_CSI0A)
> + , pmipi_rx + MIPI_RX_ANA00_CSI0A);
> + break;
> + case CFG_CSI_PORT_0B:
> + writel(0xfffffff3 & readl(pmipi_rx + MIPI_RX_ANA00_CSI0B)
> + , pmipi_rx + MIPI_RX_ANA00_CSI0B);
> + break;
> + default:
> + writel(0xfffffff3 & readl(pmipi_rx + MIPI_RX_ANA00_CSI0A)
> + , pmipi_rx + MIPI_RX_ANA00_CSI0A);
> + writel(0xfffffff3 & readl(pmipi_rx + MIPI_RX_ANA00_CSI0B)
> + , pmipi_rx + MIPI_RX_ANA00_CSI0B);
> + break;
> + }
> +
> + pm_runtime_put(priv->dev);
> +}
> +
> +static const struct v4l2_mbus_framefmt mtk_seninf_default_fmt = {
> + .code = MEDIA_BUS_FMT_SBGGR10_1X10,
> + .width = DEFAULT_WIDTH,
> + .height = DEFAULT_HEIGHT,
> + .field = V4L2_FIELD_NONE,
> + .colorspace = V4L2_COLORSPACE_SRGB,
> + .xfer_func = V4L2_XFER_FUNC_DEFAULT,
> + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
> + .quantization = V4L2_QUANTIZATION_DEFAULT,
> +};
> +
> +static void init_fmt(struct mtk_seninf *priv)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < NUM_PADS; i++)
> + priv->fmt[i].format = mtk_seninf_default_fmt;
> +}
> +
> +static int seninf_init_cfg(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg)
> +{
> + struct v4l2_mbus_framefmt *mf;
> + unsigned int i;
> +
> + for (i = 0; i < sd->entity.num_pads; i++) {
> + mf = v4l2_subdev_get_try_format(sd, cfg, i);
> + *mf = mtk_seninf_default_fmt;
> + }
> +
> + return 0;
> +}
> +
> +static int seninf_set_fmt(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_format *fmt)
> +{
> + struct mtk_seninf *priv = container_of(sd, struct mtk_seninf, subdev);
> +
> + if (fmt->format.code == ~0U || fmt->format.code == 0)
> + fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
> +
> + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
> + } else {
> + priv->fmt[fmt->pad].pad = fmt->pad;
> + priv->fmt[fmt->pad].format.code = fmt->format.code;
> + priv->fmt[fmt->pad].format.width = fmt->format.width;
> + priv->fmt[fmt->pad].format.height = fmt->format.height;
> + }
> +
> + return 0;
> +}
> +
> +static int seninf_get_fmt(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_format *fmt)
> +{
> + struct mtk_seninf *priv = container_of(sd, struct mtk_seninf, subdev);
Could you add an inline function to do this? Call it e.g. sd_to_mtk_seninf.
> +
> + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
> + } else {
> + fmt->format.code = priv->fmt[fmt->pad].format.code;
> + fmt->format.width = priv->fmt[fmt->pad].format.width;
> + fmt->format.height = priv->fmt[fmt->pad].format.height;
> + fmt->format.field = priv->fmt[fmt->pad].format.field;
> + fmt->format.colorspace = priv->fmt[fmt->pad].format.colorspace;
> + fmt->format.xfer_func = priv->fmt[fmt->pad].format.xfer_func;
> + fmt->format.ycbcr_enc = priv->fmt[fmt->pad].format.ycbcr_enc;
> + fmt->format.quantization =
> + priv->fmt[fmt->pad].format.quantization;
Could you do a direct assignment?
> + }
> +
> + return 0;
> +}
> +
> +static int seninf_enum_mbus_code(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_mbus_code_enum *code)
> +{
> + struct mtk_seninf *priv = container_of(sd, struct mtk_seninf, subdev);
> +
> + if (code->index >= NUM_PADS)
> + return -EINVAL;
This check is wrong. code->index is the index to the enumeration, i.e. the
number of supported mbus code.
> + code->code = priv->fmt[code->index].format.code;
> +
> + return 0;
> +}
> +
> +static int seninf_s_stream(struct v4l2_subdev *sd, int on)
> +{
> + struct mtk_seninf *priv = container_of(sd, struct mtk_seninf, subdev);
> + int ret = 0;
> +
> + if (on)
> + ret = mtk_seninf_power_on(priv);
You can return here without assigning ret.
> + else
> + mtk_seninf_power_off(priv);
No need for else.
> +
> + return ret;
And then return here.
> +};
> +
> +static const struct v4l2_subdev_pad_ops seninf_subdev_pad_ops = {
> + .init_cfg = seninf_init_cfg,
> + .set_fmt = seninf_set_fmt,
> + .get_fmt = seninf_get_fmt,
> + .enum_mbus_code = seninf_enum_mbus_code,
You're missing link_validate op here. Can you use
v4l2_subdev_link_validate_default?
> +};
> +
> +static const struct v4l2_subdev_video_ops seninf_subdev_video_ops = {
> + .s_stream = seninf_s_stream,
> +};
> +
> +static struct v4l2_subdev_core_ops seninf_subdev_core_ops = {
> + .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
> + .unsubscribe_event = v4l2_event_subdev_unsubscribe,
> +};
> +
> +static struct v4l2_subdev_ops seninf_subdev_ops = {
> + .core = &seninf_subdev_core_ops,
> + .video = &seninf_subdev_video_ops,
> + .pad = &seninf_subdev_pad_ops,
> +};
> +
> +static int seninf_link_setup(struct media_entity *entity,
> + const struct media_pad *local,
> + const struct media_pad *remote, u32 flags)
> +{
> + struct v4l2_subdev *sd;
> + struct mtk_seninf *priv;
> + struct device *dev;
> +
> + sd = media_entity_to_v4l2_subdev(entity);
> + priv = v4l2_get_subdevdata(sd);
> + dev = priv->dev;
> + dev_dbg(dev, "mtk_seninf: remote %d-%d, local %d-%d\n"
> + , remote->entity->graph_obj.id, remote->index
> + , local->entity->graph_obj.id, local->index);
Don't begin a line with a comma, please.
IMO such debug messages would better be placed on the framework side.
> + dev_dbg(dev, "local->flags %d flags %d\n", local->flags, flags);
> +
> + if ((local->flags & MEDIA_PAD_FL_SOURCE) &&
> + (flags & MEDIA_LNK_FL_ENABLED)) {
> + dev_dbg(dev, "set cam mux %d\n", local->index);
> + priv->mux_sel = local->index - CAM_MUX_IDX_MIN;
> + }
> +
> + if ((local->flags & MEDIA_PAD_FL_SINK) &&
> + (flags & MEDIA_LNK_FL_ENABLED)) {
> + dev_dbg(dev, "set sensor port\n", local->index);
> + /* Select port */
> + priv->port = local->index;
> + if (priv->port >= NUM_SENSORS) {
> + dev_err(dev, "port index is over number of ports\n");
> + return -EINVAL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static const struct media_entity_operations seninf_media_ops = {
> + .link_setup = seninf_link_setup,
> + .link_validate = v4l2_subdev_link_validate,
> +};
> +
> +struct sensor_async_subdev {
> + struct v4l2_async_subdev asd;
> + u32 port;
> + u32 lanes;
> +};
> +
> +static int mtk_seninf_notifier_bound
> + (struct v4l2_async_notifier *notifier,
Opening parenthesis to the same line as the function name.
> + struct v4l2_subdev *sd,
> + struct v4l2_async_subdev *asd)
> +{
> + struct mtk_seninf *priv =
> + container_of(notifier, struct mtk_seninf, notifier);
> + struct sensor_async_subdev *s_asd =
> + container_of(asd, struct sensor_async_subdev, asd);
> + int ret;
> +
> + dev_dbg(priv->dev, "%s bounded with port:%d lanes: %d\n",
"bound"
> + sd->entity.name, s_asd->port, s_asd->lanes);
> +
> + priv->sensor[s_asd->port].num_data_lanes = s_asd->lanes;
> +
> + ret = media_create_pad_link(&sd->entity, 0, &priv->subdev.entity,
> + s_asd->port, 0);
> + if (ret) {
> + dev_err(priv->dev, "failed to create link for %s\n",
> + sd->entity.name);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct v4l2_async_notifier_operations mtk_seninf_async_ops = {
> + .bound = mtk_seninf_notifier_bound,
> +};
> +
> +static int mtk_seninf_fwnode_parse(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd)
> +{
> + struct sensor_async_subdev *s_asd =
> + container_of(asd, struct sensor_async_subdev, asd);
> +
> + if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
> + dev_err(dev, "Only CSI2 bus type is currently supported\n");
> + return -EINVAL;
> + }
> +
> + s_asd->port = vep->base.port;
> + s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
> +
> + return 0;
> +}
> +
> +static int seninf_enable_test_pattern(struct mtk_seninf *priv, u32 pattern)
> +{
> + void *pseninf = priv->base_reg;
> + struct device *dev = priv->dev;
> + unsigned int val;
> +
> + switch (pattern) {
> + case TEST_GEN_PATTERN:
> + writel(0xC00, pseninf + SENINF_TOP_CTRL);
> + writel(0x1001, pseninf + SENINF1_CTRL);
> + writel(0x96DF1080, pseninf + SENINF1_MUX_CTRL);
> + writel(0x8000007F, pseninf + SENINF1_MUX_INTEN);
Alignment.
Please add #defines to document the bits of these registers. Same below.
> + writel(0x0, pseninf + SENINF1_MUX_SPARE);
> + writel(0xE2000, pseninf + SENINF1_MUX_CTRL_EXT);
> + writel(0x0, pseninf + SENINF1_MUX_CTRL_EXT);
> + writel(0x404C1, pseninf + SENINF_TG1_TM_CTL);
> + val = (priv->fmt[priv->port].format.height + 0x100) << 16
> + | priv->fmt[priv->port].format.width + 0x100;
> + writel(val, pseninf + SENINF_TG1_TM_SIZE);
> + writel(0x0, pseninf + SENINF_TG1_TM_CLK);
> + writel(0x1, pseninf + SENINF_TG1_TM_STP);
> + writel(readl(pseninf + SENINF1_CTRL_EXT) | 0x02
> + , pseninf + SENINF1_CTRL_EXT);
> + break;
> + case TEST_DUMP_DEBUG_INFO:
You could use the LOG_STATUS IOCTL instead. If you can instead do this at a
particular point of time (start of streaming, for instance), even better.
> + /* Sensor Interface Control */
> + dev_dbg(dev,
> + "SENINF_CSI2_CTL SENINF1:0x%x, 2:0x%x, 3:0x%x, 5:0x%x\n"
> + , readl(pseninf + SENINF1_CSI2_CTL)
> + , readl(pseninf + SENINF2_CSI2_CTL)
> + , readl(pseninf + SENINF3_CSI2_CTL)
> + , readl(pseninf + SENINF5_CSI2_CTL));
> + /* Read width/height */
> + /* Read interrupt status */
> + dev_dbg(dev, "SENINF1_IRQ:0x%x, 2:0x%x, 3:0x%x, 5:0x%x\n"
> + , readl(pseninf + SENINF1_CSI2_INT_STATUS)
> + , readl(pseninf + SENINF2_CSI2_INT_STATUS)
> + , readl(pseninf + SENINF3_CSI2_INT_STATUS)
> + , readl(pseninf + SENINF5_CSI2_INT_STATUS));
> + /* Mux1 */
> + dev_dbg(dev, "SENINF1_MUX_CTRL:0x%x, INTSTA:0x%x, DEBUG_2(0x%x)\n",
> + readl(pseninf + SENINF1_MUX_CTRL),
> + readl(pseninf + SENINF1_MUX_INTSTA),
> + readl(pseninf + SENINF1_MUX_DEBUG_2));
> + if (readl(pseninf + SENINF1_MUX_INTSTA) & 0x1) {
> + writel(0xffffffff, pseninf + SENINF1_MUX_INTSTA);
> + usleep_range(1000, 1000 * 2);
> + dev_warn(dev, "overrun CTRL:%x INTSTA:%x DEBUG_2:%x\n"
> + , readl(pseninf + SENINF1_MUX_CTRL)
> + , readl(pseninf + SENINF1_MUX_INTSTA)
> + , readl(pseninf + SENINF1_MUX_DEBUG_2));
> + }
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int seninf_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct mtk_seninf *priv = container_of(ctrl->handler,
> + struct mtk_seninf, ctrl_handler);
> +
> + switch (ctrl->id) {
> + case V4L2_CID_TEST_PATTERN:
> + return seninf_enable_test_pattern(priv, ctrl->val);
Please move the remaining content from seninf_enable_test_pattern here.
> + }
> +
> + return 0;
> +}
> +
> +static const struct v4l2_ctrl_ops seninf_ctrl_ops = {
> + .s_ctrl = seninf_set_ctrl,
> +};
> +
> +static const char * const seninf_test_pattern_menu[] = {
> + "Horizontal bars",
> + "Monitor status",
> +};
> +
> +static int seninf_initialize_controls(struct mtk_seninf *priv)
> +{
> + struct v4l2_ctrl_handler *handler;
> + int ret;
> +
> + handler = &priv->ctrl_handler;
> + ret = v4l2_ctrl_handler_init(handler, 2);
> + if (ret)
> + return ret;
> + v4l2_ctrl_new_std_menu_items(handler, &seninf_ctrl_ops,
> + V4L2_CID_TEST_PATTERN,
> + ARRAY_SIZE(seninf_test_pattern_menu) - 1,
> + 0, 0, seninf_test_pattern_menu);
> +
> + if (handler->error) {
> + ret = handler->error;
> + dev_err(priv->dev,
> + "Failed to init controls(%d)\n", ret);
> + goto err_free_handler;
> + }
> +
> + priv->subdev.ctrl_handler = handler;
> + return 0;
> +
> +err_free_handler:
> + v4l2_ctrl_handler_free(handler);
> +
> + return ret;
> +}
> +
> +static int mtk_seninf_media_register(struct mtk_seninf *priv)
> +{
> + struct v4l2_subdev *sd = &priv->subdev;
> + struct media_pad *pads = priv->pads;
> + struct device *dev = priv->dev;
> + int i;
> + int ret;
> +
> + v4l2_subdev_init(sd, &seninf_subdev_ops);
> +
> + init_fmt(priv);
> + ret = seninf_initialize_controls(priv);
> + if (ret) {
> + dev_err(dev, "Failed to initialize controls\n");
> + return ret;
> + }
> +
> + sd->flags |= (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
> +
> + priv->subdev.dev = dev;
> + snprintf(sd->name, V4L2_SUBDEV_NAME_SIZE, "%s",
> + dev_name(dev));
> + v4l2_set_subdevdata(sd, priv);
> +
> + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
> + sd->entity.ops = &seninf_media_ops;
> +
> + for (i = 0; i < NUM_SENSORS; i++)
> + pads[i].flags = MEDIA_PAD_FL_SINK;
> +
> + for (i = CAM_MUX_IDX_MIN; i < NUM_PADS; i++)
> + pads[i].flags = MEDIA_PAD_FL_SOURCE;
> + ret = media_entity_pads_init(&sd->entity, NUM_PADS, pads);
> + if (ret < 0)
> + goto err_free_handler;
> +
> + v4l2_async_notifier_init(&priv->notifier);
> + for (i = 0; i < NUM_SENSORS; ++i) {
> + ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port
> + (dev, &priv->notifier, sizeof(struct sensor_async_subdev)
> + , i, mtk_seninf_fwnode_parse);
Please see e.g. the omap3isp or ipu3-cio2 driver for an example on the
preferred way to parse information from firmware.
> + if (ret < 0)
> + goto err_clean_entity;
> + }
> +
> + priv->subdev.subdev_notifier = &priv->notifier;
> + priv->notifier.ops = &mtk_seninf_async_ops;
> + ret = v4l2_async_subdev_notifier_register(sd, &priv->notifier);
> + if (ret < 0) {
> + dev_err(dev, "v4l2 async notifier register failed\n");
> + goto err_clean_notififer;
> + }
> +
> + ret = v4l2_async_register_subdev(sd);
> + if (ret < 0) {
> + dev_err(dev, "v4l2 async register subdev failed\n");
> + goto err_clean_notififer;
> + }
> + return 0;
> +
> +err_clean_notififer:
> + v4l2_async_notifier_cleanup(&priv->notifier);
> +err_clean_entity:
> + media_entity_cleanup(&sd->entity);
> +err_free_handler:
> + v4l2_ctrl_handler_free(&priv->ctrl_handler);
> +
> + return ret;
> +}
> +
> +static int seninf_probe(struct platform_device *pdev)
> +{
> + /* List of clocks required by seninf */
> + static const char * const clk_names[] = {
> + "CLK_CAM_SENINF", "CLK_TOP_MUX_SENINF"
> + };
> + struct resource *res;
> + struct mtk_seninf *priv;
> + struct device *dev = &pdev->dev;
> + int i, ret;
> +
> + dev_err(dev, "seninf probe +\n");
Please remove.
> +
> + priv = devm_kzalloc(dev, sizeof(struct mtk_seninf), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + memset(priv, 0, sizeof(struct mtk_seninf));
The memory was already set to zero by devm_kzalloc().
> +
> + dev_set_drvdata(dev, priv);
> + priv->dev = dev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->base_reg = devm_ioremap_resource(dev, res);
> + if (IS_ERR(priv->base_reg))
> + return PTR_ERR(priv->base_reg);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + priv->rx_reg = devm_ioremap_resource(dev, res);
> + if (IS_ERR(priv->rx_reg))
> + return PTR_ERR(priv->rx_reg);
> +
> + priv->csi2_rx[CFG_CSI_PORT_0] = priv->rx_reg;
> + priv->csi2_rx[CFG_CSI_PORT_0A] = priv->rx_reg;
The same base address but a different port?
> + priv->csi2_rx[CFG_CSI_PORT_0B] = priv->rx_reg + 0x1000;
Please add #defines for these offsets.
> + priv->csi2_rx[CFG_CSI_PORT_1] = priv->rx_reg + 0x2000;
> + priv->csi2_rx[CFG_CSI_PORT_2] = priv->rx_reg + 0x4000;
> +
> + priv->num_clks = ARRAY_SIZE(clk_names);
> + priv->clks = devm_kcalloc(dev, priv->num_clks,
> + sizeof(*priv->clks), GFP_KERNEL);
> + if (!priv->clks)
> + return -ENOMEM;
> +
> + for (i = 0; i < priv->num_clks; ++i)
> + priv->clks[i].id = clk_names[i];
> +
> + ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks);
> + if (ret) {
> + dev_err(dev, "failed to get seninf clock:%d\n", ret);
> + return ret;
> + }
> +
> + ret = mtk_seninf_media_register(priv);
> +
> + pm_runtime_enable(dev);
You probably don't want to do this if the previous operation failed.
> + dev_info(dev, "seninf probe -\n");
Please remove.
> +
> + return ret;
> +}
> +
> +static int seninf_pm_suspend(struct device *dev)
> +{
> + struct mtk_seninf *priv = dev_get_drvdata(dev);
> +
> + dev_dbg(dev, "seninf runtime suspend\n");
> + clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
> +
> + return 0;
> +}
> +
> +static int seninf_pm_resume(struct device *dev)
> +{
> + struct mtk_seninf *priv = dev_get_drvdata(dev);
> + int ret;
> +
> + dev_dbg(dev, "seninf runtime resume\n");
> + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
> + if (ret) {
> + dev_err(dev, "failed to enable clock:%d\n", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops runtime_pm_ops = {
> + SET_RUNTIME_PM_OPS(seninf_pm_suspend, seninf_pm_resume, NULL)
> +};
> +
> +static int seninf_remove(struct platform_device *pdev)
> +{
> + struct mtk_seninf *priv = dev_get_drvdata(&pdev->dev);
> + struct v4l2_subdev *subdev = &priv->subdev;
> +
> + media_entity_cleanup(&subdev->entity);
> + v4l2_async_unregister_subdev(subdev);
> + v4l2_ctrl_handler_free(&priv->ctrl_handler);
> +
> + pm_runtime_disable(priv->dev);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id mtk_seninf_of_match[] = {
> + {.compatible = "mediatek,mt8183-seninf"},
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, mtk_seninf_of_match);
> +#endif
> +
> +static struct platform_driver seninf_pdrv = {
> + .driver = {
> + .name = "seninf",
> + .pm = &runtime_pm_ops,
> + .of_match_table = of_match_ptr(mtk_seninf_of_match),
> + },
> + .probe = seninf_probe,
> + .remove = seninf_remove,
> +};
> +
> +module_platform_driver(seninf_pdrv);
> +
> +MODULE_DESCRIPTION("MTK seninf driver");
> +MODULE_AUTHOR("Louis Kuo <louis.kuo@mediatek.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("MTK:mtk_seninf");
> diff --git a/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_def.h b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_def.h
> new file mode 100644
> index 000000000000..f2c0ea7c9800
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_def.h
> @@ -0,0 +1,59 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __SENINF_DRV_DEF_H__
> +#define __SENINF_DRV_DEF_H__
> +
> +#define SENINF_TIMESTAMP_STEP 0x67
> +#define SENINF_SETTLE_DELAY 0x15
> +#define SENINF_HS_TRAIL_PARAMETER 0x8
> +
> +#define NUM_PADS 12
> +#define NUM_SENSORS 4
> +#define CAM_MUX_IDX_MIN NUM_SENSORS
> +#define DEFAULT_WIDTH 1600
> +#define DEFAULT_HEIGHT 1200
> +
> +#define PAD_10BIT 0
> +
> +enum {
> + TEST_GEN_PATTERN = 0x0,
> + TEST_DUMP_DEBUG_INFO,
> +};
> +
> +enum {
> + CFG_CSI_PORT_0 = 0x0, /* 4D1C */
> + CFG_CSI_PORT_1, /* 4D1C */
> + CFG_CSI_PORT_2, /* 4D1C */
> + CFG_CSI_PORT_0A, /* 2D1C */
> + CFG_CSI_PORT_0B, /* 2D1C */
> + CFG_CSI_PORT_MAX_NUM,
> + CFG_CSI_PORT_NONE /*for non-MIPI sensor */
> +};
> +
> +enum {
> + ONE_PIXEL_MODE = 0x0,
> + TWO_PIXEL_MODE = 0x1,
> + FOUR_PIXEL_MODE = 0x2,
> +};
> +
> +enum {
> + SENINF_1 = 0x0,
> + SENINF_2 = 0x1,
> + SENINF_3 = 0x2,
> + SENINF_4 = 0x3,
> + SENINF_5 = 0x4,
> + SENINF_NUM,
> +};
> +
> +enum {
> + RAW_8BIT_FMT = 0x0,
> + RAW_10BIT_FMT = 0x1,
> + RAW_12BIT_FMT = 0x2,
> + YUV422_FMT = 0x3,
> + RAW_14BIT_FMT = 0x4,
> + RGB565_MIPI_FMT = 0x5,
> + RGB888_MIPI_FMT = 0x6,
> + JPEG_FMT = 0x7
> +};
> +
> +#endif /*__SENINF_DRV_DEF_H__ */
> diff --git a/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_reg.h b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_reg.h
> new file mode 100644
> index 000000000000..5f7e10916f35
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_reg.h
> @@ -0,0 +1,853 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef _SENINF_REG_H_
> +#define _SENINF_REG_H_
> +
> +/* 0x11c80000..0x11c850ac */
> +#define MIPI_RX_ANA00_CSI0A 0x0000
> +#define MIPI_RX_ANA04_CSI0A 0x0004
> +#define MIPI_RX_ANA08_CSI0A 0x0008
> +#define MIPI_RX_ANA0C_CSI0A 0x000C
> +#define MIPI_RX_ANA10_CSI0A 0x0010
> +#define MIPI_RX_ANA14_CSI0A 0x0014
> +#define MIPI_RX_ANA18_CSI0A 0x0018
> +#define MIPI_RX_ANA1C_CSI0A 0x001C
> +#define MIPI_RX_ANA20_CSI0A 0x0020
> +#define MIPI_RX_ANA24_CSI0A 0x0024
> +#define MIPI_RX_ANA28_CSI0A 0x0028
> +#define MIPI_RX_ANA2C_CSI0A 0x002C
> +#define MIPI_RX_ANA34_CSI0A 0x0034
> +#define MIPI_RX_ANA38_CSI0A 0x0038
> +#define MIPI_RX_ANA40_CSI0A 0x0040
> +#define MIPI_RX_ANA48_CSI0A 0x0048
> +#define MIPI_RX_WRAPPER80_CSI0A 0x0080
> +#define MIPI_RX_WRAPPER84_CSI0A 0x0084
> +#define MIPI_RX_WRAPPER88_CSI0A 0x0088
> +#define MIPI_RX_WRAPPER8C_CSI0A 0x008C
> +#define MIPI_RX_WRAPPER90_CSI0A 0x0090
> +#define MIPI_RX_WRAPPER94_CSI0A 0x0094
> +#define MIPI_RX_WRAPPER98_CSI0A 0x0098
> +#define MIPI_RX_WRAPPER9C_CSI0A 0x009C
> +#define MIPI_RX_ANAA4_CSI0A 0x00A4
> +#define MIPI_RX_ANAA8_CSI0A 0x00A8
> +#define MIPI_RX_ANA00_CSI0B 0x1000
> +#define MIPI_RX_ANA04_CSI0B 0x1004
> +#define MIPI_RX_ANA08_CSI0B 0x1008
> +#define MIPI_RX_ANA0C_CSI0B 0x100C
> +#define MIPI_RX_ANA10_CSI0B 0x1010
> +#define MIPI_RX_ANA14_CSI0B 0x1014
> +#define MIPI_RX_ANA18_CSI0B 0x1018
> +#define MIPI_RX_ANA1C_CSI0B 0x101C
> +#define MIPI_RX_ANA20_CSI0B 0x1020
> +#define MIPI_RX_ANA24_CSI0B 0x1024
> +#define MIPI_RX_ANA28_CSI0B 0x1028
> +#define MIPI_RX_ANA2C_CSI0B 0x102C
> +#define MIPI_RX_ANA34_CSI0B 0x1034
> +#define MIPI_RX_ANA38_CSI0B 0x1038
> +#define MIPI_RX_ANA48_CSI0B 0x1048
> +#define MIPI_RX_WRAPPER80_CSI0B 0x1080
> +#define MIPI_RX_WRAPPER84_CSI0B 0x1084
> +#define MIPI_RX_WRAPPER88_CSI0B 0x1088
> +#define MIPI_RX_WRAPPER8C_CSI0B 0x108C
> +#define MIPI_RX_WRAPPER90_CSI0B 0x1090
> +#define MIPI_RX_WRAPPER94_CSI0B 0x1094
> +#define MIPI_RX_WRAPPER98_CSI0B 0x1098
> +#define MIPI_RX_WRAPPER9C_CSI0B 0x109C
> +#define MIPI_RX_ANAA4_CSI0B 0x10A4
> +#define MIPI_RX_ANAA8_CSI0B 0x10A8
> +#define MIPI_RX_ANA00_CSI1A 0x2000
> +#define MIPI_RX_ANA04_CSI1A 0x2004
> +#define MIPI_RX_ANA08_CSI1A 0x2008
> +#define MIPI_RX_ANA0C_CSI1A 0x200C
> +#define MIPI_RX_ANA10_CSI1A 0x2010
> +#define MIPI_RX_ANA18_CSI1A 0x2018
> +#define MIPI_RX_ANA1C_CSI1A 0x201C
> +#define MIPI_RX_ANA24_CSI1A 0x2024
> +#define MIPI_RX_ANA48_CSI1A 0x2048
> +#define MIPI_RX_WRAPPER80_CSI1A 0x2080
> +#define MIPI_RX_WRAPPER84_CSI1A 0x2084
> +#define MIPI_RX_WRAPPER88_CSI1A 0x2088
> +#define MIPI_RX_WRAPPER8C_CSI1A 0x208C
> +#define MIPI_RX_WRAPPER90_CSI1A 0x2090
> +#define MIPI_RX_WRAPPER94_CSI1A 0x2094
> +#define MIPI_RX_WRAPPER98_CSI1A 0x2098
> +#define MIPI_RX_WRAPPER9C_CSI1A 0x209C
> +#define MIPI_RX_ANAA4_CSI1A 0x20A4
> +#define MIPI_RX_ANAA8_CSI1A 0x20A8
> +#define MIPI_RX_ANA00_CSI1B 0x3000
> +#define MIPI_RX_ANA04_CSI1B 0x3004
> +#define MIPI_RX_ANA08_CSI1B 0x3008
> +#define MIPI_RX_ANA0C_CSI1B 0x300C
> +#define MIPI_RX_ANA10_CSI1B 0x3010
> +#define MIPI_RX_ANA18_CSI1B 0x3018
> +#define MIPI_RX_ANA1C_CSI1B 0x301C
> +#define MIPI_RX_ANA24_CSI1B 0x3024
> +#define MIPI_RX_ANA48_CSI1B 0x3048
> +#define MIPI_RX_WRAPPER80_CSI1B 0x3080
> +#define MIPI_RX_WRAPPER84_CSI1B 0x3084
> +#define MIPI_RX_WRAPPER88_CSI1B 0x3088
> +#define MIPI_RX_WRAPPER8C_CSI1B 0x308C
> +#define MIPI_RX_WRAPPER90_CSI1B 0x3090
> +#define MIPI_RX_WRAPPER94_CSI1B 0x3094
> +#define MIPI_RX_WRAPPER98_CSI1B 0x3098
> +#define MIPI_RX_WRAPPER9C_CSI1B 0x309C
> +#define MIPI_RX_ANAA4_CSI1B 0x30A4
> +#define MIPI_RX_ANAA8_CSI1B 0x30A8
> +#define MIPI_RX_ANA00_CSI2A 0x4000
> +#define MIPI_RX_ANA04_CSI2A 0x4004
> +#define MIPI_RX_ANA08_CSI2A 0x4008
> +#define MIPI_RX_ANA0C_CSI2A 0x400C
> +#define MIPI_RX_ANA10_CSI2A 0x4010
> +#define MIPI_RX_ANA18_CSI2A 0x4018
> +#define MIPI_RX_ANA1C_CSI2A 0x401C
> +#define MIPI_RX_ANA24_CSI2A 0x4024
> +#define MIPI_RX_ANA48_CSI2A 0x4048
> +#define MIPI_RX_WRAPPER80_CSI2A 0x4080
> +#define MIPI_RX_WRAPPER84_CSI2A 0x4084
> +#define MIPI_RX_WRAPPER88_CSI2A 0x4088
> +#define MIPI_RX_WRAPPER8C_CSI2A 0x408C
> +#define MIPI_RX_WRAPPER90_CSI2A 0x4090
> +#define MIPI_RX_WRAPPER94_CSI2A 0x4094
> +#define MIPI_RX_WRAPPER98_CSI2A 0x4098
> +#define MIPI_RX_WRAPPER9C_CSI2A 0x409C
> +#define MIPI_RX_ANAA4_CSI2A 0x40A4
> +#define MIPI_RX_ANAA8_CSI2A 0x40A8
> +#define MIPI_RX_ANA00_CSI2B 0x5000
> +#define MIPI_RX_ANA04_CSI2B 0x5004
> +#define MIPI_RX_ANA08_CSI2B 0x5008
> +#define MIPI_RX_ANA0C_CSI2B 0x500C
> +#define MIPI_RX_ANA10_CSI2B 0x5010
> +#define MIPI_RX_ANA18_CSI2B 0x5018
> +#define MIPI_RX_ANA1C_CSI2B 0x501C
> +#define MIPI_RX_ANA24_CSI2B 0x5024
> +#define MIPI_RX_ANA48_CSI2B 0x5048
> +#define MIPI_RX_WRAPPER80_CSI2B 0x5080
> +#define MIPI_RX_WRAPPER84_CSI2B 0x5084
> +#define MIPI_RX_WRAPPER88_CSI2B 0x5088
> +#define MIPI_RX_WRAPPER8C_CSI2B 0x508C
> +#define MIPI_RX_WRAPPER90_CSI2B 0x5090
> +#define MIPI_RX_WRAPPER94_CSI2B 0x5094
> +#define MIPI_RX_WRAPPER98_CSI2B 0x5098
> +#define MIPI_RX_WRAPPER9C_CSI2B 0x509C
> +#define MIPI_RX_ANAA4_CSI2B 0x50A4
> +#define MIPI_RX_ANAA8_CSI2B 0x50A8
> +
> +/* 0x1a040000..0x1a047d40 */
> +#define SENINF_TOP_CTRL 0x0000
> +#define SENINF_TOP_CMODEL_PAR 0x0004
> +#define SENINF_TOP_MUX_CTRL 0x0008
> +#define SENINF_TOP_CAM_MUX_CTRL 0x0010
> +#define SENINF_TOP_N3D_A_CTL 0x0014
> +#define SENINF_TOP_N3D_B_CTL 0x0018
> +#define SENINF_TOP_PHY_SENINF_CTL_CSI0 0x001C
> +#define SENINF_TOP_PHY_SENINF_CTL_CSI1 0x0020
> +#define SENINF_TOP_PHY_SENINF_CTL_CSI2 0x0024
> +#define SENINF_N3D_A_CTL 0x0100
> +#define SENINF_N3D_A_POS 0x0104
> +#define SENINF_N3D_A_TRIG 0x0108
> +#define SENINF_N3D_A_INT 0x010C
> +#define SENINF_N3D_A_CNT0 0x0110
> +#define SENINF_N3D_A_CNT1 0x0114
> +#define SENINF_N3D_A_DBG 0x0118
> +#define SENINF_N3D_A_DIFF_THR 0x011C
> +#define SENINF_N3D_A_DIFF_CNT 0x0120
> +#define SENINF_N3D_A_DBG_1 0x0124
> +#define SENINF_N3D_A_VALID_TG_CNT 0x0128
> +#define SENINF_N3D_A_SYNC_A_PERIOD 0x012C
> +#define SENINF_N3D_A_SYNC_B_PERIOD 0x0130
> +#define SENINF_N3D_A_SYNC_A_PULSE_LEN 0x0134
> +#define SENINF_N3D_A_SYNC_B_PULSE_LEN 0x0138
> +#define SENINF_N3D_A_SUB_CNT 0x013C
> +#define SENINF_N3D_A_VSYNC_CNT 0x0140
> +#define SENINF1_CTRL 0x0200
> +#define SENINF1_CTRL_EXT 0x0204
> +#define SENINF1_ASYNC_CTRL 0x0208
> +#define SENINF_TG1_PH_CNT 0x0600
> +#define SENINF_TG1_SEN_CK 0x0604
> +#define SENINF_TG1_TM_CTL 0x0608
> +#define SENINF_TG1_TM_SIZE 0x060C
> +#define SENINF_TG1_TM_CLK 0x0610
> +#define SENINF_TG1_TM_STP 0x0614
> +#define MIPI_RX_CON24_CSI0 0x0824
> +#define MIPI_RX_CON28_CSI0 0x0828
> +#define MIPI_RX_CON34_CSI0 0x0834
> +#define MIPI_RX_CON38_CSI0 0x0838
> +#define MIPI_RX_CON3C_CSI0 0x083C
> +#define MIPI_RX_CON7C_CSI0 0x087C
> +#define MIPI_RX_CON80_CSI0 0x0880
> +#define MIPI_RX_CON84_CSI0 0x0884
> +#define MIPI_RX_CON88_CSI0 0x0888
> +#define MIPI_RX_CON8C_CSI0 0x088C
> +#define MIPI_RX_CON90_CSI0 0x0890
> +#define MIPI_RX_CON94_CSI0 0x0894
> +#define MIPI_RX_CON98_CSI0 0x0898
> +#define MIPI_RX_CONA0_CSI0 0x08A0
> +#define MIPI_RX_CONB0_CSI0 0x08B0
> +#define MIPI_RX_CONB4_CSI0 0x08B4
> +#define MIPI_RX_CONB8_CSI0 0x08B8
> +#define MIPI_RX_CONBC_CSI0 0x08BC
> +#define MIPI_RX_CONC0_CSI0 0x08C0
> +#define MIPI_RX_CONC4_CSI0 0x08C4
> +#define MIPI_RX_CONC8_CSI0 0x08C8
> +#define MIPI_RX_CONCC_CSI0 0x08CC
> +#define MIPI_RX_COND0_CSI0 0x08D0
> +#define SENINF1_CSI2_CTL 0x0A00
> +#define SENINF1_CSI2_LNRC_TIMING 0x0A04
> +#define SENINF1_CSI2_LNRD_TIMING 0x0A08
> +#define SENINF1_CSI2_DPCM 0x0A0C
> +#define SENINF1_CSI2_INT_EN 0x0A10
> +#define SENINF1_CSI2_INT_STATUS 0x0A14
> +#define SENINF1_CSI2_DGB_SEL 0x0A18
> +#define SENINF1_CSI2_DBG_PORT 0x0A1C
> +#define SENINF1_CSI2_SPARE0 0x0A20
> +#define SENINF1_CSI2_SPARE1 0x0A24
> +#define SENINF1_CSI2_LNRC_FSM 0x0A28
> +#define SENINF1_CSI2_LNRD_FSM 0x0A2C
> +#define SENINF1_CSI2_FRAME_LINE_NUM 0x0A30
> +#define SENINF1_CSI2_GENERIC_SHORT 0x0A34
> +#define SENINF1_CSI2_HSRX_DBG 0x0A38
> +#define SENINF1_CSI2_DI 0x0A3C
> +#define SENINF1_CSI2_HS_TRAIL 0x0A40
> +#define SENINF1_CSI2_DI_CTRL 0x0A44
> +#define SENINF1_CSI2_DETECT_CON1 0x0A4C
> +#define SENINF1_CSI2_DETECT_CON2 0x0A50
> +#define SENINF1_CSI2_DETECT_CON3 0x0A54
> +#define SENINF1_CSI2_RLR0_CON0 0x0A58
> +#define SENINF1_CSI2_RLR1_CON0 0x0A5C
> +#define SENINF1_CSI2_RLR2_CON0 0x0A60
> +#define SENINF1_CSI2_RLR_CON0 0x0A64
> +#define SENINF1_CSI2_MUX_CON 0x0A68
> +#define SENINF1_CSI2_DETECT_DBG0 0x0A6C
> +#define SENINF1_CSI2_DETECT_DBG1 0x0A70
> +#define SENINF1_CSI2_RESYNC_MERGE_CTL 0x0A74
> +#define SENINF1_CSI2_CTRL_TRIO_MUX 0x0A78
> +#define SENINF1_CSI2_CTRL_TRIO_CON 0x0A7C
> +#define SENINF1_FIX_ADDR_CPHY0_DBG 0x0A80
> +#define SENINF1_FIX_ADDR_CPHY1_DBG 0x0A84
> +#define SENINF1_FIX_ADDR_CPHY2_DBG 0x0A88
> +#define SENINF1_FIX_ADDR_DBG 0x0A8C
> +#define SENINF1_WIRE_STATE_DECODE_CPHY0_DBG0 0x0A90
> +#define SENINF1_WIRE_STATE_DECODE_CPHY0_DBG1 0x0A94
> +#define SENINF1_WIRE_STATE_DECODE_CPHY1_DBG0 0x0A98
> +#define SENINF1_WIRE_STATE_DECODE_CPHY1_DBG1 0x0A9C
> +#define SENINF1_WIRE_STATE_DECODE_CPHY2_DBG0 0x0AA0
> +#define SENINF1_WIRE_STATE_DECODE_CPHY2_DBG1 0x0AA4
> +#define SENINF1_SYNC_RESYNC_CTL 0x0AA8
> +#define SENINF1_POST_DETECT_CTL 0x0AAC
> +#define SENINF1_WIRE_STATE_DECODE_CONFIG 0x0AB0
> +#define SENINF1_CSI2_CPHY_LNRD_FSM 0x0AB4
> +#define SENINF1_FIX_ADDR_CPHY0_DBG0 0x0AB8
> +#define SENINF1_FIX_ADDR_CPHY0_DBG1 0x0ABC
> +#define SENINF1_FIX_ADDR_CPHY0_DBG2 0x0AC0
> +#define SENINF1_FIX_ADDR_CPHY1_DBG0 0x0AC4
> +#define SENINF1_FIX_ADDR_CPHY1_DBG1 0x0AC8
> +#define SENINF1_FIX_ADDR_CPHY1_DBG2 0x0ACC
> +#define SENINF1_FIX_ADDR_CPHY2_DBG0 0x0AD0
> +#define SENINF1_FIX_ADDR_CPHY2_DBG1 0x0AD4
> +#define SENINF1_FIX_ADDR_CPHY2_DBG2 0x0AD8
> +#define SENINF1_FIX_ADDR_DBG0 0x0ADC
> +#define SENINF1_FIX_ADDR_DBG1 0x0AE0
> +#define SENINF1_FIX_ADDR_DBG2 0x0AE4
> +#define SENINF1_CSI2_MODE 0x0AE8
> +#define SENINF1_CSI2_DI_EXT 0x0AF0
> +#define SENINF1_CSI2_DI_CTRL_EXT 0x0AF4
> +#define SENINF1_CSI2_CPHY_LOOPBACK 0x0AF8
> +#define SENINF1_CSI2_PROGSEQ_0 0x0B00
> +#define SENINF1_CSI2_PROGSEQ_1 0x0B04
> +#define SENINF1_CSI2_INT_EN_EXT 0x0B10
> +#define SENINF1_CSI2_INT_STATUS_EXT 0x0B14
> +#define SENINF1_CSI2_CPHY_FIX_POINT_RST 0x0B18
> +#define SENINF1_CSI2_RLR3_CON0 0x0B1C
> +#define SENINF1_CSI2_DPHY_SYNC 0x0B20
> +#define SENINF1_CSI2_DESKEW_SYNC 0x0B24
> +#define SENINF1_CSI2_DETECT_DBG2 0x0B28
> +#define SENINF1_FIX_ADDR_CPHY3_DBG0 0x0B30
> +#define SENINF1_FIX_ADDR_CPHY3_DBG1 0x0B34
> +#define SENINF1_FIX_ADDR_CPHY3_DBG2 0x0B38
> +#define SENINF1_CSI2_DI_EXT_2 0x0B3C
> +#define SENINF1_CSI2_DI_CTRL_EXT_2 0x0B40
> +#define SENINF1_WIRE_STATE_DECODE_CPHY3_DBG0 0x0B44
> +#define SENINF1_WIRE_STATE_DECODE_CPHY3_DBG1 0x0B48
> +#define SENINF1_MUX_CTRL 0x0D00
> +#define SENINF1_MUX_INTEN 0x0D04
> +#define SENINF1_MUX_INTSTA 0x0D08
> +#define SENINF1_MUX_SIZE 0x0D0C
> +#define SENINF1_MUX_DEBUG_1 0x0D10
> +#define SENINF1_MUX_DEBUG_2 0x0D14
> +#define SENINF1_MUX_DEBUG_3 0x0D18
> +#define SENINF1_MUX_DEBUG_4 0x0D1C
> +#define SENINF1_MUX_DEBUG_5 0x0D20
> +#define SENINF1_MUX_DEBUG_6 0x0D24
> +#define SENINF1_MUX_DEBUG_7 0x0D28
> +#define SENINF1_MUX_SPARE 0x0D2C
> +#define SENINF1_MUX_DATA 0x0D30
> +#define SENINF1_MUX_DATA_CNT 0x0D34
> +#define SENINF1_MUX_CROP 0x0D38
> +#define SENINF1_MUX_CTRL_EXT 0x0D3C
> +#define SENINF_N3D_B_CTL 0x1100
> +#define SENINF_N3D_B_POS 0x1104
> +#define SENINF_N3D_B_TRIG 0x1108
> +#define SENINF_N3D_B_INT 0x110C
> +#define SENINF_N3D_B_CNT0 0x1110
> +#define SENINF_N3D_B_CNT1 0x1114
> +#define SENINF_N3D_B_DBG 0x1118
> +#define SENINF_N3D_B_DIFF_THR 0x111C
> +#define SENINF_N3D_B_DIFF_CNT 0x1120
> +#define SENINF_N3D_B_DBG_1 0x1124
> +#define SENINF_N3D_B_VALID_TG_CNT 0x1128
> +#define SENINF_N3D_B_SYNC_A_PERIOD 0x112C
> +#define SENINF_N3D_B_SYNC_B_PERIOD 0x1130
> +#define SENINF_N3D_B_SYNC_A_PULSE_LEN 0x1134
> +#define SENINF_N3D_B_SYNC_B_PULSE_LEN 0x1138
> +#define SENINF_N3D_B_SUB_CNT 0x113C
> +#define SENINF_N3D_B_VSYNC_CNT 0x1140
> +#define SENINF2_CTRL 0x1200
> +#define SENINF2_CTRL_EXT 0x1204
> +#define SENINF2_ASYNC_CTRL 0x1208
> +#define SENINF_TG2_PH_CNT 0x1600
> +#define SENINF_TG2_SEN_CK 0x1604
> +#define SENINF_TG2_TM_CTL 0x1608
> +#define SENINF_TG2_TM_SIZE 0x160C
> +#define SENINF_TG2_TM_CLK 0x1610
> +#define SENINF_TG2_TM_STP 0x1614
> +#define MIPI_RX_CON24_CSI1 0x1824
> +#define MIPI_RX_CON28_CSI1 0x1828
> +#define MIPI_RX_CON34_CSI1 0x1834
> +#define MIPI_RX_CON38_CSI1 0x1838
> +#define MIPI_RX_CON3C_CSI1 0x183C
> +#define MIPI_RX_CON7C_CSI1 0x187C
> +#define MIPI_RX_CON80_CSI1 0x1880
> +#define MIPI_RX_CON84_CSI1 0x1884
> +#define MIPI_RX_CON88_CSI1 0x1888
> +#define MIPI_RX_CON8C_CSI1 0x188C
> +#define MIPI_RX_CON90_CSI1 0x1890
> +#define MIPI_RX_CON94_CSI1 0x1894
> +#define MIPI_RX_CON98_CSI1 0x1898
> +#define MIPI_RX_CONA0_CSI1 0x18A0
> +#define MIPI_RX_CONB0_CSI1 0x18B0
> +#define MIPI_RX_CONB4_CSI1 0x18B4
> +#define MIPI_RX_CONB8_CSI1 0x18B8
> +#define MIPI_RX_CONBC_CSI1 0x18BC
> +#define MIPI_RX_CONC0_CSI1 0x18C0
> +#define MIPI_RX_CONC4_CSI1 0x18C4
> +#define MIPI_RX_CONC8_CSI1 0x18C8
> +#define MIPI_RX_CONCC_CSI1 0x18CC
> +#define MIPI_RX_COND0_CSI1 0x18D0
> +#define SENINF2_CSI2_CTL 0x1A00
> +#define SENINF2_CSI2_LNRC_TIMING 0x1A04
> +#define SENINF2_CSI2_LNRD_TIMING 0x1A08
> +#define SENINF2_CSI2_DPCM 0x1A0C
> +#define SENINF2_CSI2_INT_EN 0x1A10
> +#define SENINF2_CSI2_INT_STATUS 0x1A14
> +#define SENINF2_CSI2_DGB_SEL 0x1A18
> +#define SENINF2_CSI2_DBG_PORT 0x1A1C
> +#define SENINF2_CSI2_SPARE0 0x1A20
> +#define SENINF2_CSI2_SPARE1 0x1A24
> +#define SENINF2_CSI2_LNRC_FSM 0x1A28
> +#define SENINF2_CSI2_LNRD_FSM 0x1A2C
> +#define SENINF2_CSI2_FRAME_LINE_NUM 0x1A30
> +#define SENINF2_CSI2_GENERIC_SHORT 0x1A34
> +#define SENINF2_CSI2_HSRX_DBG 0x1A38
> +#define SENINF2_CSI2_DI 0x1A3C
> +#define SENINF2_CSI2_HS_TRAIL 0x1A40
> +#define SENINF2_CSI2_DI_CTRL 0x1A44
> +#define SENINF2_CSI2_DETECT_CON1 0x1A4C
> +#define SENINF2_CSI2_DETECT_CON2 0x1A50
> +#define SENINF2_CSI2_DETECT_CON3 0x1A54
> +#define SENINF2_CSI2_RLR0_CON0 0x1A58
> +#define SENINF2_CSI2_RLR1_CON0 0x1A5C
> +#define SENINF2_CSI2_RLR2_CON0 0x1A60
> +#define SENINF2_CSI2_RLR_CON0 0x1A64
> +#define SENINF2_CSI2_MUX_CON 0x1A68
> +#define SENINF2_CSI2_DETECT_DBG0 0x1A6C
> +#define SENINF2_CSI2_DETECT_DBG1 0x1A70
> +#define SENINF2_CSI2_RESYNC_MERGE_CTL 0x1A74
> +#define SENINF2_CSI2_CTRL_TRIO_MUX 0x1A78
> +#define SENINF2_CSI2_CTRL_TRIO_CON 0x1A7C
> +#define SENINF2_FIX_ADDR_CPHY0_DBG 0x1A80
> +#define SENINF2_FIX_ADDR_CPHY1_DBG 0x1A84
> +#define SENINF2_FIX_ADDR_CPHY2_DBG 0x1A88
> +#define SENINF2_FIX_ADDR_DBG 0x1A8C
> +#define SENINF2_WIRE_STATE_DECODE_CPHY0_DBG0 0x1A90
> +#define SENINF2_WIRE_STATE_DECODE_CPHY0_DBG1 0x1A94
> +#define SENINF2_WIRE_STATE_DECODE_CPHY1_DBG0 0x1A98
> +#define SENINF2_WIRE_STATE_DECODE_CPHY1_DBG1 0x1A9C
> +#define SENINF2_WIRE_STATE_DECODE_CPHY2_DBG0 0x1AA0
> +#define SENINF2_WIRE_STATE_DECODE_CPHY2_DBG1 0x1AA4
> +#define SENINF2_SYNC_RESYNC_CTL 0x1AA8
> +#define SENINF2_POST_DETECT_CTL 0x1AAC
> +#define SENINF2_WIRE_STATE_DECODE_CONFIG 0x1AB0
> +#define SENINF2_CSI2_CPHY_LNRD_FSM 0x1AB4
> +#define SENINF2_FIX_ADDR_CPHY0_DBG0 0x1AB8
> +#define SENINF2_FIX_ADDR_CPHY0_DBG1 0x1ABC
> +#define SENINF2_FIX_ADDR_CPHY0_DBG2 0x1AC0
> +#define SENINF2_FIX_ADDR_CPHY1_DBG0 0x1AC4
> +#define SENINF2_FIX_ADDR_CPHY1_DBG1 0x1AC8
> +#define SENINF2_FIX_ADDR_CPHY1_DBG2 0x1ACC
> +#define SENINF2_FIX_ADDR_CPHY2_DBG0 0x1AD0
> +#define SENINF2_FIX_ADDR_CPHY2_DBG1 0x1AD4
> +#define SENINF2_FIX_ADDR_CPHY2_DBG2 0x1AD8
> +#define SENINF2_FIX_ADDR_DBG0 0x1ADC
> +#define SENINF2_FIX_ADDR_DBG1 0x1AE0
> +#define SENINF2_FIX_ADDR_DBG2 0x1AE4
> +#define SENINF2_CSI2_MODE 0x1AE8
> +#define SENINF2_CSI2_DI_EXT 0x1AF0
> +#define SENINF2_CSI2_DI_CTRL_EXT 0x1AF4
> +#define SENINF2_CSI2_CPHY_LOOPBACK 0x1AF8
> +#define SENINF2_CSI2_PROGSEQ_0 0x1B00
> +#define SENINF2_CSI2_PROGSEQ_1 0x1B04
> +#define SENINF2_CSI2_INT_EN_EXT 0x1B10
> +#define SENINF2_CSI2_INT_STATUS_EXT 0x1B14
> +#define SENINF2_CSI2_CPHY_FIX_POINT_RST 0x1B18
> +#define SENINF2_CSI2_RLR3_CON0 0x1B1C
> +#define SENINF2_CSI2_DPHY_SYNC 0x1B20
> +#define SENINF2_CSI2_DESKEW_SYNC 0x1B24
> +#define SENINF2_CSI2_DETECT_DBG2 0x1B28
> +#define SENINF2_FIX_ADDR_CPHY3_DBG0 0x1B30
> +#define SENINF2_FIX_ADDR_CPHY3_DBG1 0x1B34
> +#define SENINF2_FIX_ADDR_CPHY3_DBG2 0x1B38
> +#define SENINF2_CSI2_DI_EXT_2 0x1B3C
> +#define SENINF2_CSI2_DI_CTRL_EXT_2 0x1B40
> +#define SENINF2_WIRE_STATE_DECODE_CPHY3_DBG0 0x1B44
> +#define SENINF2_WIRE_STATE_DECODE_CPHY3_DBG1 0x1B48
> +#define SENINF2_MUX_CTRL 0x1D00
> +#define SENINF2_MUX_INTEN 0x1D04
> +#define SENINF2_MUX_INTSTA 0x1D08
> +#define SENINF2_MUX_SIZE 0x1D0C
> +#define SENINF2_MUX_DEBUG_1 0x1D10
> +#define SENINF2_MUX_DEBUG_2 0x1D14
> +#define SENINF2_MUX_DEBUG_3 0x1D18
> +#define SENINF2_MUX_DEBUG_4 0x1D1C
> +#define SENINF2_MUX_DEBUG_5 0x1D20
> +#define SENINF2_MUX_DEBUG_6 0x1D24
> +#define SENINF2_MUX_DEBUG_7 0x1D28
> +#define SENINF2_MUX_SPARE 0x1D2C
> +#define SENINF2_MUX_DATA 0x1D30
> +#define SENINF2_MUX_DATA_CNT 0x1D34
> +#define SENINF2_MUX_CROP 0x1D38
> +#define SENINF2_MUX_CTRL_EXT 0x1D3C
> +#define SENINF3_CTRL 0x2200
> +#define SENINF3_CTRL_EXT 0x2204
> +#define SENINF3_ASYNC_CTRL 0x2208
> +#define SENINF_TG3_PH_CNT 0x2600
> +#define SENINF_TG3_SEN_CK 0x2604
> +#define SENINF_TG3_TM_CTL 0x2608
> +#define SENINF_TG3_TM_SIZE 0x260C
> +#define SENINF_TG3_TM_CLK 0x2610
> +#define SENINF_TG3_TM_STP 0x2614
> +#define MIPI_RX_CON24_CSI2 0x2824
> +#define MIPI_RX_CON28_CSI2 0x2828
> +#define MIPI_RX_CON34_CSI2 0x2834
> +#define MIPI_RX_CON38_CSI2 0x2838
> +#define MIPI_RX_CON3C_CSI2 0x283C
> +#define MIPI_RX_CON7C_CSI2 0x287C
> +#define MIPI_RX_CON80_CSI2 0x2880
> +#define MIPI_RX_CON84_CSI2 0x2884
> +#define MIPI_RX_CON88_CSI2 0x2888
> +#define MIPI_RX_CON8C_CSI2 0x288C
> +#define MIPI_RX_CON90_CSI2 0x2890
> +#define MIPI_RX_CON94_CSI2 0x2894
> +#define MIPI_RX_CON98_CSI2 0x2898
> +#define MIPI_RX_CONA0_CSI2 0x28A0
> +#define MIPI_RX_CONB0_CSI2 0x28B0
> +#define MIPI_RX_CONB4_CSI2 0x28B4
> +#define MIPI_RX_CONB8_CSI2 0x28B8
> +#define MIPI_RX_CONBC_CSI2 0x28BC
> +#define MIPI_RX_CONC0_CSI2 0x28C0
> +#define MIPI_RX_CONC4_CSI2 0x28C4
> +#define MIPI_RX_CONC8_CSI2 0x28C8
> +#define MIPI_RX_CONCC_CSI2 0x28CC
> +#define MIPI_RX_COND0_CSI2 0x28D0
> +#define SENINF3_CSI2_CTL 0x2A00
> +#define SENINF3_CSI2_LNRC_TIMING 0x2A04
> +#define SENINF3_CSI2_LNRD_TIMING 0x2A08
> +#define SENINF3_CSI2_DPCM 0x2A0C
> +#define SENINF3_CSI2_INT_EN 0x2A10
> +#define SENINF3_CSI2_INT_STATUS 0x2A14
> +#define SENINF3_CSI2_DGB_SEL 0x2A18
> +#define SENINF3_CSI2_DBG_PORT 0x2A1C
> +#define SENINF3_CSI2_SPARE0 0x2A20
> +#define SENINF3_CSI2_SPARE1 0x2A24
> +#define SENINF3_CSI2_LNRC_FSM 0x2A28
> +#define SENINF3_CSI2_LNRD_FSM 0x2A2C
> +#define SENINF3_CSI2_FRAME_LINE_NUM 0x2A30
> +#define SENINF3_CSI2_GENERIC_SHORT 0x2A34
> +#define SENINF3_CSI2_HSRX_DBG 0x2A38
> +#define SENINF3_CSI2_DI 0x2A3C
> +#define SENINF3_CSI2_HS_TRAIL 0x2A40
> +#define SENINF3_CSI2_DI_CTRL 0x2A44
> +#define SENINF3_CSI2_DETECT_CON1 0x2A4C
> +#define SENINF3_CSI2_DETECT_CON2 0x2A50
> +#define SENINF3_CSI2_DETECT_CON3 0x2A54
> +#define SENINF3_CSI2_RLR0_CON0 0x2A58
> +#define SENINF3_CSI2_RLR1_CON0 0x2A5C
> +#define SENINF3_CSI2_RLR2_CON0 0x2A60
> +#define SENINF3_CSI2_RLR_CON0 0x2A64
> +#define SENINF3_CSI2_MUX_CON 0x2A68
> +#define SENINF3_CSI2_DETECT_DBG0 0x2A6C
> +#define SENINF3_CSI2_DETECT_DBG1 0x2A70
> +#define SENINF3_CSI2_RESYNC_MERGE_CTL 0x2A74
> +#define SENINF3_CSI2_CTRL_TRIO_MUX 0x2A78
> +#define SENINF3_CSI2_CTRL_TRIO_CON 0x2A7C
> +#define SENINF3_FIX_ADDR_CPHY0_DBG 0x2A80
> +#define SENINF3_FIX_ADDR_CPHY1_DBG 0x2A84
> +#define SENINF3_FIX_ADDR_CPHY2_DBG 0x2A88
> +#define SENINF3_FIX_ADDR_DBG 0x2A8C
> +#define SENINF3_WIRE_STATE_DECODE_CPHY0_DBG0 0x2A90
> +#define SENINF3_WIRE_STATE_DECODE_CPHY0_DBG1 0x2A94
> +#define SENINF3_WIRE_STATE_DECODE_CPHY1_DBG0 0x2A98
> +#define SENINF3_WIRE_STATE_DECODE_CPHY1_DBG1 0x2A9C
> +#define SENINF3_WIRE_STATE_DECODE_CPHY2_DBG0 0x2AA0
> +#define SENINF3_WIRE_STATE_DECODE_CPHY2_DBG1 0x2AA4
> +#define SENINF3_SYNC_RESYNC_CTL 0x2AA8
> +#define SENINF3_POST_DETECT_CTL 0x2AAC
> +#define SENINF3_WIRE_STATE_DECODE_CONFIG 0x2AB0
> +#define SENINF3_CSI2_CPHY_LNRD_FSM 0x2AB4
> +#define SENINF3_FIX_ADDR_CPHY0_DBG0 0x2AB8
> +#define SENINF3_FIX_ADDR_CPHY0_DBG1 0x2ABC
> +#define SENINF3_FIX_ADDR_CPHY0_DBG2 0x2AC0
> +#define SENINF3_FIX_ADDR_CPHY1_DBG0 0x2AC4
> +#define SENINF3_FIX_ADDR_CPHY1_DBG1 0x2AC8
> +#define SENINF3_FIX_ADDR_CPHY1_DBG2 0x2ACC
> +#define SENINF3_FIX_ADDR_CPHY2_DBG0 0x2AD0
> +#define SENINF3_FIX_ADDR_CPHY2_DBG1 0x2AD4
> +#define SENINF3_FIX_ADDR_CPHY2_DBG2 0x2AD8
> +#define SENINF3_FIX_ADDR_DBG0 0x2ADC
> +#define SENINF3_FIX_ADDR_DBG1 0x2AE0
> +#define SENINF3_FIX_ADDR_DBG2 0x2AE4
> +#define SENINF3_CSI2_MODE 0x2AE8
> +#define SENINF3_CSI2_DI_EXT 0x2AF0
> +#define SENINF3_CSI2_DI_CTRL_EXT 0x2AF4
> +#define SENINF3_CSI2_CPHY_LOOPBACK 0x2AF8
> +#define SENINF3_CSI2_PROGSEQ_0 0x2B00
> +#define SENINF3_CSI2_PROGSEQ_1 0x2B04
> +#define SENINF3_CSI2_INT_EN_EXT 0x2B10
> +#define SENINF3_CSI2_INT_STATUS_EXT 0x2B14
> +#define SENINF3_CSI2_CPHY_FIX_POINT_RST 0x2B18
> +#define SENINF3_CSI2_RLR3_CON0 0x2B1C
> +#define SENINF3_CSI2_DPHY_SYNC 0x2B20
> +#define SENINF3_CSI2_DESKEW_SYNC 0x2B24
> +#define SENINF3_CSI2_DETECT_DBG2 0x2B28
> +#define SENINF3_FIX_ADDR_CPHY3_DBG0 0x2B30
> +#define SENINF3_FIX_ADDR_CPHY3_DBG1 0x2B34
> +#define SENINF3_FIX_ADDR_CPHY3_DBG2 0x2B38
> +#define SENINF3_CSI2_DI_EXT_2 0x2B3C
> +#define SENINF3_CSI2_DI_CTRL_EXT_2 0x2B40
> +#define SENINF3_WIRE_STATE_DECODE_CPHY3_DBG0 0x2B44
> +#define SENINF3_WIRE_STATE_DECODE_CPHY3_DBG1 0x2B48
> +#define SENINF3_MUX_CTRL 0x2D00
> +#define SENINF3_MUX_INTEN 0x2D04
> +#define SENINF3_MUX_INTSTA 0x2D08
> +#define SENINF3_MUX_SIZE 0x2D0C
> +#define SENINF3_MUX_DEBUG_1 0x2D10
> +#define SENINF3_MUX_DEBUG_2 0x2D14
> +#define SENINF3_MUX_DEBUG_3 0x2D18
> +#define SENINF3_MUX_DEBUG_4 0x2D1C
> +#define SENINF3_MUX_DEBUG_5 0x2D20
> +#define SENINF3_MUX_DEBUG_6 0x2D24
> +#define SENINF3_MUX_DEBUG_7 0x2D28
> +#define SENINF3_MUX_SPARE 0x2D2C
> +#define SENINF3_MUX_DATA 0x2D30
> +#define SENINF3_MUX_DATA_CNT 0x2D34
> +#define SENINF3_MUX_CROP 0x2D38
> +#define SENINF3_MUX_CTRL_EXT 0x2D3C
> +#define SENINF4_CTRL 0x3200
> +#define SENINF4_CTRL_EXT 0x3204
> +#define SENINF4_ASYNC_CTRL 0x3208
> +#define SENINF_TG4_PH_CNT 0x3600
> +#define SENINF_TG4_SEN_CK 0x3604
> +#define SENINF_TG4_TM_CTL 0x3608
> +#define SENINF_TG4_TM_SIZE 0x360C
> +#define SENINF_TG4_TM_CLK 0x3610
> +#define SENINF_TG4_TM_STP 0x3614
> +#define MIPI_RX_CON24_CSI3 0x3824
> +#define MIPI_RX_CON28_CSI3 0x3828
> +#define MIPI_RX_CON34_CSI3 0x3834
> +#define MIPI_RX_CON38_CSI3 0x3838
> +#define MIPI_RX_CON3C_CSI3 0x383C
> +#define MIPI_RX_CON7C_CSI3 0x387C
> +#define MIPI_RX_CON80_CSI3 0x3880
> +#define MIPI_RX_CON84_CSI3 0x3884
> +#define MIPI_RX_CON88_CSI3 0x3888
> +#define MIPI_RX_CON8C_CSI3 0x388C
> +#define MIPI_RX_CON90_CSI3 0x3890
> +#define MIPI_RX_CON94_CSI3 0x3894
> +#define MIPI_RX_CON98_CSI3 0x3898
> +#define MIPI_RX_CONA0_CSI3 0x38A0
> +#define MIPI_RX_CONB0_CSI3 0x38B0
> +#define MIPI_RX_CONB4_CSI3 0x38B4
> +#define MIPI_RX_CONB8_CSI3 0x38B8
> +#define MIPI_RX_CONBC_CSI3 0x38BC
> +#define MIPI_RX_CONC0_CSI3 0x38C0
> +#define MIPI_RX_CONC4_CSI3 0x38C4
> +#define MIPI_RX_CONC8_CSI3 0x38C8
> +#define MIPI_RX_CONCC_CSI3 0x38CC
> +#define MIPI_RX_COND0_CSI3 0x38D0
> +#define SENINF4_CSI2_CTL 0x3A00
> +#define SENINF4_CSI2_LNRC_TIMING 0x3A04
> +#define SENINF4_CSI2_LNRD_TIMING 0x3A08
> +#define SENINF4_CSI2_DPCM 0x3A0C
> +#define SENINF4_CSI2_INT_EN 0x3A10
> +#define SENINF4_CSI2_INT_STATUS 0x3A14
> +#define SENINF4_CSI2_DGB_SEL 0x3A18
> +#define SENINF4_CSI2_DBG_PORT 0x3A1C
> +#define SENINF4_CSI2_SPARE0 0x3A20
> +#define SENINF4_CSI2_SPARE1 0x3A24
> +#define SENINF4_CSI2_LNRC_FSM 0x3A28
> +#define SENINF4_CSI2_LNRD_FSM 0x3A2C
> +#define SENINF4_CSI2_FRAME_LINE_NUM 0x3A30
> +#define SENINF4_CSI2_GENERIC_SHORT 0x3A34
> +#define SENINF4_CSI2_HSRX_DBG 0x3A38
> +#define SENINF4_CSI2_DI 0x3A3C
> +#define SENINF4_CSI2_HS_TRAIL 0x3A40
> +#define SENINF4_CSI2_DI_CTRL 0x3A44
> +#define SENINF4_CSI2_DETECT_CON1 0x3A4C
> +#define SENINF4_CSI2_DETECT_CON2 0x3A50
> +#define SENINF4_CSI2_DETECT_CON3 0x3A54
> +#define SENINF4_CSI2_RLR0_CON0 0x3A58
> +#define SENINF4_CSI2_RLR1_CON0 0x3A5C
> +#define SENINF4_CSI2_RLR2_CON0 0x3A60
> +#define SENINF4_CSI2_RLR_CON0 0x3A64
> +#define SENINF4_CSI2_MUX_CON 0x3A68
> +#define SENINF4_CSI2_DETECT_DBG0 0x3A6C
> +#define SENINF4_CSI2_DETECT_DBG1 0x3A70
> +#define SENINF4_CSI2_RESYNC_MERGE_CTL 0x3A74
> +#define SENINF4_CSI2_CTRL_TRIO_MUX 0x3A78
> +#define SENINF4_CSI2_CTRL_TRIO_CON 0x3A7C
> +#define SENINF4_FIX_ADDR_CPHY0_DBG 0x3A80
> +#define SENINF4_FIX_ADDR_CPHY1_DBG 0x3A84
> +#define SENINF4_FIX_ADDR_CPHY2_DBG 0x3A88
> +#define SENINF4_FIX_ADDR_DBG 0x3A8C
> +#define SENINF4_WIRE_STATE_DECODE_CPHY0_DBG0 0x3A90
> +#define SENINF4_WIRE_STATE_DECODE_CPHY0_DBG1 0x3A94
> +#define SENINF4_WIRE_STATE_DECODE_CPHY1_DBG0 0x3A98
> +#define SENINF4_WIRE_STATE_DECODE_CPHY1_DBG1 0x3A9C
> +#define SENINF4_WIRE_STATE_DECODE_CPHY2_DBG0 0x3AA0
> +#define SENINF4_WIRE_STATE_DECODE_CPHY2_DBG1 0x3AA4
> +#define SENINF4_SYNC_RESYNC_CTL 0x3AA8
> +#define SENINF4_POST_DETECT_CTL 0x3AAC
> +#define SENINF4_WIRE_STATE_DECODE_CONFIG 0x3AB0
> +#define SENINF4_CSI2_CPHY_LNRD_FSM 0x3AB4
> +#define SENINF4_FIX_ADDR_CPHY0_DBG0 0x3AB8
> +#define SENINF4_FIX_ADDR_CPHY0_DBG1 0x3ABC
> +#define SENINF4_FIX_ADDR_CPHY0_DBG2 0x3AC0
> +#define SENINF4_FIX_ADDR_CPHY1_DBG0 0x3AC4
> +#define SENINF4_FIX_ADDR_CPHY1_DBG1 0x3AC8
> +#define SENINF4_FIX_ADDR_CPHY1_DBG2 0x3ACC
> +#define SENINF4_FIX_ADDR_CPHY2_DBG0 0x3AD0
> +#define SENINF4_FIX_ADDR_CPHY2_DBG1 0x3AD4
> +#define SENINF4_FIX_ADDR_CPHY2_DBG2 0x3AD8
> +#define SENINF4_FIX_ADDR_DBG0 0x3ADC
> +#define SENINF4_FIX_ADDR_DBG1 0x3AE0
> +#define SENINF4_FIX_ADDR_DBG2 0x3AE4
> +#define SENINF4_CSI2_MODE 0x3AE8
> +#define SENINF4_CSI2_DI_EXT 0x3AF0
> +#define SENINF4_CSI2_DI_CTRL_EXT 0x3AF4
> +#define SENINF4_CSI2_CPHY_LOOPBACK 0x3AF8
> +#define SENINF4_CSI2_PROGSEQ_0 0x3B00
> +#define SENINF4_CSI2_PROGSEQ_1 0x3B04
> +#define SENINF4_CSI2_INT_EN_EXT 0x3B10
> +#define SENINF4_CSI2_INT_STATUS_EXT 0x3B14
> +#define SENINF4_CSI2_CPHY_FIX_POINT_RST 0x3B18
> +#define SENINF4_CSI2_RLR3_CON0 0x3B1C
> +#define SENINF4_CSI2_DPHY_SYNC 0x3B20
> +#define SENINF4_CSI2_DESKEW_SYNC 0x3B24
> +#define SENINF4_CSI2_DETECT_DBG2 0x3B28
> +#define SENINF4_FIX_ADDR_CPHY3_DBG0 0x3B30
> +#define SENINF4_FIX_ADDR_CPHY3_DBG1 0x3B34
> +#define SENINF4_FIX_ADDR_CPHY3_DBG2 0x3B38
> +#define SENINF4_CSI2_DI_EXT_2 0x3B3C
> +#define SENINF4_CSI2_DI_CTRL_EXT_2 0x3B40
> +#define SENINF4_WIRE_STATE_DECODE_CPHY3_DBG0 0x3B44
> +#define SENINF4_WIRE_STATE_DECODE_CPHY3_DBG1 0x3B48
> +#define SENINF4_MUX_CTRL 0x3D00
> +#define SENINF4_MUX_INTEN 0x3D04
> +#define SENINF4_MUX_INTSTA 0x3D08
> +#define SENINF4_MUX_SIZE 0x3D0C
> +#define SENINF4_MUX_DEBUG_1 0x3D10
> +#define SENINF4_MUX_DEBUG_2 0x3D14
> +#define SENINF4_MUX_DEBUG_3 0x3D18
> +#define SENINF4_MUX_DEBUG_4 0x3D1C
> +#define SENINF4_MUX_DEBUG_5 0x3D20
> +#define SENINF4_MUX_DEBUG_6 0x3D24
> +#define SENINF4_MUX_DEBUG_7 0x3D28
> +#define SENINF4_MUX_SPARE 0x3D2C
> +#define SENINF4_MUX_DATA 0x3D30
> +#define SENINF4_MUX_DATA_CNT 0x3D34
> +#define SENINF4_MUX_CROP 0x3D38
> +#define SENINF4_MUX_CTRL_EXT 0x3D3C
> +#define SENINF5_CTRL 0x4200
> +#define SENINF5_CTRL_EXT 0x4204
> +#define SENINF5_ASYNC_CTRL 0x4208
> +#define SENINF_TG5_PH_CNT 0x4600
> +#define SENINF_TG5_SEN_CK 0x4604
> +#define SENINF_TG5_TM_CTL 0x4608
> +#define SENINF_TG5_TM_SIZE 0x460C
> +#define SENINF_TG5_TM_CLK 0x4610
> +#define SENINF_TG5_TM_STP 0x4614
> +#define MIPI_RX_CON24_CSI4 0x4824
> +#define MIPI_RX_CON28_CSI4 0x4828
> +#define MIPI_RX_CON34_CSI4 0x4834
> +#define MIPI_RX_CON38_CSI4 0x4838
> +#define MIPI_RX_CON3C_CSI4 0x483C
> +#define MIPI_RX_CON7C_CSI4 0x487C
> +#define MIPI_RX_CON80_CSI4 0x4880
> +#define MIPI_RX_CON84_CSI4 0x4884
> +#define MIPI_RX_CON88_CSI4 0x4888
> +#define MIPI_RX_CON8C_CSI4 0x488C
> +#define MIPI_RX_CON90_CSI4 0x4890
> +#define MIPI_RX_CON94_CSI4 0x4894
> +#define MIPI_RX_CON98_CSI4 0x4898
> +#define MIPI_RX_CONA0_CSI4 0x48A0
> +#define MIPI_RX_CONB0_CSI4 0x48B0
> +#define MIPI_RX_CONB4_CSI4 0x48B4
> +#define MIPI_RX_CONB8_CSI4 0x48B8
> +#define MIPI_RX_CONBC_CSI4 0x48BC
> +#define MIPI_RX_CONC0_CSI4 0x48C0
> +#define MIPI_RX_CONC4_CSI4 0x48C4
> +#define MIPI_RX_CONC8_CSI4 0x48C8
> +#define MIPI_RX_CONCC_CSI4 0x48CC
> +#define MIPI_RX_COND0_CSI4 0x48D0
> +#define SENINF5_CSI2_CTL 0x4A00
> +#define SENINF5_CSI2_LNRC_TIMING 0x4A04
> +#define SENINF5_CSI2_LNRD_TIMING 0x4A08
> +#define SENINF5_CSI2_DPCM 0x4A0C
> +#define SENINF5_CSI2_INT_EN 0x4A10
> +#define SENINF5_CSI2_INT_STATUS 0x4A14
> +#define SENINF5_CSI2_DGB_SEL 0x4A18
> +#define SENINF5_CSI2_DBG_PORT 0x4A1C
> +#define SENINF5_CSI2_SPARE0 0x4A20
> +#define SENINF5_CSI2_SPARE1 0x4A24
> +#define SENINF5_CSI2_LNRC_FSM 0x4A28
> +#define SENINF5_CSI2_LNRD_FSM 0x4A2C
> +#define SENINF5_CSI2_FRAME_LINE_NUM 0x4A30
> +#define SENINF5_CSI2_GENERIC_SHORT 0x4A34
> +#define SENINF5_CSI2_HSRX_DBG 0x4A38
> +#define SENINF5_CSI2_DI 0x4A3C
> +#define SENINF5_CSI2_HS_TRAIL 0x4A40
> +#define SENINF5_CSI2_DI_CTRL 0x4A44
> +#define SENINF5_CSI2_DETECT_CON1 0x4A4C
> +#define SENINF5_CSI2_DETECT_CON2 0x4A50
> +#define SENINF5_CSI2_DETECT_CON3 0x4A54
> +#define SENINF5_CSI2_RLR0_CON0 0x4A58
> +#define SENINF5_CSI2_RLR1_CON0 0x4A5C
> +#define SENINF5_CSI2_RLR2_CON0 0x4A60
> +#define SENINF5_CSI2_RLR_CON0 0x4A64
> +#define SENINF5_CSI2_MUX_CON 0x4A68
> +#define SENINF5_CSI2_DETECT_DBG0 0x4A6C
> +#define SENINF5_CSI2_DETECT_DBG1 0x4A70
> +#define SENINF5_CSI2_RESYNC_MERGE_CTL 0x4A74
> +#define SENINF5_CSI2_CTRL_TRIO_MUX 0x4A78
> +#define SENINF5_CSI2_CTRL_TRIO_CON 0x4A7C
> +#define SENINF5_FIX_ADDR_CPHY0_DBG 0x4A80
> +#define SENINF5_FIX_ADDR_CPHY1_DBG 0x4A84
> +#define SENINF5_FIX_ADDR_CPHY2_DBG 0x4A88
> +#define SENINF5_FIX_ADDR_DBG 0x4A8C
> +#define SENINF5_WIRE_STATE_DECODE_CPHY0_DBG0 0x4A90
> +#define SENINF5_WIRE_STATE_DECODE_CPHY0_DBG1 0x4A94
> +#define SENINF5_WIRE_STATE_DECODE_CPHY1_DBG0 0x4A98
> +#define SENINF5_WIRE_STATE_DECODE_CPHY1_DBG1 0x4A9C
> +#define SENINF5_WIRE_STATE_DECODE_CPHY2_DBG0 0x4AA0
> +#define SENINF5_WIRE_STATE_DECODE_CPHY2_DBG1 0x4AA4
> +#define SENINF5_SYNC_RESYNC_CTL 0x4AA8
> +#define SENINF5_POST_DETECT_CTL 0x4AAC
> +#define SENINF5_WIRE_STATE_DECODE_CONFIG 0x4AB0
> +#define SENINF5_CSI2_CPHY_LNRD_FSM 0x4AB4
> +#define SENINF5_FIX_ADDR_CPHY0_DBG0 0x4AB8
> +#define SENINF5_FIX_ADDR_CPHY0_DBG1 0x4ABC
> +#define SENINF5_FIX_ADDR_CPHY0_DBG2 0x4AC0
> +#define SENINF5_FIX_ADDR_CPHY1_DBG0 0x4AC4
> +#define SENINF5_FIX_ADDR_CPHY1_DBG1 0x4AC8
> +#define SENINF5_FIX_ADDR_CPHY1_DBG2 0x4ACC
> +#define SENINF5_FIX_ADDR_CPHY2_DBG0 0x4AD0
> +#define SENINF5_FIX_ADDR_CPHY2_DBG1 0x4AD4
> +#define SENINF5_FIX_ADDR_CPHY2_DBG2 0x4AD8
> +#define SENINF5_FIX_ADDR_DBG0 0x4ADC
> +#define SENINF5_FIX_ADDR_DBG1 0x4AE0
> +#define SENINF5_FIX_ADDR_DBG2 0x4AE4
> +#define SENINF5_CSI2_MODE 0x4AE8
> +#define SENINF5_CSI2_DI_EXT 0x4AF0
> +#define SENINF5_CSI2_DI_CTRL_EXT 0x4AF4
> +#define SENINF5_CSI2_CPHY_LOOPBACK 0x4AF8
> +#define SENINF5_CSI2_PROGSEQ_0 0x4B00
> +#define SENINF5_CSI2_PROGSEQ_1 0x4B04
> +#define SENINF5_CSI2_INT_EN_EXT 0x4B10
> +#define SENINF5_CSI2_INT_STATUS_EXT 0x4B14
> +#define SENINF5_CSI2_CPHY_FIX_POINT_RST 0x4B18
> +#define SENINF5_CSI2_RLR3_CON0 0x4B1C
> +#define SENINF5_CSI2_DPHY_SYNC 0x4B20
> +#define SENINF5_CSI2_DESKEW_SYNC 0x4B24
> +#define SENINF5_CSI2_DETECT_DBG2 0x4B28
> +#define SENINF5_FIX_ADDR_CPHY3_DBG0 0x4B30
> +#define SENINF5_FIX_ADDR_CPHY3_DBG1 0x4B34
> +#define SENINF5_FIX_ADDR_CPHY3_DBG2 0x4B38
> +#define SENINF5_CSI2_DI_EXT_2 0x4B3C
> +#define SENINF5_CSI2_DI_CTRL_EXT_2 0x4B40
> +#define SENINF5_WIRE_STATE_DECODE_CPHY3_DBG0 0x4B44
> +#define SENINF5_WIRE_STATE_DECODE_CPHY3_DBG1 0x4B48
> +#define SENINF5_MUX_CTRL 0x4D00
> +#define SENINF5_MUX_INTEN 0x4D04
> +#define SENINF5_MUX_INTSTA 0x4D08
> +#define SENINF5_MUX_SIZE 0x4D0C
> +#define SENINF5_MUX_DEBUG_1 0x4D10
> +#define SENINF5_MUX_DEBUG_2 0x4D14
> +#define SENINF5_MUX_DEBUG_3 0x4D18
> +#define SENINF5_MUX_DEBUG_4 0x4D1C
> +#define SENINF5_MUX_DEBUG_5 0x4D20
> +#define SENINF5_MUX_DEBUG_6 0x4D24
> +#define SENINF5_MUX_DEBUG_7 0x4D28
> +#define SENINF5_MUX_SPARE 0x4D2C
> +#define SENINF5_MUX_DATA 0x4D30
> +#define SENINF5_MUX_DATA_CNT 0x4D34
> +#define SENINF5_MUX_CROP 0x4D38
> +#define SENINF5_MUX_CTRL_EXT 0x4D3C
> +#define SENINF6_MUX_CTRL 0x5D00
> +#define SENINF6_MUX_INTEN 0x5D04
> +#define SENINF6_MUX_INTSTA 0x5D08
> +#define SENINF6_MUX_SIZE 0x5D0C
> +#define SENINF6_MUX_DEBUG_1 0x5D10
> +#define SENINF6_MUX_DEBUG_2 0x5D14
> +#define SENINF6_MUX_DEBUG_3 0x5D18
> +#define SENINF6_MUX_DEBUG_4 0x5D1C
> +#define SENINF6_MUX_DEBUG_5 0x5D20
> +#define SENINF6_MUX_DEBUG_6 0x5D24
> +#define SENINF6_MUX_DEBUG_7 0x5D28
> +#define SENINF6_MUX_SPARE 0x5D2C
> +#define SENINF6_MUX_DATA 0x5D30
> +#define SENINF6_MUX_DATA_CNT 0x5D34
> +#define SENINF6_MUX_CROP 0x5D38
> +#define SENINF6_MUX_CTRL_EXT 0x5D3C
> +#define SENINF7_MUX_CTRL 0x6D00
> +#define SENINF7_MUX_INTEN 0x6D04
> +#define SENINF7_MUX_INTSTA 0x6D08
> +#define SENINF7_MUX_SIZE 0x6D0C
> +#define SENINF7_MUX_DEBUG_1 0x6D10
> +#define SENINF7_MUX_DEBUG_2 0x6D14
> +#define SENINF7_MUX_DEBUG_3 0x6D18
> +#define SENINF7_MUX_DEBUG_4 0x6D1C
> +#define SENINF7_MUX_DEBUG_5 0x6D20
> +#define SENINF7_MUX_DEBUG_6 0x6D24
> +#define SENINF7_MUX_DEBUG_7 0x6D28
> +#define SENINF7_MUX_SPARE 0x6D2C
> +#define SENINF7_MUX_DATA 0x6D30
> +#define SENINF7_MUX_DATA_CNT 0x6D34
> +#define SENINF7_MUX_CROP 0x6D38
> +#define SENINF7_MUX_CTRL_EXT 0x6D3C
> +#define SENINF8_MUX_CTRL 0x7D00
> +#define SENINF8_MUX_INTEN 0x7D04
> +#define SENINF8_MUX_INTSTA 0x7D08
> +#define SENINF8_MUX_SIZE 0x7D0C
> +#define SENINF8_MUX_DEBUG_1 0x7D10
> +#define SENINF8_MUX_DEBUG_2 0x7D14
> +#define SENINF8_MUX_DEBUG_3 0x7D18
> +#define SENINF8_MUX_DEBUG_4 0x7D1C
> +#define SENINF8_MUX_DEBUG_5 0x7D20
> +#define SENINF8_MUX_DEBUG_6 0x7D24
> +#define SENINF8_MUX_DEBUG_7 0x7D28
> +#define SENINF8_MUX_SPARE 0x7D2C
> +#define SENINF8_MUX_DATA 0x7D30
> +#define SENINF8_MUX_DATA_CNT 0x7D34
> +#define SENINF8_MUX_CROP 0x7D38
> +#define SENINF8_MUX_CTRL_EXT 0x7D3C
> +
> +#endif /* _SENINF_REG_H_ */
> --
> 2.18.0
>
--
Kind regards,
Sakari Ailus
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [RFC PATCH V4 2/4] media: platform: Add Mediatek sensor interface driver KConfig
From: Sakari Ailus @ 2019-09-18 8:16 UTC (permalink / raw)
To: Louis Kuo
Cc: devicetree, Sean.Cheng, laurent.pinchart+renesas, Rynn.Wu,
christie.yu, srv_heupstream, Jerry-ch.Chen, tfiga, keiichiw,
jungo.lin, sj.huang, yuzhao, hans.verkuil, zwisler, frederic.chen,
matthias.bgg, linux-mediatek, mchehab, linux-arm-kernel,
linux-media
In-Reply-To: <20190915065004.20257-3-louis.kuo@mediatek.com>
On Sun, Sep 15, 2019 at 02:50:02PM +0800, Louis Kuo wrote:
> This patch adds KConfig for sensor interface driver. Sensor interface
> driver
> is a MIPI-CSI2 host driver, namely, a HW camera interface controller.
> It support a widely adopted, simple, high-speed protocol primarily
> intended
> for point-to-point image and video transmission between cameras and host
> devices.
>
> Signed-off-by: Louis Kuo <louis.kuo@mediatek.com>
> ---
> drivers/media/platform/mtk-isp/Kconfig | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
> create mode 100644 drivers/media/platform/mtk-isp/Kconfig
>
> diff --git a/drivers/media/platform/mtk-isp/Kconfig b/drivers/media/platform/mtk-isp/Kconfig
> new file mode 100644
> index 000000000000..bc7fd01808b3
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/Kconfig
> @@ -0,0 +1,17 @@
> +config MTK_SENINF
> + bool "Mediatek mipi csi2 driver"
Would there be issues in building this as a module?
> + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
> + depends on MEDIA_CAMERA_SUPPORT
> + select V4L2_FWNODE
> +
> + default n
> + help
> + This driver provides a mipi-csi2 host driver used as a
> + interface to connect camera with Mediatek's
> + MT8183 SOCs. It is able to handle multiple cameras
> + at the same time.
> +
> + Choose y if you want to use Mediatek SoCs to create image
> + capture application such as video recording and still image
> + capture.
> +
> --
> 2.18.0
>
--
Sakari Ailus
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] hwmon: (aspeed-pwm-tacho) Use devm_platform_ioremap_resource() in aspeed_pwm_tacho_probe()
From: Markus Elfring @ 2019-09-18 8:20 UTC (permalink / raw)
To: linux-hwmon, linux-arm-kernel, linux-aspeed, Andrew Jeffery,
Günter Röck, Jean Delvare, Joel Stanley
Cc: Bartosz Golaszewski, kernel-janitors, LKML, Himanshu Jha
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Wed, 18 Sep 2019 10:12:31 +0200
Simplify this function implementation by using a known wrapper function.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/hwmon/aspeed-pwm-tacho.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
index 40c489be62ea..33fb54845bf6 100644
--- a/drivers/hwmon/aspeed-pwm-tacho.c
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -891,17 +891,12 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
struct device_node *np, *child;
struct aspeed_pwm_tacho_data *priv;
void __iomem *regs;
- struct resource *res;
struct device *hwmon;
struct clk *clk;
int ret;
np = dev->of_node;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
- regs = devm_ioremap_resource(dev, res);
+ regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v6 0/4] Add HDMI jack support on RK3288
From: Cheng-Yi Chiang @ 2019-09-18 8:24 UTC (permalink / raw)
To: linux-kernel
Cc: alsa-devel, Heiko Stuebner, Neil Armstrong, David Airlie,
dri-devel, Liam Girdwood, Hans Verkuil, Andrzej Hajda,
Laurent Pinchart, Jerome Brunet, Takashi Iwai, linux-rockchip,
dgreid, Cheng-Yi Chiang, tzungbi, Jonas Karlman, Russell King,
Mark Brown, Jaroslav Kysela, linux-arm-kernel, Jernej Skrabec,
dianders, Daniel Vetter
This patch series supports HDMI jack reporting on RK3288, which uses
DRM dw-hdmi driver and hdmi-codec codec driver.
The previous discussion about reporting jack status using hdmi-notifier
and drm_audio_component is at
https://lore.kernel.org/patchwork/patch/1083027/
The new approach is to use a callback mechanism that is
specific to hdmi-codec.
The dependent change on hdmi-codec.c
https://patchwork.kernel.org/patch/11047447
has been picked up by Mark Brown in ASoC tree for-5.4 branch.
Changes from v5 to v6:
1. Remove the patch for sound/soc/codecs/hdmi-codec.c because it is accepted.
2. Rebase the rest of patches based on drm-misc-next tree.
Cheng-Yi Chiang (4):
drm: bridge: dw-hdmi: Report connector status using callback
drm: dw-hdmi-i2s: Use fixed id for codec device
ASoC: rockchip_max98090: Add dai_link for HDMI
ASoC: rockchip_max98090: Add HDMI jack support
.../drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 13 +-
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 41 ++++++-
include/drm/bridge/dw_hdmi.h | 4 +
sound/soc/rockchip/Kconfig | 3 +-
sound/soc/rockchip/rk3288_hdmi_analog.c | 3 +-
sound/soc/rockchip/rockchip_max98090.c | 116 ++++++++++++++----
6 files changed, 153 insertions(+), 27 deletions(-)
--
2.23.0.237.gc6a4ce50a0-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v6 1/4] drm: bridge: dw-hdmi: Report connector status using callback
From: Cheng-Yi Chiang @ 2019-09-18 8:24 UTC (permalink / raw)
To: linux-kernel
Cc: alsa-devel, Heiko Stuebner, Neil Armstrong, David Airlie,
dri-devel, Liam Girdwood, Hans Verkuil, Andrzej Hajda,
Laurent Pinchart, Jerome Brunet, Takashi Iwai, linux-rockchip,
dgreid, Cheng-Yi Chiang, tzungbi, Jonas Karlman, Russell King,
Mark Brown, Jaroslav Kysela, linux-arm-kernel, Jernej Skrabec,
dianders, Daniel Vetter
In-Reply-To: <20190918082500.209281-1-cychiang@chromium.org>
Allow codec driver register callback function for plug event.
The callback registration flow:
dw-hdmi <--- hw-hdmi-i2s-audio <--- hdmi-codec
dw-hdmi-i2s-audio implements hook_plugged_cb op
so codec driver can register the callback.
dw-hdmi exports a function dw_hdmi_set_plugged_cb so platform device
can register the callback.
When connector plug/unplug event happens, report this event using the
callback.
Make sure that audio and drm are using the single source of truth for
connector status.
Signed-off-by: Cheng-Yi Chiang <cychiang@chromium.org>
---
.../drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 11 +++++
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 41 ++++++++++++++++++-
include/drm/bridge/dw_hdmi.h | 4 ++
3 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
index 20f4f92dd866..d7e65c869415 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
@@ -160,12 +160,23 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
return -EINVAL;
}
+static int dw_hdmi_i2s_hook_plugged_cb(struct device *dev, void *data,
+ hdmi_codec_plugged_cb fn,
+ struct device *codec_dev)
+{
+ struct dw_hdmi_i2s_audio_data *audio = data;
+ struct dw_hdmi *hdmi = audio->hdmi;
+
+ return dw_hdmi_set_plugged_cb(hdmi, fn, codec_dev);
+}
+
static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
.hw_params = dw_hdmi_i2s_hw_params,
.audio_startup = dw_hdmi_i2s_audio_startup,
.audio_shutdown = dw_hdmi_i2s_audio_shutdown,
.get_eld = dw_hdmi_i2s_get_eld,
.get_dai_id = dw_hdmi_i2s_get_dai_id,
+ .hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb,
};
static int snd_dw_hdmi_probe(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index aa7efd4da1c8..7ffe8ed675ff 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -193,6 +193,10 @@ struct dw_hdmi {
struct mutex cec_notifier_mutex;
struct cec_notifier *cec_notifier;
+
+ hdmi_codec_plugged_cb plugged_cb;
+ struct device *codec_dev;
+ enum drm_connector_status last_connector_result;
};
#define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -217,6 +221,28 @@ static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
return val;
}
+static void handle_plugged_change(struct dw_hdmi *hdmi, bool plugged)
+{
+ if (hdmi->plugged_cb && hdmi->codec_dev)
+ hdmi->plugged_cb(hdmi->codec_dev, plugged);
+}
+
+int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
+ struct device *codec_dev)
+{
+ bool plugged;
+
+ mutex_lock(&hdmi->mutex);
+ hdmi->plugged_cb = fn;
+ hdmi->codec_dev = codec_dev;
+ plugged = hdmi->last_connector_result == connector_status_connected;
+ handle_plugged_change(hdmi, plugged);
+ mutex_unlock(&hdmi->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_plugged_cb);
+
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{
regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
@@ -2183,6 +2209,7 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
+ enum drm_connector_status result;
mutex_lock(&hdmi->mutex);
hdmi->force = DRM_FORCE_UNSPECIFIED;
@@ -2190,7 +2217,18 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
dw_hdmi_update_phy_mask(hdmi);
mutex_unlock(&hdmi->mutex);
- return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+ result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+
+ mutex_lock(&hdmi->mutex);
+ if (result != hdmi->last_connector_result) {
+ dev_dbg(hdmi->dev, "read_hpd result: %d", result);
+ handle_plugged_change(hdmi,
+ result == connector_status_connected);
+ hdmi->last_connector_result = result;
+ }
+ mutex_unlock(&hdmi->mutex);
+
+ return result;
}
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -2641,6 +2679,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
hdmi->rxsense = true;
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
hdmi->mc_clkdis = 0x7f;
+ hdmi->last_connector_result = connector_status_disconnected;
mutex_init(&hdmi->mutex);
mutex_init(&hdmi->audio_mutex);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 4b3e863c4f8a..45a05e97e78a 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -6,6 +6,8 @@
#ifndef __DW_HDMI__
#define __DW_HDMI__
+#include <sound/hdmi-codec.h>
+
struct drm_connector;
struct drm_display_mode;
struct drm_encoder;
@@ -154,6 +156,8 @@ void dw_hdmi_resume(struct dw_hdmi *hdmi);
void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
+int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
+ struct device *codec_dev);
void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt);
void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status);
--
2.23.0.237.gc6a4ce50a0-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v6 2/4] drm: dw-hdmi-i2s: Use fixed id for codec device
From: Cheng-Yi Chiang @ 2019-09-18 8:24 UTC (permalink / raw)
To: linux-kernel
Cc: alsa-devel, Heiko Stuebner, Neil Armstrong, David Airlie,
dri-devel, Liam Girdwood, Hans Verkuil, Andrzej Hajda,
Laurent Pinchart, Jerome Brunet, Takashi Iwai, linux-rockchip,
dgreid, Cheng-Yi Chiang, tzungbi, Jonas Karlman, Russell King,
Mark Brown, Jaroslav Kysela, linux-arm-kernel, Jernej Skrabec,
dianders, Daniel Vetter
In-Reply-To: <20190918082500.209281-1-cychiang@chromium.org>
The problem of using auto ID is that the device name will be like
hdmi-audio-codec.<id number>.auto.
The number might be changed when there are other platform devices being
created before hdmi-audio-codec device.
Use a fixed name so machine driver can set codec name on the DAI link.
Using the fixed name should be fine because there will only be one
hdmi-audio-codec device.
Fix the codec name in rockchip rk3288_hdmi_analog machine driver.
Signed-off-by: Cheng-Yi Chiang <cychiang@chromium.org>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 2 +-
sound/soc/rockchip/rk3288_hdmi_analog.c | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
index d7e65c869415..86bd482b9f94 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
@@ -193,7 +193,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev)
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo.parent = pdev->dev.parent;
- pdevinfo.id = PLATFORM_DEVID_AUTO;
+ pdevinfo.id = PLATFORM_DEVID_NONE;
pdevinfo.name = HDMI_CODEC_DRV_NAME;
pdevinfo.data = &pdata;
pdevinfo.size_data = sizeof(pdata);
diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c
index 767700c34ee2..8286025a8747 100644
--- a/sound/soc/rockchip/rk3288_hdmi_analog.c
+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c
@@ -15,6 +15,7 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
+#include <sound/hdmi-codec.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -142,7 +143,7 @@ static const struct snd_soc_ops rk_ops = {
SND_SOC_DAILINK_DEFS(audio,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, NULL),
- COMP_CODEC("hdmi-audio-codec.2.auto", "i2s-hifi")),
+ COMP_CODEC(HDMI_CODEC_DRV_NAME, "i2s-hifi")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
static struct snd_soc_dai_link rk_dailink = {
--
2.23.0.237.gc6a4ce50a0-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v6 3/4] ASoC: rockchip_max98090: Add dai_link for HDMI
From: Cheng-Yi Chiang @ 2019-09-18 8:24 UTC (permalink / raw)
To: linux-kernel
Cc: alsa-devel, Heiko Stuebner, Neil Armstrong, David Airlie,
dri-devel, Liam Girdwood, Hans Verkuil, Andrzej Hajda,
Laurent Pinchart, Jerome Brunet, Takashi Iwai, linux-rockchip,
dgreid, Cheng-Yi Chiang, tzungbi, Jonas Karlman, Russell King,
Mark Brown, Jaroslav Kysela, linux-arm-kernel, Jernej Skrabec,
dianders, Daniel Vetter
In-Reply-To: <20190918082500.209281-1-cychiang@chromium.org>
Use two dai_links. One for HDMI and one for max98090.
With this setup, audio can play to speaker and HDMI selectively.
Signed-off-by: Cheng-Yi Chiang <cychiang@chromium.org>
---
sound/soc/rockchip/rockchip_max98090.c | 96 ++++++++++++++++++++------
1 file changed, 73 insertions(+), 23 deletions(-)
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index c5fc24675a33..c82948e383da 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -11,6 +11,7 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
+#include <sound/hdmi-codec.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -41,6 +42,7 @@ static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_LINE("HDMI", NULL),
};
static const struct snd_soc_dapm_route rk_audio_map[] = {
@@ -52,6 +54,7 @@ static const struct snd_soc_dapm_route rk_audio_map[] = {
{"Headphone", NULL, "HPR"},
{"Speaker", NULL, "SPKL"},
{"Speaker", NULL, "SPKR"},
+ {"HDMI", NULL, "TX"},
};
static const struct snd_kcontrol_new rk_mc_controls[] = {
@@ -59,6 +62,7 @@ static const struct snd_kcontrol_new rk_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("HDMI"),
};
static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
@@ -92,38 +96,63 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
SND_SOC_CLOCK_OUT);
- if (ret < 0) {
- dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
+ if (ret) {
+ dev_err(cpu_dai->dev, "Can't set cpu dai clock %d\n", ret);
return ret;
}
+ /* HDMI codec dai does not need to set sysclk. */
+ if (!strcmp(rtd->dai_link->name, "HDMI"))
+ return 0;
+
ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
+ if (ret) {
+ dev_err(codec_dai->dev, "Can't set codec dai clock %d\n", ret);
return ret;
}
- return ret;
+ return 0;
}
static const struct snd_soc_ops rk_aif1_ops = {
.hw_params = rk_aif1_hw_params,
};
-SND_SOC_DAILINK_DEFS(hifi,
+SND_SOC_DAILINK_DEFS(analog,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
-static struct snd_soc_dai_link rk_dailink = {
- .name = "max98090",
- .stream_name = "Audio",
- .ops = &rk_aif1_ops,
- /* set max98090 as slave */
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
- SND_SOC_DAILINK_REG(hifi),
+SND_SOC_DAILINK_DEFS(hdmi,
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC(HDMI_CODEC_DRV_NAME, "i2s-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+enum {
+ DAILINK_MAX98090,
+ DAILINK_HDMI,
+};
+
+/* max98090 and HDMI codec dai_link */
+static struct snd_soc_dai_link rk_dailinks[] = {
+ [DAILINK_MAX98090] = {
+ .name = "max98090",
+ .stream_name = "Analog",
+ .ops = &rk_aif1_ops,
+ /* set max98090 as slave */
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAILINK_REG(analog),
+ },
+ [DAILINK_HDMI] = {
+ .name = "HDMI",
+ .stream_name = "HDMI",
+ .ops = &rk_aif1_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAILINK_REG(hdmi),
+ }
};
static int rk_98090_headset_init(struct snd_soc_component *component);
@@ -136,8 +165,8 @@ static struct snd_soc_aux_dev rk_98090_headset_dev = {
static struct snd_soc_card snd_soc_card_rk = {
.name = "ROCKCHIP-I2S",
.owner = THIS_MODULE,
- .dai_link = &rk_dailink,
- .num_links = 1,
+ .dai_link = rk_dailinks,
+ .num_links = ARRAY_SIZE(rk_dailinks),
.aux_dev = &rk_98090_headset_dev,
.num_aux_devs = 1,
.dapm_widgets = rk_dapm_widgets,
@@ -173,27 +202,48 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
int ret = 0;
struct snd_soc_card *card = &snd_soc_card_rk;
struct device_node *np = pdev->dev.of_node;
+ struct device_node *np_analog;
+ struct device_node *np_cpu;
+ struct of_phandle_args args;
/* register the soc card */
card->dev = &pdev->dev;
- rk_dailink.codecs->of_node = of_parse_phandle(np,
- "rockchip,audio-codec", 0);
- if (!rk_dailink.codecs->of_node) {
+ np_analog = of_parse_phandle(np, "rockchip,audio-codec", 0);
+ if (!np_analog) {
dev_err(&pdev->dev,
"Property 'rockchip,audio-codec' missing or invalid\n");
return -EINVAL;
}
+ rk_dailinks[DAILINK_MAX98090].codecs->of_node = np_analog;
+
+ ret = of_parse_phandle_with_fixed_args(np, "rockchip,audio-codec",
+ 0, 0, &args);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Unable to parse property 'rockchip,audio-codec'\n");
+ return ret;
+ }
+
+ ret = snd_soc_get_dai_name(
+ &args, &rk_dailinks[DAILINK_MAX98090].codecs->dai_name);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to get codec dai_name\n");
+ return ret;
+ }
+
+ np_cpu = of_parse_phandle(np, "rockchip,i2s-controller", 0);
- rk_dailink.cpus->of_node = of_parse_phandle(np,
- "rockchip,i2s-controller", 0);
- if (!rk_dailink.cpus->of_node) {
+ if (!np_cpu) {
dev_err(&pdev->dev,
"Property 'rockchip,i2s-controller' missing or invalid\n");
return -EINVAL;
}
- rk_dailink.platforms->of_node = rk_dailink.cpus->of_node;
+ rk_dailinks[DAILINK_MAX98090].cpus->of_node = np_cpu;
+ rk_dailinks[DAILINK_MAX98090].platforms->of_node = np_cpu;
+ rk_dailinks[DAILINK_HDMI].cpus->of_node = np_cpu;
+ rk_dailinks[DAILINK_HDMI].platforms->of_node = np_cpu;
rk_98090_headset_dev.codec_of_node = of_parse_phandle(np,
"rockchip,headset-codec", 0);
--
2.23.0.237.gc6a4ce50a0-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [RFC PATCH v3 4/6] psci: Add hvc call service for ptp_kvm.
From: Paolo Bonzini @ 2019-09-18 8:25 UTC (permalink / raw)
To: Jianyong Wu, netdev, yangbo.lu, john.stultz, tglx,
sean.j.christopherson, maz, richardcochran, Mark.Rutland,
Will.Deacon, suzuki.poulose
Cc: justin.he, kvm, Steve.Capper, linux-kernel, Kaly.Xin, nd,
linux-arm-kernel
In-Reply-To: <20190918080716.64242-5-jianyong.wu@arm.com>
On 18/09/19 10:07, Jianyong Wu wrote:
> + case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> + getnstimeofday(ts);
This is not Y2038-safe. Please use ktime_get_real_ts64 instead, and
split the 64-bit seconds value between val[0] and val[1].
However, it seems to me that the new function is not needed and you can
just use ktime_get_snapshot. You'll get the time in
systime_snapshot->real and the cycles value in systime_snapshot->cycles.
> + get_current_counterval(&sc);
> + val[0] = ts->tv_sec;
> + val[1] = ts->tv_nsec;
> + val[2] = sc.cycles;
> + val[3] = 0;
> + break;
This should return a guest-cycles value. If the cycles values always
the same between the host and the guest on ARM, then okay. If not, you
have to apply whatever offset exists.
Thanks,
Paolo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ 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