Merge "power: pm8921-bms: api for battery insertion/removal"
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 2214f12..755d817 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -72,6 +72,8 @@
- misc. LCD driver documentation (cfag12864b, ks0108).
basic_profiling.txt
- basic instructions for those who wants to profile Linux kernel.
+bif-framework.txt
+ - information about MIPI-BIF support in the Linux kernel.
binfmt_misc.txt
- info on the kernel support for extra binary formats.
blackfin/
diff --git a/Documentation/bif-framework.txt b/Documentation/bif-framework.txt
new file mode 100644
index 0000000..3ba500d
--- /dev/null
+++ b/Documentation/bif-framework.txt
@@ -0,0 +1,508 @@
+Introduction
+============
+
+BIF (Battery Interface) is a MIPI (Mobile Industry Processor Interface)
+Alliance specification for a serial interface between a host device and a
+battery pack. It provides a means to handle smart battery packs which can
+communicate over BIF as well as low cost battery packs which provide no
+serial communication interface.
+
+The BIF bus supports 1 master and up to 256 slaves. It supports data rates
+up to 250 kbps. The master is in charge of initiating all bus
+communications. Slaves may only respond asynchronously when they need to
+signal the master that they have an interrupt pending and when the bus is
+configured for interrupt mode.
+
+The BIF framework consists of a core into which BIF controller drivers
+register. At runtime, consumers are notified of various events (e.g. battery
+insertion and battery removal) via a notifier. Various framework functions are
+available for consumers to read and write slave registers as well as to send
+arbitrary BIF commands on the bus.
+
+Hardware description
+====================
+
+The BIF bus is a 1-wire wired-or interface. The bus signal is referred to as
+the battery communication line (BCL). The BCL is pulled high by a resistor on
+the host side and is driven low when the master or one of the slaves is
+communicating. Additionally, there is a pull down resistor in the battery
+pack which is used to identify whether or not the battery pack has BIF slaves.
+Battery removal detection is achieved by comparing the analog voltage of the BCL
+when idle to the host side reference voltage. If these voltages are within a
+certain threshold, then a battery pack is not present.
+
+Slaves are addressed on the BIF bus using an 8-bit device address (DEV_ADR).
+Notably, it is possible for no slaves to have defined DEV_ADR. In this case,
+slave addressing is achieved via the always present unique ID (UID). The UID
+of a slave is 80 bits long and guaranteed to be globally unique. A UID search
+algorithm can be followed in order determine the UID of all slaves on the bus.
+
+BIF slaves come in two varieties: primary and secondary. A single primary
+slave may be present on the battery pack and a single primary slave may be
+present on the host. A battery pack primary slave has DEV_ADR=0x01. The
+DEV_ADR of a host primary slave is set by the manufacturer. A given primary
+slave contains a list of the UIDs of all secondary slaves in the same
+subsystem. This provides a fast mechanism to determine the address of all
+slaves without having to resort to the lengthy UID search algorithm.
+
+Each slave has a 64 kB address space. Part of this address space consists of
+generic DDB L1 and L2 data structures at known addresses. This allows for
+runtime discovery of supported battery properties and functions of a given
+smart battery pack.
+
+System Diagram:
+ +-------------------------------+ +---------------------------------+
+ | Host | | Smart Battery Pack |
+ | | | |
+ | Vbat-<+>-------<+>----------------------------+ |
+ | | | | |
+ | +--------------+ | | +--------------+ | |
+ | | Master BIF<+>-+---------<+>--BCL--<+>------+-<+>BIF Primary | | |
+ | | | | | | | | Slave | | |
+ | +--------------+ | | | | +--------------+ | |
+ | | | | | | |
+ | + - - - - - - -+ | | | | + - - - - - - -+ | |
+ | | Primary BIF<+>-+ | | +-<+>BIF Secondary| | |
+ | | Slave | | | | | | Slave | | |
+ | +- - - - - - - + | | | | +-- - - - - - -+ | |
+ | | | | | | |
+ | + - - - - - - -+ | | | | + - - - - - - -+ | |
+ | |Secondary BIF<+>-+ | | +-<+>BIF Secondary| | |
+ | |Slave | | | | | | Slave | | |
+ | +- - - - - - - + | | | | +-- - - - - - -+ | |
+ | / | | / | |
+ | Vref \ Rpu | | Rid \ ---- |
+ | ___ / | | / Battery -- |
+ | | \ | | \ Cell ---- |
+ | +-------+ | | | -- |
+ | | | | | |
+ | GND-<+>-------<+>------+---------------------+ |
+ | | | |
+ +-------------------------------+ +---------------------------------+
+
+An overview of BIF is available at:
+http://mipi.org/specifications/battery-interface
+
+Software description
+====================
+
+A given BIF hardware interface driver registers as a BIF controller in the
+BIF framework during its probe function. The controller specifies a set of
+callback functions which are used by the BIF framework to initiate bus
+transactions (e.g. register read, register write, wait for slave interrupt)
+and to configure the bus. The framework exposes a small API to controllers
+which is used to notify the framework about asynchronous events such as
+battery pack insertion/removal and slave interrupts.
+
+A given BIF consumer is linked to a BIF controller by specifying a property
+in the consumer's device tree node which takes as its value the phandle of
+the BIF controller's device tree node.
+
+A consumer driver calls a get function during its probe function with its
+device pointer in order to get a handle to the BIF controller if it has probed.
+If it hasn't, then ERR_PTR(-EPROBE_DEFER) is returned. The controller handle
+can be used directly by the consumer to issue raw bus transactions if needed.
+The controller handle can then be used to query which slaves are currently
+present on the bus, if any. Handles to these slaves may be used by a consumer
+driver in high level framework APIs such as register read and register write
+which are slave oriented. All BIF framework API functions are synchronous,
+blocking, and can sleep.
+
+Consumer drivers may also register a notifier function which is called when
+certain bus activities occur such as battery pack insertion and removal.
+Additionally, consumer drivers may register a notifier function which is called
+when a specified slave interrupt fires.
+
+The framework maintains several linked-lists. One list contains all controllers
+that have been registered. A second list contains all slaves that have been
+seen since the system booted as well as a flag to indicate if they are currently
+present or not. This scheme is used to avoid issues with slave handles existing
+after a slave is removed and also so that function and object values do not have
+to be searched when a slave is reinserted in the system since slaves are
+globally unique and these features are read-only. Two further lists are
+maintained inside slave device structures which contain BIF functions and
+objects found in the slave. API functions are provided so that consumers can
+find functions supported by slaves.
+
+Design
+======
+
+Design Goals:
+One major goal of the BIF framework is to provide a uniform API for BIF
+consumers to communicate with battery packs. This ensures that consumers are
+unaffected by changes in the controller driver which actually interfaces with
+the BCL at a hardware level.
+
+Another goal of the framework is to ensure the BIF bus can be shared between
+multiple consumers in a simple and functionally correct way. Locking is used
+inside of the framework to provide mutual exclusion on the bus.
+
+The framework also exposes features that almost all consumers will need, such
+as BIF slave identification and BIF function enumeration within a given slave.
+
+The framework allows consumers to issue very specific bus commands which may
+not be used within high level APIs. This provides maximum flexibility so
+that consumers can make use of manufacturer defined bus commands which cannot be
+handled in a generic fashion.
+
+Design Trade-offs:
+The choice to not treat BIF like a traditional Linux bus was made because
+there is nothing within BIF that naturally maps to a device on the bus for a
+driver to manage. Slave devices would be a good candidate except that
+consumers will not be managing slaves so much as functions exposed within
+slaves. Bus matching could then instead be made at a BIF slave function
+level. Unfortunately, the BIF specification allows for manufacturer specific
+features to reside at any non-defined addresses. Additionally, consumers may
+wish only to read and make policy decisions based on BIF non-volatile memory
+(NVM) objects read out of memory. Thus, there are use-cases that require
+consumers to utilize the bus without having a particular function to match to.
+
+Another trade-off was the choice to use custom interrupt handling functions
+instead of the Linux interrupt framework. This choice was made because there is
+no obvious way to handle IRQ chip registration given the dynamic nature of BIF
+slaves (i.e. slaves may come and go at runtime if battery packs are swapped).
+
+Software layering:
+BIF controller drivers register a set of callback functions with the BIF
+framework which implement various BIF transaction primitives. These
+callbacks ensure that tight timing constraints are met such as when receiving
+a bus query response immediately after issuing a command. Such actions
+cannot be carried out at the framework level as timing requirements are on
+the order of 32 us when using the maximum data rate.
+
+The BIF framework provides easy access to standard BIF features such as
+slave, functions, and interrupts. The framework also ensures mutual exclusion
+between different BIF consumers.
+
+BIF consumer drivers make use of the API exposed by the framework in order
+utilize functionality found on smart battery packs. One example of a
+consumer driver is a temperature monitoring driver which reads the
+temperature reported by the BIF temperature function on a BIF slave and
+reports it to the Linux thermal framework.
+
+Power Management
+================
+
+The framework does not perform any special actions during system suspend and
+resume. Controller drivers may choose to enter low power states during
+suspend if they wish as long as it does not affect the logical state of the
+bus.
+
+SMP/multi-core
+==============
+
+Various linked lists are maintained inside of the framework which are
+protected by mutexes. Mutex locks are also used during transactions at a bus
+level in order to ensure mutual exclusion between consumers of the bus.
+
+Performance
+===========
+
+The BIF bus is inherently slow. Consumers should expect transactions to take
+a long time to execute. Consumers are responsible for blocking suspend if
+their transactions must be completed before the system enters suspend.
+
+Interface - BIF Consumer API
+============================
+
+BIF framework structs, enums, and functions used by BIF consumers are defined in
+include/linux/bif/consumer.h
+
+Detailed descriptions of the BIF framework functions can be found in:
+drivers/bif/bif-core.c
+
+Get/put handle for a BIF controller:
+------------------------------------
+
+struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev);
+
+void bif_ctrl_put(struct bif_ctrl *ctrl);
+
+int bif_ctrl_count(void);
+
+struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id);
+
+The function bif_ctrl_get() is intended to be the primary way to get a consumer
+BIF controller handle. It relies upon the consumer device specifying a
+"qcom,bif-ctrl" property in its device tree node which points to the phandle of
+the BIF controller it wishes to use.
+
+A secondary mechanism is also provided for drivers without device tree support.
+bif_ctrl_count() returns the number of BIF controllers currently registered.
+bif_ctrl_get_by_id() returns a handle to the id'th controller enumerated in
+registration order.
+
+Get/put handle for a BIF slave:
+-------------------------------
+
+int bif_slave_match_count(const struct bif_ctrl *ctrl,
+ const struct bif_match_criteria *match_criteria);
+
+struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+ unsigned int id, const struct bif_match_criteria *match_criteria);
+
+void bif_slave_put(struct bif_slave *slave);
+
+A consumer finds a slave attached to a given BIF controller by specifying a set
+of matching criteria. The criteria can include such quantities as manufacturer
+ID, product ID, function type or function version. It is possible that multiple
+slaves will match the criteria. bif_slave_match_count() returns how many slaves
+match the specified criteria. bif_slave_match_get() returns the id'th slave
+which matches the criteria in an arbitrary, but fixed order (for a constant set
+of slaves). Consumer drivers need to be able to handle the case of multiple
+slaves matching the criteria.
+
+Additionally, if a battery pack is inserted or removed, then the output of
+bif_slave_match_count() and bif_slave_match_get() could change. A consumer
+driver can register to receive notification of battery pack insertion and
+removal using the bif_ctrl_notifier_register() function listed below.
+
+Check if slave handle is still meaningful:
+------------------------------------------
+
+int bif_slave_is_present(struct bif_slave *slave);
+
+If a battery pack is removed, then the handles for its slaves will no longer be
+meaningful. All transactions using a handle for a slave that isn't present will
+fail. The function bif_slave_is_present() allows a consumer to determine if
+a given slave is still physically present in the system.
+
+Get access to the controller handle present in a slave handle:
+--------------------------------------------------------------
+
+struct bif_ctrl *bif_get_ctrl_handle(struct bif_slave *slave);
+
+This function is useful if a consumer wishes to only store a slave handle but
+also has need to call bus oriented BIF framework functions.
+
+Get version and register offset of a BIF function if it is present in a slave:
+------------------------------------------------------------------------------
+
+int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
+ u16 *function_pointer);
+
+This function is used by consumers who wish to support given BIF functions
+(e.g. temperature measurement, authentication, etc.) found inside of slaves.
+
+Receive notification upon battery insertion and removal:
+--------------------------------------------------------
+
+int bif_ctrl_notifier_register(struct bif_ctrl *ctrl,
+ struct notifier_block *nb);
+
+int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
+ struct notifier_block *nb);
+
+
+Read or write BIF slave registers:
+----------------------------------
+
+int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+
+int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+
+
+Get or set the BIF bus state or period:
+---------------------------------------
+
+int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl);
+
+int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state);
+
+int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl);
+
+int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns);
+
+Bus states include: active for communication, active waiting for interrupt,
+standby, and power down. The MIPI-BIF specification defines the allowed range
+of bus periods as 2000 ns to 153000 ns. Individual controllers may further
+restrict the range of allowed periods. When bif_ctrl_set_bus_period() is called
+the first supported period that greater than or equal to the specified period
+will be set.
+
+Measure battery pack resistance:
+--------------------------------
+
+int bif_ctrl_measure_rid(struct bif_ctrl *ctrl);
+
+This function returns an estimate of the battery pack resistance in ohms. If
+no battery pack is connected, then the output of this function is undefined.
+
+Utilize BIF slave tasks and interrupts:
+---------------------------------------
+
+int bif_request_irq(struct bif_slave *slave, unsigned int task,
+ struct notifier_block *nb);
+
+int bif_free_irq(struct bif_slave *slave, unsigned int task,
+ struct notifier_block *nb);
+
+int bif_trigger_task(struct bif_slave *slave, unsigned int task);
+
+int bif_task_is_busy(struct bif_slave *slave, unsigned int task);
+
+A consumer can request a slave interrupt and specify a notifier to call when the
+interrupt is triggered. Once the interrupt is requested the consumer will need
+to call bif_trigger_task() in order to start the task associated with the
+interrupt (both are identified by the same index). Polling for task completion
+is also supported via the bif_task_is_busy() function.
+
+Raw BIF bus transactions:
+-------------------------
+
+void bif_ctrl_bus_lock(struct bif_ctrl *ctrl);
+
+void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl);
+
+int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data);
+
+int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
+ u8 data, int *response);
+
+int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
+ u8 data, bool *query_response);
+
+int bif_slave_is_selected(struct bif_slave *slave);
+
+int bif_slave_select(struct bif_slave *slave);
+
+The function bif_ctrl_bus_lock() locks the BIF bus for exclusive use by the
+consumer. No other transactions will be allowed on the bus including those
+that would arise from battery insertion/removal or slave interrupt reception.
+This lock is primarily intended to be used along with the raw transaction
+functions. These functions allow a consumer to issue any BIF transaction
+including manufacturer specific bus commands not handled by the BIF framework.
+
+While performing raw transactions, features normally performed transparently by
+the core, such as device selection, are not available. The functions
+bif_slave_select() and bif_slave_is_selected() can be used to fill in this gap
+so that raw transactions are performed on the desired slave.
+
+Notify the BIF core that a battery has been inserted or removed:
+----------------------------------------------------------------
+
+int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl);
+
+This function should only be called on systems where the BIF controller driver
+is architecturally unable to detect battery insertion and removal on its own.
+
+Perform BIF object CRC using CRC-CCITT algorithm:
+-------------------------------------------------
+
+u16 bif_crc_ccitt(const u8 *buffer, int len);
+
+Interface - BIF Controller API
+==============================
+
+BIF framework structs and functions used by BIF controllers are defined in:
+include/linux/bif/driver.h
+
+Ops found in struct bif_ctrl_ops:
+---------------------------------
+
+int (*bus_transaction) (struct bif_ctrl_dev *bdev, int transaction, u8 data);
+
+int (*bus_transaction_query) (struct bif_ctrl_dev *bdev, int transaction,
+ u8 data, bool *query_response);
+
+int (*bus_transaction_read) (struct bif_ctrl_dev *bdev, int transaction,
+ u8 data, int *response);
+
+int (*read_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+ u8 *data, int len);
+
+int (*write_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+ const u8 *data, int len);
+
+int (*get_bus_period) (struct bif_ctrl_dev *bdev);
+
+int (*set_bus_period) (struct bif_ctrl_dev *bdev, int period_ns);
+
+int (*get_battery_presence) (struct bif_ctrl_dev *bdev);
+
+int (*get_battery_rid) (struct bif_ctrl_dev *bdev);
+
+int (*get_bus_state) (struct bif_ctrl_dev *bdev);
+
+int (*set_bus_state) (struct bif_ctrl_dev *bdev, int state);
+
+A BIF controller driver registers a set of call back functions which instantiate
+these ops. The BIF framework then calls these functions based on internal and
+consumer needs.
+
+The ops bus_transaction(), bus_transaction_query(), and bus_transaction_read()
+carry out the controller hardware specific actions to perform BIF transactions
+on the BIF bus. These transactions result in no slave response, a pulse in
+response, or a word in response respectively. The ops read_slave_registers()
+and write_slave_registers() internally must perform all transactions necessary
+to read and write to BIF slave registers. These ops exist so that burst reads
+and writes can take place since these activities have very tight timing
+constraints that the BIF core cannot handle.
+
+The ops get_bus_period() and set_bus_period() return the current bus clock base
+period in nanoseconds and change the period to a new value respectively. The
+ops get_bus_state() and set_bus_state() allow for monitoring and controlling the
+bus state (i.e. active for communication, active waiting for interrupt, standby,
+or power down). The op get_battery_presence() returns if any battery pack
+(smart or low cost) is currently connected to the BCL. The op get_battery_rid()
+returns a best estimate of the Rid battery pack pull down ID resistance in ohms
+which can be used to determine if the battery pack is smart or low cost.
+
+Register/unregister a BIF controller:
+-------------------------------------
+
+struct bif_ctrl_dev *bif_ctrl_register(struct bif_ctrl_desc *bif_desc,
+ struct device *dev, void *driver_data, struct device_node *of_node);
+
+void bif_ctrl_unregister(struct bif_ctrl_dev *bdev);
+
+Notify the BIF framework that a battery has been inserted or removed:
+---------------------------------------------------------------------
+
+int bif_ctrl_notify_battery_changed(struct bif_ctrl_dev *bdev);
+
+The BIF core will then call the get_battery_presence() op internally to
+determine if the event is an insertion or removal.
+
+Notify the BIF framework that a slave interrupt has been received:
+------------------------------------------------------------------
+
+int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev);
+
+Upon receiving this call, the BIF core interrogates each slave to determine
+which slaves have pending interrupts. It then iterates through all interrupts
+on those slaves clearing all pending interrupts and notifying any consumers
+waiting for the interrupts.
+
+Get BIF controller private data:
+--------------------------------
+
+void *bdev_get_drvdata(struct bif_ctrl_dev *bdev);
+
+Config options
+==============
+
+CONFIG_BIF - Enables BIF framework support.
+
+User space utilities
+====================
+
+No user space interface is provided in the BIF framework. Therefore, user
+space will not be able to directly use it.
+
+To do
+=====
+
+It is conceivable that the BIF framework should take some action during
+system suspend and resume. However, it is not clear exactly what should be
+done given that the BCL would still need to be active in order to detect
+battery removal while suspended.
+
+sysfs nodes could be added which describe slaves as well as functions and
+objects within the slaves. However these nodes would be read-only and would
+really only be useful for descriptive as opposed to control purposes.
+
+The exact time at which slave searching, function enumeration, and object
+loading takes place could be optimized in order to improve performance to
+some degree. It could also be made configurable at a controller level if
+needed.
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
index 53a67a4..9616a94 100644
--- a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -7,6 +7,7 @@
Optional properties:
-qcom,satellite-mode: the hardware needs to be configured in satellite mode
+-qcom,rx-ring-size: the size of the receive ring buffer pool, default is 32
Example:
@@ -15,4 +16,5 @@
reg = <0xfc834000 0x7000>;
interrupts = <0 29 1>;
qcom,satellite-mode;
+ qcom,rx-ring-size = <64>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
new file mode 100644
index 0000000..3a29004
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -0,0 +1,69 @@
+Qualcomm CPR (Core Power Reduction) Regulator
+
+CPR regulator device is for Qualcomm RBCPR (RapidBridge CPR) on
+ application processor core. It takes voltage corner level
+ as input and converts it to actual voltage based on the
+ suggestions from factory production process. When CPR is
+ enabled for application processer core, it will suggest
+ scaling the voltage up or down for best performance and
+ power of the core. The scaling based on factory production
+ process is called PVS (Process Voltage Scaling) with efuse
+ bits to indicate what bin (and voltage range) a chip is in.
+
+Required properties:
+- compatible: Must be "qcom,cpr-regulator"
+- reg: Register addresses for RBCPR and efuse
+- reg-names: Register names. Must be "rbcpr" and "efuse_phys"
+- regulator-name: A string used to describe the regulator
+- regulator-min-microvolt: Minimum corner value as min constraint, which
+ should be 1 for SVS corner
+- regulator-max-microvolt: Maximum corner value as max constraint, which
+ should be 4 for SUPER_TURBO or 3 for TURBO
+- qcom,num-efuse-bits: The number of bits used in efuse memory to
+ represent total number of PVS bins. It should
+ not exceed a maximum of 5 for total number of
+ 32 bins.
+- qcom,efuse-bit-pos: A list of integers whose length must equal
+ to qcom,num-efuse-bits and each integer indicates
+ bit position in efuse memory from LSB to MSB
+- qcom,pvs-bin-process: A list of integers whose length is equal to 2 to
+ the power of qcom,num-efuse-bits. The location or
+ 0-based index of an element in the list corresponds
+ to the bin number. The value of each integer
+ corresponds to the PVS process speed of the APC
+ silicon for a chip with one of these cases:
+ 1 = APC_PVS_SLOW
+ 2 = APC_PVS_NOM
+ 3 = APC_PVS_FAST
+ 0 or other values = No PVS
+- qcom,pvs-corner-ceiling-slow: Ceiling voltages of all corners for APC_PVS_SLOW
+- qcom,pvs-corner-ceiling-nom: Ceiling voltages of all corners for APC_PVS_NOM
+- qcom,pvs-corner-ceiling-fast: Ceiling voltages of all corners for APC_PVS_FAST
+ The ceiling voltages for each of above three
+ properties may look like this:
+ 0 (SVS voltage): 1050000 uV
+ 1 (NORMAL voltage): 1150000 uV
+ 2 (TURBO voltage): 1275000 uV
+ 3 (SUPER_TURBO voltage): 1275000 uV
+- vdd-apc-supply: Regulator to supply VDD APC power
+
+Example:
+ apc_vreg_corner: regulator@f9018000 {
+ status = "okay";
+ compatible = "qcom,cpr-regulator";
+ reg = <0xf9018000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "rbcpr", "efuse_phys";
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <4>;
+ qcom,num-efuse-bits = <5>;
+ qcom,efuse-bit-pos = <6 7 8 9 10>;
+ qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ vdd-apc-supply = <&pm8226_s2>;
+ };
+
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 0588c5e..b55bd53 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -55,6 +55,10 @@
- label: A string used as a descriptive name of the panel
- qcom,enable-gpio: Specifies the panel lcd/display enable gpio.
- qcom,rst-gpio: Specifies the panel reset gpio.
+- qcom,te-gpio: Specifies the gpio used for TE.
+- qcom,dsi-lpg-channel : LPG channel for backlight.
+- qcom,dsi-pwm-period : PWM period in microseconds.
+- qcom,dsi-pwm-gpio : PWM gpio.
- qcom,mdss-pan-broadcast-mode: Boolean used to enable broadcast mode.
- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode.
- qcom,mdss-pan-porch-values: An array of size 6 that specifies the panel blanking values.
@@ -71,6 +75,15 @@
- qcom,mdss-pan-dsi-mode: Specifies the panel operating mode.
0 = enable video mode(default mode).
1 = enable command mode.
+- qcom,mdss-vsync-enable: Specifies Tear Check configuration.
+ 0 = TE disable.
+ 1 = TE enable.
+- qcom,mdss-hw-vsync-mode: Specifies TE type.
+ 0 = software vsync.
+ 1 = hardware vsync (TE gpio pin).
+- qcom,mdss-pan-te-sel: Specifies TE operating mode.
+ 0 = TE through embedded dcs command
+ 1 = TE through TE gpio pin.
- qcom,mdss-pan-dsi-h-pulse-mode: Specifies the pulse mode option for the panel.
0 = Don't send hsa/he following vs/ve packet(default)
1 = Send hsa/he following vs/ve packet
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 6b95625..0422b57 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -75,6 +75,12 @@
The number of dspp blocks should match the
number of mixers driving data to interface
defined in property: qcom,mdss-mixer-intf-off
+- qcom,mdss-pingpong-off: Array of offset addresses for the available
+ pingpong blocks. These offsets are calculated
+ from regsiter "mdp_phys" defined in reg property.
+ The number of pingpong blocks should match the
+ number of mixers driving data to interface
+ defined in property: qcom,mdss-mixer-intf-off
- qcom,mdss-mixer-wb-off: Array of offset addresses for the available
mixer blocks that can be drive data to writeback
block. These offsets will be calculated from
@@ -99,6 +105,9 @@
settings used to setup MDSS QoS for best performance.
The key used should be offset from "mdp_phys" register
defined in reg property.
+- qcom,mdss-rot-block-size: The size of a memory block (in pixels) to be used
+ by the rotator. If this property is not specified,
+ then a default value of 128 pixels would be used.
Optional subnodes:
Child nodes representing the frame buffer virtual devices.
@@ -131,6 +140,7 @@
qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
qcom,mdss-pipe-dma-fetch-id = <10 13>;
qcom,mdss-smp-data = <22 4096>;
+ qcom,mdss-rot-block-size = <64>;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
0x00000900 0x0000A00>;
@@ -138,6 +148,7 @@
0x00003A00>;
qcom,mdss-mixer-wb-off = <0x00003E00 0x00004200>;
qcom,mdss-dspp-off = <0x00004600 0x00004A00 0x00004E00>;
+ qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
qcom,mdss-wb-off = <0x00011100 0x00013100 0x00015100
0x00017100 0x00019100>;
qcom,mdss-intf-off = <0x00021100 0x00021300
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 812a895..4f31f07 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -30,7 +30,7 @@
- qcom,ctrl-delay-us: delay in activation of led
- qcom,dig-mod-gen-en: digital module generator
- qcom,cs-out-en: current sink output enable
-- qcom,op-fdbck: selection of output as feedback for the boost
+- qcom,op-fdbck: selection of output as feedback for the boost, 00 = automatic selection, 01 = select LED1 output, 02 = select LED2 output, 03 = select LED3 output
- qcom,cp-select: high pole capacitance
- linux,default-trigger: trigger the led from external modules such as display
- qcom,default-state: default state of the led, should be "on" or "off"
@@ -138,7 +138,7 @@
linux,default-trigger = "bkl-trigger"
label = "wled";
qcom,cs-out-en;
- qcom,op-fdbck;
+ qcom,op-fdbck = <1>;
qcom,default-state "off";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index bebdb5a..2caa959 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -40,6 +40,8 @@
(enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
as "enum cp_mem_usage" in include/linux/msm_ion.h
- qcom,has-ocmem: indicate the target has ocmem if this property exists
+- qcom,max-hw-load: The maximum load the hardware can support expressed in units
+ of macroblocks per second.
Example:
@@ -73,4 +75,5 @@
qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
qcom,buffer-type-tz-usage-table = <0x1 0x1>,
<0x1fe 0x2>;
+ qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
};
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index e3108ac..ad35985 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -13,6 +13,8 @@
- interrupts: WCNSS to Apps watchdog bite interrupt
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
+- qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
+- qcom,gpio-force-stop: GPIO used by the Apps to force the wcnss to shutdown.
Example:
qcom,pronto@fb21b000 {
@@ -25,4 +27,10 @@
interrupts = <0 231 1>;
qcom,firmware-name = "wcnss";
+
+ /* GPIO input from wcnss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+
+ /* GPIO output to wcnss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 86b3ccb..acd0ae3 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -10,8 +10,7 @@
- reg: Pairs of physical base addresses and region sizes of
memory mapped registers.
- reg-names: Names of the bases for the above registers. "qdsp6_base",
- "halt_base", "rmb_base", "restart_reg", and
- "metadata_base" are expected.
+ "halt_base", "rmb_base", and "restart_reg" are expected.
- interrupts: The modem watchdog interrupt
- vdd_mss-supply: Reference to the regulator that supplies the processor.
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
@@ -34,10 +33,9 @@
reg = <0xfc880000 0x100>,
<0xfd485000 0x400>,
<0xfc820000 0x020>,
- <0xfc401680 0x004>,
- <0x0d1f0000 0x4000>;
+ <0xfc401680 0x004>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", metadata_base";
+ "restart_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8841_s3>;
vdd_cx-supply = <&pm8841_s2>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 2832693..f5465a4 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -45,8 +45,8 @@
battery temperature of 250 decidegree
Celsius, state of charge to be 50%
and disable charging.
-- qcom,chg-warm-bat-degc: Warm battery temperature in degC.
-- qcom,chg-cool-bat-degc: Cool battery temperature in degC.
+- qcom,chg-warm-bat-decidegc: Warm battery temperature in decidegC.
+- qcom,chg-cool-bat-decidegc: Cool battery temperature in decidegC.
Note that if both warm and cool battery
temperatures are set, the corresponding
ibatmax and bat-mv properties are
diff --git a/Documentation/devicetree/bindings/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt
index 43033a8..ac82387 100644
--- a/Documentation/devicetree/bindings/qseecom/qseecom.txt
+++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt
@@ -3,6 +3,9 @@
Required properties:
- compatible : Should be "qcom,qseecom"
- reg : should contain memory region address reserved for loading secure apps.
+- qcom,disk-encrypt-pipe-pair : indicates what CE HW pipe pair is used for disk encryption
+- qcom,hlos-ce-hw-instance : indicates what CE HW is used by HLOS crypto driver
+- qcom,qsee-ce-hw-instance : indicates what CE HW is used by secure domain (TZ) crypto driver
- qcom, msm_bus,name: Should be "qseecom-noc"
- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling
- qcom, msm_bus,num_paths: The paths for source and destination ports
@@ -13,6 +16,9 @@
compatible = "qcom,qseecom";
reg = <0x7f00000 0x500000>;
reg-names = "secapp-region";
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,hlos-ce-hw-instance = <1>;
+ qcom,qsee-ce-hw-instance = <0>;
qcom,msm_bus,name = "qseecom-noc";
qcom,msm_bus,num_cases = <4>;
qcom,msm_bus,active_only = <0>;
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 989bea8..cbc77ad 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -2,21 +2,38 @@
Required properties:
- - compatible : "qcom,taiko-slim-pgd"
- - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits)
+ - compatible : "qcom,taiko-slim-pgd"
+ - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits)
- - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
+ - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
- - <supply-name>-supply: phandle to the regulator device tree node
- - qcom,<supply-name>-voltage - specifies voltage levels for supply.
- Should be specified in pairs (min, max), units mV.
- - qcom,<supply-name>-current - specifies max current in mA that can drawn
- from the <supply-name>.
+ - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node.
+ - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-buck-current: buck supply's max current in mA.
- above three properties with "supply-name" set to "qcom,cdc-vdd-buck",
- "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
- "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
- should be present.
+ - cdc-vdd-tx-h-supply: phandle of tx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-tx-h-voltage: tx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-tx-h-current: tx-h supply's max current in mA.
+
+ - cdc-vdd-rx-h-supply: phandle of rx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-rx-h-voltage: rx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-rx-h-current: rx-h supply's max current in mA.
+
+ - cdc-vddpx-1-supply: phandle of px-1 supply's regulator device tree node.
+ - qcom,cdc-vddpx-1-voltage: px-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddpx-1-current: px-1 supply's max current in mA.
+
+ - cdc-vdd-a-1p2v-supply: phandle of 1.2v supply's regulator device tree node.
+ - qcom,cdc-vdd-a-1p2v-voltage: 1.2v supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-a-1p2v-current: 1.2v supply's max current in mA.
+
+ - cdc-vddcx-1-supply: phandle of cx-1 supply's regulator device tree node.
+ - qcom,cdc-vddcx-1-voltage: cx-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-1-current: cx-1 supply's max current in mA.
+
+ - cdc-vddcx-2-supply: phandle of cx-2 supply's regulator device tree node.
+ - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
- qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
@@ -99,19 +116,37 @@
Wcd9xxx audio CODEC in I2C mode
- - compatible = "qcom,wcd9xxx-i2c-device";
- - reg: represents the slave address provided to the I2C driver.
- - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
- - <supply-name>-supply: phandle to the regulator device tree node.
- - qcom,<supply-name>-voltage - specifies voltage levels for supply.
- Should be specified in pairs (min, max), units mV.
- - qcom,<supply-name>-current - specifies max current in mA that can drawn
- from the <supply-name>.
+ - compatible = "qcom,wcd9xxx-i2c-device";
+ - reg: represents the slave address provided to the I2C driver.
+ - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
- above three properties with "supply-name" set to "qcom,cdc-vdd-buck",
- "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
- "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
- should be present.
+ - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node.
+ - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-buck-current: buck supply's max current in mA.
+
+ - cdc-vdd-tx-h-supply: phandle of tx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-tx-h-voltage: tx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-tx-h-current: tx-h supply's max current in mA.
+
+ - cdc-vdd-rx-h-supply: phandle of rx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-rx-h-voltage: rx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-rx-h-current: rx-h supply's max current in mA.
+
+ - cdc-vddpx-1-supply: phandle of px-1 supply's regulator device tree node.
+ - qcom,cdc-vddpx-1-voltage: px-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddpx-1-current: px-1 supply's max current in mA.
+
+ - cdc-vdd-a-1p2v-supply: phandle of 1.2v supply's regulator device tree node.
+ - qcom,cdc-vdd-a-1p2v-voltage: 1.2v supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-a-1p2v-current: 1.2v supply's max current in mA.
+
+ - cdc-vddcx-1-supply: phandle of cx-1 supply's regulator device tree node.
+ - qcom,cdc-vddcx-1-voltage: cx-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-1-current: cx-1 supply's max current in mA.
+
+ - cdc-vddcx-2-supply: phandle of cx-2 supply's regulator device tree node.
+ - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
- qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
@@ -121,13 +156,13 @@
cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
- qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1
- (should be from 1 to 3).
+ (should be from 1 to 3).
- qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2
- (should be from 1 to 3).
+ (should be from 1 to 3).
- qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3
- (should be from 1 to 3).
+ (should be from 1 to 3).
- qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4
- (should be from 1 to 3).
+ (should be from 1 to 3).
This value represents the connected CFLIT to MIC Bias.
- qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index f1f4e94..3854598 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -20,6 +20,13 @@
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+Optional properties:
+- qcom,thermal-node : If present a thermal node is created and the channel is registered as
+ part of the thermal sysfs which allows clients to use the thermal framework
+ to set temperature thresholds and receive notification when the temperature
+ crosses a set threshold, read temperature and enable/set trip types supported
+ by the thermal framework.
+
Channel nodes
NOTE: Atleast one Channel node is required.
@@ -105,7 +112,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
- /* Channel Node */
+ /* Channel Node to be registered as part of thermal sysfs */
chan@b5 {
label = "pa_therm1";
reg = <0xb5>;
@@ -116,5 +123,19 @@
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
};
+
+ /* Channel Node */
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x78>;
+ };
};
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index effc7c5..e2b6a66 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -342,6 +342,17 @@
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
};
+
+ chan@c {
+ label = "ref_buf_625mv";
+ reg = <0xc>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
};
iadc@3600 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index d174157..2b1a352 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -175,10 +175,10 @@
qcom,chg-ibatmax-ma = <1500>;
qcom,chg-ibatsafe-ma = <1500>;
qcom,chg-thermal-mitigation = <1500 700 600 325>;
- qcom,chg-cool-bat-degc = <10>;
+ qcom,chg-cool-bat-decidegc = <100>;
qcom,chg-cool-bat-mv = <4100>;
qcom,chg-ibatmax-warm-ma = <350>;
- qcom,chg-warm-bat-degc = <45>;
+ qcom,chg-warm-bat-decidegc = <450>;
qcom,chg-warm-bat-mv = <4100>;
qcom,chg-ibatmax-cool-ma = <350>;
qcom,chg-vbatdet-delta-mv = <350>;
@@ -724,7 +724,7 @@
};
chan@b5 {
- label = "pa_therm1";
+ label = "pa_therm0";
reg = <0xb5>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
@@ -735,7 +735,7 @@
};
chan@b7 {
- label = "pa_therm2";
+ label = "pa_therm1";
reg = <0xb7>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
@@ -814,7 +814,7 @@
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
+ qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x48>;
};
@@ -826,32 +826,58 @@
qcom,calibration-type = "ratiometric";
qcom,scale-function = <1>;
qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
+ qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x68>;
};
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x88>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x90>;
+ };
+
chan@b5 {
- label = "pa_therm1";
+ label = "pa_therm0";
reg = <0xb5>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
qcom,scale-function = <2>;
qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
+ qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
};
chan@b7 {
- label = "pa_therm2";
+ label = "pa_therm1";
reg = <0xb7>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
+ qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
};
chan@b4 {
@@ -862,8 +888,22 @@
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
+ qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x80>;
+ qcom,thermal-node;
+ };
+
+ chan@b3 {
+ label = "msm_therm";
+ reg = <0xb3>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x98>;
+ qcom,thermal-node;
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 750e591..3c41e9e 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -1012,8 +1012,8 @@
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 04b7c7e..eab8b07 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -189,14 +189,14 @@
linux,name = "wled:backlight";
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
- qcom,op-fdbck;
+ qcom,op-fdbck = <1>;
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 35d329c..993b4e6 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -213,7 +213,7 @@
coresight-name = "coresight-csr";
coresight-nr-inports = <0>;
- qcom,blk-size = <3>;
+ qcom,blk-size = <1>;
};
cti0: cti@fc308000 {
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index ef8cb700..7ab76f1 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -32,8 +32,10 @@
qcom,mdss-mixer-intf-off = <0x00003200>;
qcom,mdss-mixer-wb-off = <0x00003E00>;
qcom,mdss-dspp-off = <0x00004600>;
+ qcom,mdss-pingpong-off = <0x00021B00>;
qcom,mdss-wb-off = <0x00011100 0x00013100>;
qcom,mdss-intf-off = <0x00000000 0x00021300>;
+ qcom,mdss-rot-block-size = <64>;
qcom,vbif-settings = <0x004 0x00000001>,
<0x0D8 0x00000707>,
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index be831b4..5c6fbd5 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -182,14 +182,14 @@
linux,name = "wled:backlight";
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
- qcom,op-fdbck;
+ qcom,op-fdbck = <1>;
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index 6bd5ea9..df74bf9 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -185,14 +185,14 @@
linux,name = "wled:backlight";
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
- qcom,op-fdbck;
+ qcom,op-fdbck = <1>;
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 448a5be..9c21707 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -24,6 +24,29 @@
};
};
+/* CPR controlled regulator */
+
+/ {
+ apc_vreg_corner: regulator@f9018000 {
+ status = "okay";
+ compatible = "qcom,cpr-regulator";
+ reg = <0xf9018000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "rbcpr", "efuse_phys";
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <4>;
+ qcom,num-efuse-bits = <5>;
+ qcom,efuse-bit-pos = <6 7 8 9 10>;
+ qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ vdd-apc-supply = <&pm8226_s2>;
+ };
+};
+
/* RPM controlled regulators: */
&rpm_bus {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 2538317..b34fa1f 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -96,6 +96,7 @@
qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
qcom,buffer-type-tz-usage-table = <0x1 0x1>,
<0x1fe 0x2>;
+ qcom,max-hw-load = <352800>; /* 720p @ 30 + 1080p @ 30 */
};
qcom,wfd {
@@ -409,6 +410,15 @@
gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
qcom,has_pronto_hw;
};
+
+ qcom,msm-adsp-sensors {
+ compatible = "qcom,msm-adsp-sensors";
+ qcom,src-id = <11>;
+ qcom,dst-id = <604>;
+ qcom,ab = <32505856>;
+ qcom,ib = <32505856>;
+ };
+
qcom,wdt@f9017000 {
compatible = "qcom,msm-watchdog";
reg = <0xf9017000 0x1000>;
@@ -565,7 +575,7 @@
compatible = "qcom,acpuclk-a7";
reg = <0xf9011050 0x8>;
reg-names = "rcg_base";
- a7_cpu-supply = <&pm8226_s2>;
+ a7_cpu-supply = <&apc_vreg_corner>;
a7_mem-supply = <&pm8226_l3>;
};
@@ -636,10 +646,9 @@
<0xfd485000 0x400>,
<0xfc820000 0x020>,
<0xfc401680 0x004>,
- <0x0d1fc000 0x4000>,
<0xfd485194 0x4>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "metadata_base", "cxrail_bhs_reg";
+ "restart_reg", "cxrail_bhs_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8226_s1>;
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
new file mode 100644
index 0000000..f3a8259
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -0,0 +1,168 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+/ {
+ msm_gpu: qcom,kgsl-3d0@fdc00000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ reg = <0xfdc00000 0x10000
+ 0xfdc10000 0x10000>;
+ reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_shader_memory";
+ interrupts = <0 33 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x03000520>;
+
+ qcom,initial-pwrlevel = <1>;
+
+ qcom,idle-timeout = <8>; /* <HZ/12> */
+ qcom,nap-allowed = <1>;
+ qcom,strtstp-sleepwake;
+ qcom,clk-map = <0x000001E>; /* KGSL_CLK_CORE |
+ KGSL_CLK_IFACE | KGSL_CLK_MEM | KGSL_CLK_MEM_IFACE */
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "grp3d";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>,
+ <26 512 0 800000>,
+ <26 512 0 1600000>,
+ <26 512 0 2128000>;
+
+ /* GDSC oxili regulators */
+ vdd-supply = <&gdsc_oxili_cx>;
+
+ /* IOMMU Data */
+ iommu = <&gfx_iommu>;
+
+ /* Power levels */
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <400000000>;
+ qcom,bus-freq = <3>;
+ qcom,io-fraction = <0>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <300000000>;
+ qcom,bus-freq = <2>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <200000000>;
+ qcom,bus-freq = <2>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <150000000>;
+ qcom,bus-freq = <1>;
+ qcom,io-fraction = <100>;
+ };
+
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <27000000>;
+ qcom,bus-freq = <0>;
+ qcom,io-fraction = <0>;
+ };
+ };
+
+ /* DVCS Info */
+ qcom,dcvs-core-info {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,dcvs-core-info";
+
+ qcom,num-cores = <1>;
+ qcom,sensors = <0>;
+
+ qcom,core-core-type = <1>;
+
+ qcom,algo-disable-pc-threshold = <0>;
+ qcom,algo-em-win-size-min-us = <100000>;
+ qcom,algo-em-win-size-max-us = <300000>;
+ qcom,algo-em-max-util-pct = <97>;
+ qcom,algo-group-id = <95>;
+ qcom,algo-max-freq-chg-time-us = <100000>;
+ qcom,algo-slack-mode-dynamic = <100000>;
+ qcom,algo-slack-weight-thresh-pct = <0>;
+ qcom,algo-slack-time-min-us = <39000>;
+ qcom,algo-slack-time-max-us = <39000>;
+ qcom,algo-ss-win-size-min-us = <1000000>;
+ qcom,algo-ss-win-size-max-us = <1000000>;
+ qcom,algo-ss-util-pct = <95>;
+ qcom,algo-ss-no-corr-below-freq = <0>;
+
+ qcom,energy-active-coeff-a = <2492>;
+ qcom,energy-active-coeff-b = <0>;
+ qcom,energy-active-coeff-c = <0>;
+ qcom,energy-leakage-coeff-a = <11>;
+ qcom,energy-leakage-coeff-b = <157150>;
+ qcom,energy-leakage-coeff-c = <0>;
+ qcom,energy-leakage-coeff-d = <0>;
+
+ qcom,power-current-temp = <25>;
+ qcom,power-num-freq = <4>;
+
+ qcom,dcvs-freq@0 {
+ reg = <0>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
+ };
+
+ qcom,dcvs-freq@1 {
+ reg = <1>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
+ };
+
+ qcom,dcvs-freq@2 {
+ reg = <2>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
+ };
+
+ qcom,dcvs-freq@3 {
+ reg = <3>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <844545>;
+ qcom,leakage-energy-offset = <0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index f11f04b..5512ccd 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -23,6 +23,43 @@
};
};
+/* SPM controlled regulators */
+
+&spmi_bus {
+ qcom,pm8110@1 {
+ pm8110_s2: spm-regulator@1700 {
+ compatible = "qcom,spm-regulator";
+ regulator-name = "8110_s2";
+ reg = <0x1700 0x100>;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1350000>;
+ };
+ };
+};
+
+/* CPR controlled regulator */
+
+/ {
+ apc_vreg_corner: regulator@f9018000 {
+ status = "okay";
+ compatible = "qcom,cpr-regulator";
+ reg = <0xf9018000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "rbcpr", "efuse_phys";
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <4>;
+ qcom,num-efuse-bits = <5>;
+ qcom,efuse-bit-pos = <6 7 8 9 10>;
+ qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ vdd-apc-supply = <&pm8110_s2>;
+ };
+};
+
/* QPNP controlled regulators: */
&spmi_bus {
@@ -38,15 +75,6 @@
regulator-always-on;
};
- pm8110_s2: regulator@1700 {
- status = "okay";
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1150000>;
- qcom,enable-time = <500>;
- qcom,system-load = <100000>;
- regulator-always-on;
- };
-
pm8110_s3: regulator@1a00 {
status = "okay";
regulator-min-microvolt = <1350000>;
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
new file mode 100644
index 0000000..4a5273b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -0,0 +1,184 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+/ {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-adsp {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 158 1>;
+ };
+
+ qcom,smp2p-wcnss {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <0 143 1>;
+ };
+
+ smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+ gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+ gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 407104f..91dfdbe 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -13,9 +13,11 @@
/include/ "skeleton.dtsi"
/include/ "msm-iommu-v0.dtsi"
/include/ "msm8610-ion.dtsi"
+/include/ "msm8610-gpu.dtsi"
/include/ "msm-gdsc.dtsi"
/include/ "msm8610-coresight.dtsi"
/include/ "msm8610-pm.dtsi"
+/include/ "msm8610-smp2p.dtsi"
/ {
model = "Qualcomm MSM 8610";
@@ -77,6 +79,7 @@
qcom,buffer-type-tz-usage-map = <0x1 0x1>,
<0x1fe 0x2>;
qcom,hfi = "q6";
+ qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
};
usb@f9a55000 {
@@ -262,7 +265,7 @@
compatible = "qcom,acpuclk-a7";
reg = <0xf9011050 0x8>;
reg-names = "rcg_base";
- a7_cpu-supply = <&pm8110_s2>;
+ a7_cpu-supply = <&apc_vreg_corner>;
a7_mem-supply = <&pm8110_l3>;
};
@@ -440,10 +443,9 @@
<0xfd485000 0x400>,
<0xfc820000 0x020>,
<0xfc401680 0x004>,
- <0x0d1fc000 0x4000>,
<0xfd485194 0x4>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "metadata_base", "cxrail_bhs_reg";
+ "restart_reg", "cxrail_bhs_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8110_s1>;
@@ -475,7 +477,7 @@
interrupts = <0 184 0>;
qcom,sensors = <2>;
qcom,slope = <2901 2846>;
- qcom,calib-mode = "fuse_map2";
+ qcom,calib-mode = "fuse_map3";
qcom,calibration-less-mode;
qcom,tsens-local-init;
};
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index 8f58c3e..828e7ae 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1166,8 +1166,8 @@
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
};
mas-ampss-m1 {
@@ -1180,8 +1180,8 @@
qcom,qport = <1>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 9d98476..2919709 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -247,7 +247,7 @@
linux,name = "wled:backlight";
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
- qcom,op-fdbck;
+ qcom,op-fdbck = <1>;
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
@@ -298,6 +298,10 @@
};
};
+&sdcc1 {
+ status = "disabled";
+};
+
&sdcc2 {
#address-cells = <0>;
interrupt-parent = <&sdcc2>;
@@ -310,12 +314,15 @@
interrupt-names = "core_irq", "bam_irq", "status_irq";
cd-gpios = <&msmgpio 62 0x1>;
wp-gpios = <&pm8941_gpios 29 0x1>;
+ status = "disabled";
};
&sdhc_1 {
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -329,6 +336,7 @@
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
qcom,nonremovable;
+ status = "ok";
};
&sdhc_2 {
@@ -349,8 +357,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -358,6 +364,7 @@
qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+ status = "ok";
};
&uart7 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 2ddc61d..046939e 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -224,7 +224,7 @@
linux,name = "wled:backlight";
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
- qcom,op-fdbck;
+ qcom,op-fdbck = <1>;
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
@@ -277,6 +277,7 @@
&sdcc1 {
qcom,bus-width = <4>;
+ status = "disabled";
};
&sdcc2 {
@@ -290,12 +291,15 @@
2 &msmgpio 62 0x3>;
interrupt-names = "core_irq", "bam_irq", "status_irq";
cd-gpios = <&msmgpio 62 0x1>;
+ status = "disabled";
};
&sdhc_1 {
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -309,6 +313,7 @@
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
qcom,nonremovable;
+ status = "ok";
};
&sdhc_2 {
@@ -329,8 +334,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -338,6 +341,7 @@
qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+ status = "ok";
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index a10d1d6..0f38e44 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -764,10 +764,20 @@
};
};
+&sdcc1 {
+ status = "disabled";
+};
+
+&sdcc2 {
+ status = "disabled";
+};
+
&sdhc_1 {
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -781,6 +791,7 @@
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
qcom,nonremovable;
+ status = "ok";
};
&sdhc_2 {
@@ -790,8 +801,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -799,4 +808,5 @@
qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+ status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 6011d52..8fa1d75 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -199,7 +199,7 @@
linux,name = "wled:backlight";
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
- qcom,op-fdbck;
+ qcom,op-fdbck = <1>;
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
@@ -250,6 +250,10 @@
};
};
+&sdcc1 {
+ status = "disabled";
+};
+
&sdcc2 {
#address-cells = <0>;
interrupt-parent = <&sdcc2>;
@@ -261,12 +265,15 @@
2 &msmgpio 62 0x3>;
interrupt-names = "core_irq", "bam_irq", "status_irq";
cd-gpios = <&msmgpio 62 0x1>;
+ status = "disabled";
};
&sdhc_1 {
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -280,6 +287,7 @@
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
qcom,nonremovable;
+ status = "ok";
};
&sdhc_2 {
@@ -300,8 +308,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -309,6 +315,7 @@
qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+ status = "ok";
};
&usb_otg {
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index b125138..05451671 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -520,4 +520,15 @@
gpio = <&pm8941_mpps 5 0>;
enable-active-high;
};
+
+ /*
+ * vph_pwr_vreg represents the unregulated battery voltage supply
+ * VPH_PWR that is present whenever the device is powered on.
+ */
+ vph_pwr_vreg: vph_pwr_vreg {
+ compatible = "regulator-fixed";
+ status = "disabled";
+ regulator-name = "vph_pwr";
+ regulator-always-on;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
index 1b08246..a621801 100644
--- a/arch/arm/boot/dts/msm8974-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -184,6 +184,29 @@
#interrupt-cells = <2>;
};
+ /* SMP2P SSR Driver for inbound entry from wcnss. */
+ smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* SMP2P SSR Driver for outbound entry to wcnss */
+ smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
qcom,smp2pgpio_test_smp2p_4_out {
compatible = "qcom,smp2pgpio_test_smp2p_4_out";
gpios = <&smp2pgpio_smp2p_4_out 0 0>;
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index bccf0fe..ae8cf83 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -56,6 +56,10 @@
qcom,write-64bit;
};
+&mdss_mdp {
+ qcom,mdss-pingpong-off = <0x00021B00 0x00021C00 0x00021D00>;
+};
+
&msm_vidc {
qcom,vidc-cp-map = <0x1000000 0x3f000000>;
qcom,vidc-ns-map = <0x40000000 0x40000000>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 16cdeb1..61f2c4f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -64,6 +64,7 @@
0x00011900 0x00011D00 0x00012100>;
qcom,mdss-intf-off = <0x00012500 0x00012700
0x00012900 0x00012b00>;
+ qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
};
&msm_vidc {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 9102770..c16feee 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -96,6 +96,7 @@
interrupts = <0 44 0>;
qcom,hfi = "venus";
qcom,has-ocmem;
+ qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
};
qcom,vidc {
@@ -209,6 +210,7 @@
<78 512 2048000 4096000>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
qcom,dat1-mpm-int = <42>;
+ status = "disable";
};
sdcc2: qcom,sdcc@f98a4000 {
@@ -255,6 +257,7 @@
<81 512 2048000 4096000>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
qcom,dat1-mpm-int = <44>;
+ status = "disable";
};
sdcc3: qcom,sdcc@f9864000 {
@@ -989,10 +992,9 @@
reg = <0xfc880000 0x100>,
<0xfd485000 0x400>,
<0xfc820000 0x020>,
- <0xfc401680 0x004>,
- <0x0d1fc000 0x4000>;
+ <0xfc401680 0x004>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "metadata_base";
+ "restart_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8841_s3>;
@@ -1021,6 +1023,12 @@
vdd_pronto_pll-supply = <&pm8941_l12>;
qcom,firmware-name = "wcnss";
+
+ /* GPIO input from wcnss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+
+ /* GPIO output to wcnss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
};
qcom,iris-fm {
@@ -1098,6 +1106,9 @@
compatible = "qcom,qseecom";
reg = <0x7f00000 0x500000>;
reg-names = "secapp-region";
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,hlos-ce-hw-instance = <1>;
+ qcom,qsee-ce-hw-instance = <0>;
qcom,msm-bus,name = "qseecom-noc";
qcom,msm-bus,num-cases = <4>;
qcom,msm-bus,active-only = <0>;
@@ -1118,9 +1129,9 @@
qcom,ipi-ping;
};
- qcom,tz-log@fc03000 {
+ qcom,tz-log@fe805720 {
compatible = "qcom,tz-log";
- reg = <0x0fc03000 0x1000>;
+ reg = <0xfe805720 0x1000>;
};
qcom,venus@fdce0000 {
@@ -1267,6 +1278,7 @@
compatible = "qcom,bam_dmux";
reg = <0xfc834000 0x7000>;
interrupts = <0 29 1>;
+ qcom,rx-ring-size = <64>;
};
qcom,msm-mem-hole {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index b06419d..3dbc95d 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -189,6 +189,7 @@
qcom,dst-bam-pipe-index = <3>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe4 {
label = "hsic-ipa-in-1";
@@ -201,6 +202,7 @@
qcom,dst-bam-pipe-index = <4>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe5 {
label = "hsic-ipa-in-2";
@@ -213,6 +215,7 @@
qcom,dst-bam-pipe-index = <5>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe6 {
label = "hsic-ipa-in-3";
@@ -225,6 +228,7 @@
qcom,dst-bam-pipe-index = <6>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe7 {
label = "hsic-ipa-out-0";
@@ -237,6 +241,7 @@
qcom,src-bam-pipe-index = <7>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
};
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
deleted file mode 100644
index d925ab3..0000000
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ /dev/null
@@ -1,376 +0,0 @@
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-perf"
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X30=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG3=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RPC_WATCHDOG=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_QSD_AUDIO is not set
-CONFIG_MSM_MEMORY_LOW_POWER_MODE=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
-CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
-CONFIG_MSM_MULTIMEDIA_USE_ION=y
-CONFIG_MSM_RPC_PMIC=y
-CONFIG_MSM_RPC_USB=y
-CONFIG_MSM_RPC_PMAPP=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NETFILTER_TPROXY=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_LOG=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFLOG=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
-CONFIG_NETFILTER_XT_MATCH_SOCKET=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_SFQ=y
-CONFIG_NET_SCH_TBF=y
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_INGRESS=y
-CONFIG_NET_CLS_BASIC=y
-CONFIG_NET_CLS_TCINDEX=y
-CONFIG_NET_CLS_FW=y
-CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_FLOW=m
-CONFIG_NET_EMATCH=y
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_MIRRED=y
-CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=y
-# CONFIG_CFG80211_WEXT is not set
-CONFIG_RFKILL=y
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8XXX_UPL=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_TUN=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-CONFIG_LIBRA_SDIOIF=m
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM=y
-CONFIG_TOUCHSCREEN_TSC2007=y
-CONFIG_TOUCHSCREEN_CY8C_TS=y
-CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-CONFIG_BOSCH_BMA150=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_QUP=y
-CONFIG_I2C_SSBI=y
-CONFIG_SPI=y
-CONFIG_SPI_QSD=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-CONFIG_SENSORS_MSM_ADC=y
-CONFIG_THERMAL=y
-CONFIG_THERMAL_MSM_POPMEM=y
-CONFIG_PMIC8058=y
-CONFIG_MARIMBA_CORE=y
-CONFIG_MARIMBA_CODEC=y
-CONFIG_TIMPANI_CODEC=y
-# CONFIG_MFD_PM8XXX_DEBUG is not set
-# CONFIG_MFD_PM8XXX_PWM is not set
-# CONFIG_MFD_PM8XXX_MISC is not set
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_VIDEO_DEV=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_RADIO_TAVARUA=y
-CONFIG_ION=y
-CONFIG_ION_MSM=y
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_LOGO=y
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP40=y
-CONFIG_FB_MSM_OVERLAY=y
-CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y
-CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_SPI is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM7KV2_SOC=y
-CONFIG_SND_MVS_SOC=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_MAGICMOUSE=y
-CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
-CONFIG_USB_MSM_ACA=y
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_TEST=m
-CONFIG_MMC_MSM=y
-# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
-CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
-CONFIG_MMC_MSM_SDC3_SUPPORT=y
-CONFIG_MMC_MSM_SDC4_SUPPORT=y
-CONFIG_LEDS_PMIC8058=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_MSM_SSBI=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_FUSE_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
deleted file mode 100644
index 9eea95c..0000000
--- a/arch/arm/configs/msm7630_defconfig
+++ /dev/null
@@ -1,381 +0,0 @@
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X30=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG3=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RPC_WATCHDOG=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_QSD_AUDIO is not set
-CONFIG_MSM_MEMORY_LOW_POWER_MODE=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
-CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
-CONFIG_MSM_MULTIMEDIA_USE_ION=y
-CONFIG_MSM_RPC_PMIC=y
-CONFIG_MSM_RPC_USB=y
-CONFIG_MSM_RPC_PMAPP=y
-CONFIG_STRICT_MEMORY_RWX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NETFILTER_TPROXY=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_LOG=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFLOG=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
-CONFIG_NETFILTER_XT_MATCH_SOCKET=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_SFQ=y
-CONFIG_NET_SCH_TBF=y
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_INGRESS=y
-CONFIG_NET_CLS_BASIC=y
-CONFIG_NET_CLS_TCINDEX=y
-CONFIG_NET_CLS_FW=y
-CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_FLOW=m
-CONFIG_NET_EMATCH=y
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_MIRRED=y
-CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=y
-# CONFIG_CFG80211_WEXT is not set
-CONFIG_RFKILL=y
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8XXX_UPL=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_TUN=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-CONFIG_LIBRA_SDIOIF=m
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM=y
-CONFIG_TOUCHSCREEN_TSC2007=y
-CONFIG_TOUCHSCREEN_CY8C_TS=y
-CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-CONFIG_BOSCH_BMA150=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_QUP=y
-CONFIG_I2C_SSBI=y
-CONFIG_SPI=y
-CONFIG_SPI_QSD=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-CONFIG_SENSORS_MSM_ADC=y
-CONFIG_THERMAL=y
-CONFIG_THERMAL_MSM_POPMEM=y
-CONFIG_PMIC8058=y
-CONFIG_MARIMBA_CORE=y
-CONFIG_MARIMBA_CODEC=y
-CONFIG_TIMPANI_CODEC=y
-# CONFIG_MFD_PM8XXX_DEBUG is not set
-# CONFIG_MFD_PM8XXX_PWM is not set
-# CONFIG_MFD_PM8XXX_MISC is not set
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_VIDEO_DEV=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_RADIO_TAVARUA=y
-CONFIG_ION=y
-CONFIG_ION_MSM=y
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_LOGO=y
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP40=y
-CONFIG_FB_MSM_OVERLAY=y
-CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_SPI is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM7KV2_SOC=y
-CONFIG_SND_MVS_SOC=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
-CONFIG_USB_MSM_ACA=y
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_TEST=m
-CONFIG_MMC_MSM=y
-# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
-CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
-CONFIG_MMC_MSM_SDC3_SUPPORT=y
-CONFIG_MMC_MSM_SDC4_SUPPORT=y
-CONFIG_LEDS_PMIC8058=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_MSM_SSBI=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_FUSE_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_SCHEDSTATS=y
-CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_SLAB=y
-CONFIG_DEBUG_SLAB_LEAK=y
-# CONFIG_DEBUG_PREEMPT is not set
-CONFIG_PROVE_LOCKING=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2a6ba73..590692c 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -57,7 +57,9 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
@@ -203,7 +205,6 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
-CONFIG_KS8851=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
@@ -272,6 +273,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 8d6bc81..42acd99 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -53,6 +53,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_RTB=y
CONFIG_MSM_UARTDM_Core_v14=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 9e9bba9..041e89a 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -53,6 +53,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_RTB=y
CONFIG_MSM_UARTDM_Core_v14=y
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 2b3667f..366debb 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -381,6 +381,8 @@
.stop = arch_timer_stop,
};
+static struct clock_event_device arch_timer_global_evt;
+
static int __init arch_timer_common_register(void)
{
int err;
@@ -431,9 +433,19 @@
}
err = local_timer_register(&arch_timer_ops);
+ if (err) {
+ /*
+ * We couldn't register as a local timer (could be
+ * because we're on a UP platform, or because some
+ * other local timer is already present...). Try as a
+ * global timer instead.
+ */
+ arch_timer_global_evt.cpumask = cpumask_of(0);
+ err = arch_timer_setup(&arch_timer_global_evt);
+ }
+
if (err)
goto out_free_irq;
- percpu_timer_setup();
/* Use the architected timer for the delay loop. */
arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 618668f..cd5d55b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -368,10 +368,8 @@
select ARM_GIC
select MIGHT_HAVE_CACHE_L2X0
select ARCH_MSM_CORTEX_A5
- select SMP
- select MSM_SMP
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MSM_RPM_SMD
select MSM_NATIVE_RESTART
@@ -428,6 +426,7 @@
select REGULATOR
select MSM_RPM_REGULATOR_SMD
select MSM_SPM_REGULATOR
+ select MSM_CPR_REGULATOR
config ARCH_MSM8226
bool "MSM8226"
@@ -465,6 +464,7 @@
select MSM_RPM_REGULATOR_SMD
select MSM_SPM_REGULATOR
select MSM_JTAG_MM if CORESIGHT_ETM
+ select MSM_CPR_REGULATOR
endmenu
choice
@@ -2641,8 +2641,6 @@
config SENSORS_ADSP
bool "Enable Sensors Driver Support for ADSP"
- depends on (ARCH_MSM8226 || ARCH_MSM8974)
- default y
help
Add support for sensors ADSP driver.
This driver is used for exercising different sensors use cases,
@@ -2912,4 +2910,15 @@
bool "Configure XPU violations as fatal errors"
help
Select if XPU violations have to be configured as fatal errors.
+
+config MSM_CPR_REGULATOR
+ bool "RBCPR regulator driver for APC"
+ depends on REGULATOR
+ depends on OF
+ help
+ Compile in RBCPR (RapidBridge Core Power Reduction) driver to support
+ corner vote for APC power rail. The driver takes PTE process voltage
+ suggestions in efuse as initial settings. It converts corner vote
+ to voltage value before writing to a voltage regulator API, such as
+ that provided by spm-regulator driver.
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d3acbc7..d07b094 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -422,3 +422,4 @@
obj-$(CONFIG_MSM_CPU_PWRCTL) += msm_cpu_pwrctl.o
obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
+obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 73ea435..6e93c57 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/cpr-regulator.h>
#include <mach/clk-provider.h>
#include <mach/msm_bus.h>
@@ -53,13 +54,13 @@
* 3) Depending on Frodo version, may need minimum of LVL_NOM
*/
static struct clkctl_acpu_speed acpu_freq_tbl[] = {
- { 0, 19200, CXO, 0, 0, 1150000, 1150000, 0 },
- { 1, 300000, PLL0, 4, 2, 1150000, 1150000, 4 },
- { 1, 384000, ACPUPLL, 5, 0, 1150000, 1150000, 4 },
- { 1, 600000, PLL0, 4, 0, 1150000, 1150000, 6 },
- { 1, 787200, ACPUPLL, 5, 0, 1150000, 1150000, 7 },
- { 0, 998400, ACPUPLL, 5, 0, 1150000, 1150000, 7 },
- { 0, 1190400, ACPUPLL, 5, 0, 1150000, 1150000, 7 },
+ { 0, 19200, CXO, 0, 0, CPR_CORNER_SVS, 1150000, 0 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 1150000, 4 },
+ { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 1150000, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 1150000, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 1150000, 7 },
+ { 0, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 1150000, 7 },
+ { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 1150000, 7 },
{ 0 }
};
@@ -67,8 +68,7 @@
.freq_tbl = acpu_freq_tbl,
.current_speed = &(struct clkctl_acpu_speed){ 0 },
.bus_scale = &bus_client_pdata,
- /* FIXME regulator doesn't support corners yet */
- .vdd_max_cpu = 1150000,
+ .vdd_max_cpu = CPR_CORNER_TURBO,
.vdd_max_mem = 1150000,
.src_clocks = {
[PLL0].name = "gpll0",
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 20c461d..cbb9e37 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -174,7 +174,7 @@
#define A2_PHYS_BASE 0x124C2000
#define A2_PHYS_SIZE 0x2000
#define BUFFER_SIZE 2048
-#define NUM_BUFFERS 32
+#define DEFAULT_NUM_BUFFERS 32
#ifndef A2_BAM_IRQ
#define A2_BAM_IRQ -1
@@ -194,6 +194,7 @@
static struct sps_register_event tx_register_event;
static struct sps_register_event rx_register_event;
static bool satellite_mode;
+static uint32_t num_buffers;
static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
static int bam_mux_initialized;
@@ -396,7 +397,7 @@
rx_len_cached = bam_rx_pool_len;
mutex_unlock(&bam_rx_pool_mutexlock);
- while (bam_connection_is_active && rx_len_cached < NUM_BUFFERS) {
+ while (bam_connection_is_active && rx_len_cached < num_buffers) {
if (in_global_reset)
goto fail;
@@ -1182,14 +1183,14 @@
break;
}
- buffs_used = NUM_BUFFERS - buffs_unused;
+ buffs_used = num_buffers - buffs_unused;
if (buffs_unused == 0) {
rx_timer_interval = MIN_POLLING_SLEEP;
} else {
if (buffs_used > 0) {
rx_timer_interval =
- (2 * NUM_BUFFERS *
+ (2 * num_buffers *
rx_timer_interval)/
(3 * buffs_used);
} else {
@@ -2282,15 +2283,27 @@
satellite_mode = of_property_read_bool(pdev->dev.of_node,
"qcom,satellite-mode");
- DBG("%s: base:%p size:%x irq:%d satellite:%d\n", __func__,
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,rx-ring-size",
+ &num_buffers);
+ if (rc) {
+ DBG("%s: falling back to num_buffs default, rc:%d\n",
+ __func__, rc);
+ num_buffers = DEFAULT_NUM_BUFFERS;
+ }
+
+ DBG("%s: base:%p size:%x irq:%d satellite:%d num_buffs:%d\n",
+ __func__,
a2_phys_base,
a2_phys_size,
a2_bam_irq,
- satellite_mode);
+ satellite_mode,
+ num_buffers);
} else { /* fallback to default init data */
a2_phys_base = (void *)(A2_PHYS_BASE);
a2_phys_size = A2_PHYS_SIZE;
a2_bam_irq = A2_BAM_IRQ;
+ num_buffers = DEFAULT_NUM_BUFFERS;
}
xo_clk = clk_get(&pdev->dev, "xo");
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 48abd35..42bde8f 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1887,7 +1887,7 @@
static struct gpiomux_setting mdm2ap_status_gpio_run_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_NONE,
};
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 1aa7508..bf8f895 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -243,25 +243,25 @@
static struct gpiomux_setting ap2mdm_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_4MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting mdm2ap_status_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_NONE,
};
static struct gpiomux_setting mdm2ap_errfatal_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_16MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_4MA,
.pull = GPIOMUX_PULL_DOWN,
};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1f522a1..413927c 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -1350,17 +1350,6 @@
},
};
-static struct branch_clk gcc_noc_conf_xpu_ahb_clk = {
- .cbcr_reg = NOC_CONF_XPU_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[GCC_BASE],
- .c = {
- .dbg_name = "gcc_noc_conf_xpu_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(gcc_noc_conf_xpu_ahb_clk.c),
- },
-};
-
static struct branch_clk gcc_pdm2_clk = {
.cbcr_reg = PDM2_CBCR,
.has_sibling = 0,
@@ -1574,7 +1563,6 @@
static struct measure_mux_entry measure_mux_GCC[] = {
{ &gcc_periph_noc_ahb_clk.c, GCC_BASE, 0x0010 },
- { &gcc_noc_conf_xpu_ahb_clk.c, GCC_BASE, 0x0018 },
{ &gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030 },
{ &gcc_mss_q6_bimc_axi_clk.c, GCC_BASE, 0x0031 },
{ &gcc_usb_hsic_ahb_clk.c, GCC_BASE, 0x0058 },
@@ -2817,6 +2805,13 @@
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mss_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_wlan_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &xo.c);
+
+
#ifdef CONFIG_DEBUG_FS
static int measure_clk_set_parent(struct clk *c, struct clk *parent)
{
@@ -3027,20 +3022,20 @@
CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
/* PIL-LPASS */
- CLK_LOOKUP("xo", xo.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("xo", cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("reg_clk", q6ss_ahbm_clk.c, "fe200000.qcom,lpass"),
/* PIL-MODEM */
- CLK_LOOKUP("xo", xo.c, "fc880000.qcom,mss"),
+ CLK_LOOKUP("xo", cxo_pil_mss_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
/* PIL-PRONTO */
- CLK_LOOKUP("xo", xo.c, "fb21b000.qcom,pronto"),
+ CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
/* PIL-VENUS */
CLK_LOOKUP("src_clk", vcodec0_clk_src.c, "fdce0000.qcom,venus"),
@@ -3055,8 +3050,8 @@
CLK_LOOKUP("a7sspll", a7sspll.c, "f9011050.qcom,acpuclk"),
/* WCNSS CLOCKS */
- CLK_LOOKUP("xo", xo.c, "fb000000.qcom,wcnss-wlan"),
- CLK_LOOKUP("rf_clk", cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("xo", cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("rf_clk", cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
/* BUS DRIVER */
CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
@@ -3141,7 +3136,7 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
/* HSUSB-OTG Clocks */
- CLK_LOOKUP("xo", xo.c, "f9a55000.usb"),
+ CLK_LOOKUP("xo", cxo_otg_clk.c, "f9a55000.usb"),
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index a645e9c..b7c46b4 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -345,9 +345,6 @@
#define gpll0_mm_source_val 5
#define gcc_xo_mm_source_val 0
#define mm_gnd_source_val 6
-#define cxo_lpass_source_val 0
-#define lpapll0_lpass_source_val 1
-#define gpll0_lpass_source_val 5
#define dsipll_mm_source_val 1
#define F(f, s, div, m, n) \
@@ -404,17 +401,6 @@
| BVAL(10, 8, s##_mm_source_val), \
}
-#define F_LPASS(f, s, div, m, n) \
- { \
- .freq_hz = (f), \
- .src_clk = &s##_clk_src.c, \
- .m_val = (m), \
- .n_val = ~((n)-(m)) * !!(n), \
- .d_val = ~(n),\
- .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
- | BVAL(10, 8, s##_lpass_source_val), \
- }
-
#define VDD_DIG_FMAX_MAP1(l1, f1) \
.vdd_class = &vdd_dig, \
.fmax = (unsigned long[VDD_DIG_NUM]) { \
@@ -672,21 +658,6 @@
.base = &virt_bases[MMSS_BASE],
};
-static struct pll_vote_clk lpapll0_clk_src = {
- .en_reg = (void __iomem *)LPA_PLL_VOTE_APPS,
- .en_mask = BIT(0),
- .status_reg = (void __iomem *)LPAAUDIO_PLL_STATUS,
- .status_mask = BIT(17),
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &gcc_xo_clk_src.c,
- .rate = 491520000,
- .dbg_name = "lpapll0_clk_src",
- .ops = &clk_ops_pll_vote,
- CLK_INIT(lpapll0_clk_src.c),
- },
-};
-
static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
F( 960000, gcc_xo, 10, 1, 2),
F( 4800000, gcc_xo, 4, 0, 0),
@@ -2227,197 +2198,6 @@
},
};
-static struct clk_freq_tbl ftbl_audio_core_lpaif_clk[] = {
- F_LPASS( 512000, lpapll0, 16, 1, 60),
- F_LPASS( 768000, lpapll0, 16, 1, 40),
- F_LPASS( 1024000, lpapll0, 16, 1, 30),
- F_LPASS( 1536000, lpapll0, 16, 1, 20),
- F_LPASS( 2048000, lpapll0, 16, 1, 15),
- F_LPASS( 3072000, lpapll0, 16, 1, 10),
- F_LPASS( 4096000, lpapll0, 15, 1, 8),
- F_LPASS( 6144000, lpapll0, 10, 1, 8),
- F_LPASS( 8192000, lpapll0, 15, 1, 4),
- F_LPASS(12288000, lpapll0, 10, 1, 4),
- F_END,
-};
-
-static struct rcg_clk lpaif_pri_clk_src = {
- .cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pri_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_pri_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_quad_clk_src = {
- .cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_quad_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_quad_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_sec_clk_src = {
- .cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_sec_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_sec_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_spkr_clk_src = {
- .cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_spkr_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_spkr_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_ter_clk_src = {
- .cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_ter_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_ter_clk_src.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_pcm0_1_clk[] = {
- F_LPASS( 512000, lpapll0, 16, 1, 60),
- F_LPASS( 768000, lpapll0, 16, 1, 40),
- F_LPASS(1024000, lpapll0, 16, 1, 30),
- F_LPASS(1536000, lpapll0, 16, 1, 20),
- F_LPASS(2048000, lpapll0, 16, 1, 15),
- F_LPASS(3072000, lpapll0, 16, 1, 10),
- F_LPASS(4096000, lpapll0, 15, 1, 8),
- F_LPASS(6144000, lpapll0, 10, 1, 8),
- F_LPASS(8192000, lpapll0, 15, 1, 4),
- F_END,
-};
-
-static struct rcg_clk lpaif_pcm0_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pcm0_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
- CLK_INIT(lpaif_pcm0_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_pcm1_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pcm1_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
- CLK_INIT(lpaif_pcm1_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_pcmoe_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCMOE_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pcmoe_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 6140000, NOMINAL, 12290000),
- CLK_INIT(lpaif_pcmoe_clk_src.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
- F_LPASS(24576000, lpapll0, 4, 1, 5),
- F_END
-};
-
-static struct rcg_clk audio_core_slimbus_core_clk_src = {
- .cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_slimbus_core_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_slimbus_core_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12935000, NOMINAL, 25869000),
- CLK_INIT(audio_core_slimbus_core_clk_src.c),
- },
-};
-
-static struct branch_clk audio_core_slimbus_core_clk = {
- .cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_slimbus_core_clk_src.c,
- .dbg_name = "audio_core_slimbus_core_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_slimbus_core_clk.c),
- },
-};
-
-static struct branch_clk audio_core_ixfabric_clk = {
- .cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_ixfabric_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_ixfabric_clk.c),
- },
-};
-
-static struct branch_clk audio_wrapper_br_clk = {
- .cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_wrapper_br_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_wrapper_br_clk.c),
- },
-};
-
static struct branch_clk q6ss_ahb_lfabif_clk = {
.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
.has_sibling = 1,
@@ -2453,244 +2233,6 @@
},
};
-static struct branch_clk audio_core_lpaif_pcm_data_oe_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_pcmoe_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm_data_oe_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm_data_oe_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
- .has_sibling = 0,
- .max_div = 511,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_pri_clk_src.c,
- .dbg_name = "audio_core_lpaif_pri_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_pri_clk_src.c,
- .dbg_name = "audio_core_lpaif_pri_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_pcm0_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
- .has_sibling = 0,
- .max_div = 511,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_quad_clk_src.c,
- .dbg_name = "audio_core_lpaif_quad_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_quad_clk_src.c,
- .dbg_name = "audio_core_lpaif_quad_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
- .has_sibling = 0,
- .max_div = 511,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_sec_clk_src.c,
- .dbg_name = "audio_core_lpaif_sec_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_sec_clk_src.c,
- .dbg_name = "audio_core_lpaif_sec_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_pcm1_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 511,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_spkr_clk_src.c,
- .dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_spkr_clk_src.c,
- .dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
- .has_sibling = 0,
- .max_div = 511,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_ter_clk_src.c,
- .dbg_name = "audio_core_lpaif_ter_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &lpaif_ter_clk_src.c,
- .dbg_name = "audio_core_lpaif_ter_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
- },
-};
-
#ifdef CONFIG_DEBUG_FS
struct measure_mux_entry {
@@ -2781,20 +2323,9 @@
{ &csi1pix_clk.c, MMSS_BASE, 0x0025},
{ &bimc_gfx_clk.c, MMSS_BASE, 0x0032},
- { &lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
- { &lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
- { &lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
- { &lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
- { &lpaif_ter_clk_src.c, LPASS_BASE, 0x0015},
- { &lpaif_sec_clk_src.c, LPASS_BASE, 0x0016},
- { &lpaif_pri_clk_src.c, LPASS_BASE, 0x0017},
- { &lpaif_spkr_clk_src.c, LPASS_BASE, 0x0018},
{ &q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
{ &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
- { &audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
{ &q6ss_xo_clk.c, LPASS_BASE, 0x002b},
- {&audio_core_lpaif_pcm_data_oe_clk.c, LPASS_BASE, 0x0030},
- { &audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
{&apc0_m_clk, APCS_BASE, 0x10},
{&apc1_m_clk, APCS_BASE, 0x11},
@@ -3232,40 +2763,6 @@
"fd010000.qcom,iommu"),
CLK_LOOKUP("core_clk", pnoc_iommu_clk.c, "fd010000.qcom,iommu"),
- CLK_LOOKUP("core_clk_src", lpaif_pri_clk_src.c, ""),
- CLK_LOOKUP("core_clk_src", lpaif_quad_clk_src.c, ""),
- CLK_LOOKUP("core_clk_src", lpaif_sec_clk_src.c, ""),
- CLK_LOOKUP("core_clk_src", lpaif_spkr_clk_src.c, ""),
- CLK_LOOKUP("core_clk_src", lpaif_ter_clk_src.c, ""),
- CLK_LOOKUP("core_clk_src", lpaif_pcm0_clk_src.c, ""),
- CLK_LOOKUP("core_clk_src", lpaif_pcm1_clk_src.c, ""),
- CLK_LOOKUP("core_clk_src", lpaif_pcmoe_clk_src.c, ""),
- CLK_LOOKUP("core_clk", audio_core_ixfabric_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_wrapper_br_clk.c, ""),
- CLK_LOOKUP("core_clk", q6ss_ahb_lfabif_clk.c, ""),
- CLK_LOOKUP("core_clk", q6ss_ahbm_clk.c, ""),
- CLK_LOOKUP("core_clk", q6ss_xo_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm_data_oe_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pri_osr_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_quad_osr_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_sec_osr_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_ter_osr_clk.c, ""),
-
CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
@@ -3316,32 +2813,6 @@
.size = ARRAY_SIZE(msm_clocks_8610_rumi),
};
-static struct pll_config_regs gpll0_regs __initdata = {
- .l_reg = (void __iomem *)GPLL0_L_VAL,
- .m_reg = (void __iomem *)GPLL0_M_VAL,
- .n_reg = (void __iomem *)GPLL0_N_VAL,
- .config_reg = (void __iomem *)GPLL0_USER_CTL,
- .mode_reg = (void __iomem *)GPLL0_MODE,
- .base = &virt_bases[GCC_BASE],
-};
-
-/* GPLL0 at 600 MHz, main output enabled. */
-static struct pll_config gpll0_config __initdata = {
- .l = 0x1f,
- .m = 0x1,
- .n = 0x4,
- .vco_val = 0x0,
- .vco_mask = BM(21, 20),
- .pre_div_val = 0x0,
- .pre_div_mask = BM(14, 12),
- .post_div_val = 0x0,
- .post_div_mask = BM(9, 8),
- .mn_ena_val = BIT(24),
- .mn_ena_mask = BIT(24),
- .main_output_val = BIT(0),
- .main_output_mask = BIT(0),
-};
-
/* MMPLL0 at 800 MHz, main output enabled. */
static struct pll_config mmpll0_config __initdata = {
.l = 0x29,
@@ -3376,32 +2847,6 @@
.main_output_mask = BIT(0),
};
-static struct pll_config_regs lpapll0_regs __initdata = {
- .l_reg = (void __iomem *)LPAAUDIO_PLL_L_VAL,
- .m_reg = (void __iomem *)LPAAUDIO_PLL_M_VAL,
- .n_reg = (void __iomem *)LPAAUDIO_PLL_N_VAL,
- .config_reg = (void __iomem *)LPAAUDIO_PLL_USER_CTL,
- .mode_reg = (void __iomem *)LPAAUDIO_PLL_MODE,
- .base = &virt_bases[LPASS_BASE],
-};
-
-/* LPAPLL0 at 491.52 MHz, main output enabled. */
-static struct pll_config lpapll0_config __initdata = {
- .l = 0x33,
- .m = 0x1,
- .n = 0x5,
- .vco_val = 0x0,
- .vco_mask = BM(21, 20),
- .pre_div_val = BVAL(14, 12, 0x1),
- .pre_div_mask = BM(14, 12),
- .post_div_val = 0x0,
- .post_div_mask = BM(9, 8),
- .mn_ena_val = BIT(24),
- .mn_ena_mask = BIT(24),
- .main_output_val = BIT(0),
- .main_output_mask = BIT(0),
-};
-
#define PLL_AUX_OUTPUT_BIT 1
#define PLL_AUX2_OUTPUT_BIT 2
@@ -3421,21 +2866,10 @@
static void __init reg_init(void)
{
- u32 regval, status;
- int ret;
-
- if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS))
- & gpll0_clk_src.status_mask))
- configure_sr_hpm_lp_pll(&gpll0_config, &gpll0_regs, 1);
+ u32 regval;
configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
- configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
-
- /* Enable GPLL0's aux outputs. */
- regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL));
- regval |= BIT(PLL_AUX_OUTPUT_BIT) | BIT(PLL_AUX2_OUTPUT_BIT);
- writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL));
/* Vote for GPLL0 to turn on. Needed by acpuclock. */
regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
@@ -3447,31 +2881,6 @@
* register.
*/
writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
-
- /*
- * TODO: The following sequence enables the LPASS audio core GDSC.
- * Remove when this becomes unnecessary.
- */
-
- /*
- * Disable HW trigger: collapse/restore occur based on registers writes.
- * Disable SW override: Use hardware state-machine for sequencing.
- */
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
-
- /* Configure wait time between states. */
- regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
- regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~BIT(0);
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
- status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
- WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
}
static void __init msm8610_clock_post_init(void)
@@ -3489,8 +2898,6 @@
clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&mclk0_clk_src.c, mclk0_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
- clk_set_rate(&audio_core_slimbus_core_clk_src.c,
- audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
}
#define GCC_CC_PHYS 0xFC400000
@@ -3567,11 +2974,6 @@
/* TODO: Remove this once the bus driver is in place */
clk_set_rate(&axi_clk_src.c, 200000000);
clk_prepare_enable(&mmss_s0_axi_clk.c);
-
- /* TODO: Temporarily enable a clock to allow access to LPASS core
- * registers.
- */
- clk_prepare_enable(&audio_core_ixfabric_clk.c);
}
static int __init msm8610_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 2879b49..8bdc496 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -32,7 +32,7 @@
* When enabling/disabling a clock, check the halt bit up to this number
* number of times (with a 1 us delay in between) before continuing.
*/
-#define HALT_CHECK_MAX_LOOPS 200
+#define HALT_CHECK_MAX_LOOPS 500
/* For clock without halt checking, wait this long after enables/disables. */
#define HALT_CHECK_DELAY_US 10
@@ -40,7 +40,7 @@
* When updating an RCG configuration, check the update bit up to this number
* number of times (with a 1 us delay in between) before continuing.
*/
-#define UPDATE_CHECK_MAX_LOOPS 200
+#define UPDATE_CHECK_MAX_LOOPS 500
DEFINE_SPINLOCK(local_clock_reg_lock);
struct clk_freq_tbl rcg_dummy_freq = F_END;
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
index e7eca7b..f2c8d58 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.c
+++ b/arch/arm/mach-msm/clock-mdss-8226.c
@@ -111,7 +111,7 @@
static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
{
if (pll_initialized) {
- pll_pclk_rate = (rate * 3) / 2;
+ pll_pclk_rate = rate;
pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
return 0;
} else {
@@ -148,7 +148,7 @@
REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
- REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+ REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 8e7f1fa..d866874 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -193,7 +193,7 @@
static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
{
if (pll_initialized) {
- pll_pclk_rate = (rate * 3) / 2;
+ pll_pclk_rate = rate;
pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
return 0;
} else {
@@ -230,7 +230,7 @@
REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
- REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+ REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 51d895a..13041b1 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -80,12 +80,14 @@
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- if (v->is_branch)
- return 0;
-
mutex_lock(&voter_clk_lock);
parent = clk->parent;
+ if (v->is_branch) {
+ v->enabled = true;
+ goto out;
+ }
+
/*
* Increase the rate if this clock is voting for a higher rate
* than the current rate.
@@ -109,8 +111,6 @@
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- if (v->is_branch)
- return;
mutex_lock(&voter_clk_lock);
parent = clk->parent;
@@ -120,12 +120,16 @@
* the highest rate.
*/
v->enabled = false;
+ if (v->is_branch)
+ goto out;
+
new_rate = voter_clk_aggregate_rate(parent);
cur_rate = max(new_rate, clk->rate);
if (new_rate < cur_rate)
clk_set_rate(parent, new_rate);
+out:
mutex_unlock(&voter_clk_lock);
}
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
new file mode 100644
index 0000000..4e95e4e
--- /dev/null
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/cpr-regulator.h>
+
+struct cpr_regulator {
+ struct regulator_desc rdesc;
+ struct regulator_dev *rdev;
+ bool enabled;
+ int corner;
+
+ /* Process voltage parameters */
+ phys_addr_t efuse_phys;
+ u32 num_efuse_bits;
+ u32 efuse_bit_pos[CPR_PVS_EFUSE_BITS_MAX];
+ u32 pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
+ u32 pvs_corner_ceiling[NUM_APC_PVS][CPR_CORNER_MAX];
+ /* Process voltage variables */
+ u32 pvs_bin;
+ u32 pvs_process;
+ u32 *process_vmax;
+
+ /* APC voltage regulator */
+ struct regulator *vdd_apc;
+};
+
+static int cpr_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+
+ return cpr_vreg->enabled;
+}
+
+static int cpr_regulator_enable(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = regulator_enable(cpr_vreg->vdd_apc);
+ if (!rc)
+ cpr_vreg->enabled = true;
+ return rc;
+}
+
+static int cpr_regulator_disable(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = regulator_disable(cpr_vreg->vdd_apc);
+ if (!rc)
+ cpr_vreg->enabled = false;
+ return rc;
+}
+
+static int cpr_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+ int rc;
+ int vdd_apc_min, vdd_apc_max;
+
+ vdd_apc_min = cpr_vreg->process_vmax[min_uV];
+ vdd_apc_max = cpr_vreg->process_vmax[CPR_CORNER_SUPER_TURBO];
+ rc = regulator_set_voltage(cpr_vreg->vdd_apc,
+ vdd_apc_min, vdd_apc_max);
+ if (!rc)
+ cpr_vreg->corner = min_uV;
+
+ pr_debug("set [corner:%d] = %d uV: rc=%d\n", min_uV, vdd_apc_min, rc);
+ return rc;
+}
+
+static int cpr_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+
+ return cpr_vreg->corner;
+}
+
+static struct regulator_ops cpr_corner_ops = {
+ .enable = cpr_regulator_enable,
+ .disable = cpr_regulator_disable,
+ .is_enabled = cpr_regulator_is_enabled,
+ .set_voltage = cpr_regulator_set_voltage,
+ .get_voltage = cpr_regulator_get_voltage,
+};
+
+static int __init cpr_regulator_pvs_init(struct cpr_regulator *cpr_vreg)
+{
+ void __iomem *efuse_base;
+ u32 efuse_bits;
+ int i, bit_pos;
+ u32 vmax;
+
+ efuse_base = ioremap(cpr_vreg->efuse_phys, 4);
+ if (!efuse_base) {
+ pr_err("Unable to map efuse_phys 0x%x\n",
+ cpr_vreg->efuse_phys);
+ return -EINVAL;
+ }
+
+ efuse_bits = readl_relaxed(efuse_base);
+
+ /* Construct PVS process # from the efuse bits */
+ for (i = 0; i < cpr_vreg->num_efuse_bits; i++) {
+ bit_pos = cpr_vreg->efuse_bit_pos[i];
+ cpr_vreg->pvs_bin |= (efuse_bits & BIT(bit_pos)) ? BIT(i) : 0;
+ }
+
+ cpr_vreg->pvs_process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
+ if (cpr_vreg->pvs_process >= NUM_APC_PVS)
+ cpr_vreg->pvs_process = APC_PVS_NO;
+
+ /* Use ceiling voltage of Turbo@Slow for all corners of APC_PVS_NO
+ but use SuperTurbo@Slow for its SuperTurbo */
+ vmax = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_TURBO];
+ for (i = CPR_CORNER_SVS; i <= CPR_CORNER_TURBO; i++)
+ cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][i] = vmax;
+ cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][CPR_CORNER_SUPER_TURBO]
+ = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW]
+ [CPR_CORNER_SUPER_TURBO];
+
+ cpr_vreg->process_vmax =
+ cpr_vreg->pvs_corner_ceiling[cpr_vreg->pvs_process];
+
+ iounmap(efuse_base);
+
+ pr_info("PVS Info: efuse_phys=0x%08X, n_bits=%d\n",
+ cpr_vreg->efuse_phys, cpr_vreg->num_efuse_bits);
+ pr_info("PVS Info: efuse=0x%08X, bin=%d, process=%d\n",
+ efuse_bits, cpr_vreg->pvs_bin, cpr_vreg->pvs_process);
+
+ return 0;
+}
+
+static int __init cpr_regulator_apc_init(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ cpr_vreg->vdd_apc = devm_regulator_get(&pdev->dev, "vdd-apc");
+ if (IS_ERR_OR_NULL(cpr_vreg->vdd_apc)) {
+ pr_err("devm_regulator_get: rc=%d\n",
+ (int)PTR_ERR(cpr_vreg->vdd_apc));
+ }
+
+ return PTR_RET(cpr_vreg->vdd_apc);
+}
+
+static void cpr_regulator_apc_exit(struct cpr_regulator *cpr_vreg)
+{
+ if (cpr_vreg->enabled)
+ regulator_disable(cpr_vreg->vdd_apc);
+}
+
+static int __init cpr_regulator_parse_dt(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ struct resource *res;
+ int rc;
+ size_t pvs_bins;
+
+ /* Parse process voltage parameters */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "efuse_phys");
+ if (!res || !res->start) {
+ pr_err("efuse_phys missing: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->efuse_phys = res->start;
+
+ rc = of_property_read_u32(of_node, "qcom,num-efuse-bits",
+ &cpr_vreg->num_efuse_bits);
+ if (rc < 0) {
+ pr_err("num-efuse-bits missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ if (cpr_vreg->num_efuse_bits == 0 ||
+ cpr_vreg->num_efuse_bits > CPR_PVS_EFUSE_BITS_MAX) {
+ pr_err("invalid num-efuse-bits : %d\n",
+ cpr_vreg->num_efuse_bits);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(of_node, "qcom,efuse-bit-pos",
+ cpr_vreg->efuse_bit_pos,
+ cpr_vreg->num_efuse_bits);
+ if (rc < 0) {
+ pr_err("efuse-bit-pos missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ pvs_bins = 1 << cpr_vreg->num_efuse_bits;
+ rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
+ cpr_vreg->pvs_bin_process,
+ pvs_bins);
+ if (rc < 0) {
+ pr_err("pvs-bin-process missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-corner-ceiling-slow",
+ &cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-corner-ceiling-nom",
+ &cpr_vreg->pvs_corner_ceiling[APC_PVS_NOM][CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-corner-ceiling-fast",
+ &cpr_vreg->pvs_corner_ceiling[APC_PVS_FAST][CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __devinit cpr_regulator_probe(struct platform_device *pdev)
+{
+ struct cpr_regulator *cpr_vreg;
+ struct regulator_desc *rdesc;
+ struct regulator_init_data *init_data = pdev->dev.platform_data;
+ int rc;
+
+ if (!pdev->dev.of_node) {
+ pr_err("Device tree node is missing\n");
+ return -EINVAL;
+ }
+
+ init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+ if (!init_data) {
+ pr_err("regulator init data is missing\n");
+ return -EINVAL;
+ } else {
+ init_data->constraints.input_uV
+ = init_data->constraints.max_uV;
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
+ }
+
+ cpr_vreg = devm_kzalloc(&pdev->dev, sizeof(struct cpr_regulator),
+ GFP_KERNEL);
+ if (!cpr_vreg) {
+ pr_err("Can't allocate cpr_regulator memory\n");
+ return -ENOMEM;
+ }
+
+ rc = cpr_regulator_parse_dt(pdev, cpr_vreg);
+ if (rc) {
+ pr_err("Wrong DT parameter specified: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr_regulator_pvs_init(cpr_vreg);
+ if (rc) {
+ pr_err("Initialize PVS wrong: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr_regulator_apc_init(pdev, cpr_vreg);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ pr_err("Initialize APC wrong: rc=%d\n", rc);
+ return rc;
+ }
+
+ rdesc = &cpr_vreg->rdesc;
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->ops = &cpr_corner_ops;
+ rdesc->name = init_data->constraints.name;
+
+ cpr_vreg->rdev = regulator_register(rdesc, &pdev->dev, init_data,
+ cpr_vreg, pdev->dev.of_node);
+ if (IS_ERR(cpr_vreg->rdev)) {
+ rc = PTR_ERR(cpr_vreg->rdev);
+ pr_err("regulator_register failed: rc=%d\n", rc);
+
+ cpr_regulator_apc_exit(cpr_vreg);
+ return rc;
+ }
+
+ platform_set_drvdata(pdev, cpr_vreg);
+
+ pr_info("PVS [%d %d %d %d] uV\n",
+ cpr_vreg->process_vmax[CPR_CORNER_SVS],
+ cpr_vreg->process_vmax[CPR_CORNER_NORMAL],
+ cpr_vreg->process_vmax[CPR_CORNER_TURBO],
+ cpr_vreg->process_vmax[CPR_CORNER_SUPER_TURBO]);
+
+ return 0;
+}
+
+static int __devexit cpr_regulator_remove(struct platform_device *pdev)
+{
+ struct cpr_regulator *cpr_vreg;
+
+ cpr_vreg = platform_get_drvdata(pdev);
+ if (cpr_vreg) {
+ cpr_regulator_apc_exit(cpr_vreg);
+ regulator_unregister(cpr_vreg->rdev);
+ }
+
+ return 0;
+}
+
+static struct of_device_id cpr_regulator_match_table[] = {
+ { .compatible = CPR_REGULATOR_DRIVER_NAME, },
+ {}
+};
+
+static struct platform_driver cpr_regulator_driver = {
+ .driver = {
+ .name = CPR_REGULATOR_DRIVER_NAME,
+ .of_match_table = cpr_regulator_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = cpr_regulator_probe,
+ .remove = __devexit_p(cpr_regulator_remove),
+};
+
+/**
+ * cpr_regulator_init() - register cpr-regulator driver
+ *
+ * This initialization function should be called in systems in which driver
+ * registration ordering must be controlled precisely.
+ */
+int __init cpr_regulator_init(void)
+{
+ static bool initialized;
+
+ if (initialized)
+ return 0;
+ else
+ initialized = true;
+
+ return platform_driver_register(&cpr_regulator_driver);
+}
+EXPORT_SYMBOL(cpr_regulator_init);
+
+static void __exit cpr_regulator_exit(void)
+{
+ platform_driver_unregister(&cpr_regulator_driver);
+}
+
+MODULE_DESCRIPTION("CPR regulator driver");
+MODULE_LICENSE("GPL v2");
+
+arch_initcall(cpr_regulator_init);
+module_exit(cpr_regulator_exit);
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index d4c33e3..e70a0a8 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1093,6 +1093,7 @@
.num_iommu_table = 2,
.load_table = vidc_v4l2_load_table,
.num_load_table = 2,
+ .max_load = 800*480*30/256,
};
struct platform_device msm_device_vidc_v4l2 = {
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 6240195..e5b9d93 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -36,7 +36,7 @@
#define EN_FEW_WAIT_VAL (0x8 << 16)
#define CLK_DIS_WAIT_VAL (0x2 << 12)
-#define TIMEOUT_US 10
+#define TIMEOUT_US 100
struct gdsc {
struct regulator_dev *rdev;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 3fa2d5e..35257b2 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -567,6 +567,8 @@
*/
int64_t **load_table;
int num_load_table;
+
+ uint32_t max_load;
};
struct vcap_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 8fd3cfc..ef835b8 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -102,9 +102,8 @@
int msm_bus_board_rpm_get_il_ids(uint16_t *id);
int msm_bus_board_get_iid(int id);
-#ifdef CONFIG_ARCH_MSM8226
-#define NFAB 6
-#endif
+#define NFAB_MSM8226 6
+#define NFAB_MSM8610 5
/*
* These macros specify the convention followed for allocating
@@ -302,6 +301,7 @@
MSM_BUS_MASTER_V_OCMEM_GFX3D,
MSM_BUS_MASTER_IPA,
MSM_BUS_MASTER_QPIC,
+ MSM_BUS_MASTER_MDPE,
MSM_BUS_MASTER_LAST,
@@ -459,6 +459,7 @@
MSM_BUS_SLAVE_SERVICE_CNOC,
MSM_BUS_SLAVE_IPS_CFG,
MSM_BUS_SLAVE_QPIC,
+ MSM_BUS_SLAVE_DSI_CFG,
MSM_BUS_SLAVE_LAST,
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index cf59dd8..c20576a 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1261,7 +1261,7 @@
*
*/
int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
- u32 tb_sel, u8 desc_sel);
+ u32 tb_sel, u32 desc_sel);
#else
static inline int sps_register_bam_device(const struct sps_bam_props
@@ -1421,7 +1421,7 @@
}
static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
- u32 tb_sel, u8 pre_level)
+ u32 tb_sel, u32 desc_sel)
{
return -EPERM;
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index a50a37d..cafcdd2 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -48,7 +48,7 @@
#define IPC_ROUTER_XPRT_EVENT_CLOSE 3
#define IPC_ROUTER_INFINITY -1
-#define DEFAULT_RCV_TIMEO IPC_ROUTER_INFINITY
+#define DEFAULT_RCV_TIMEO 0
#define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 16b60a1..f40bd5d 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -414,7 +414,7 @@
}
if (timeout == 0)
- return -ETIMEDOUT;
+ return 0;
lock_sock(sk);
mutex_lock(&port_ptr->port_rx_q_lock);
}
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 9f06cf6..c8d6d5a 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -161,9 +161,11 @@
*/
pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
msleep(1000);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
- }
+ } else
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
goto start_mdm_peripheral;
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 03d158e..de46be8 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -649,7 +649,7 @@
}
}
- gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index 2ee07f3..ebc0c3a 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -15,4 +15,5 @@
obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o
obj-$(CONFIG_ARCH_MSM9625) += msm_bus_board_9625.o
obj-$(CONFIG_ARCH_MSM8226) += msm_bus_id.o
+obj-$(CONFIG_ARCH_MSM8610) += msm_bus_id.o
obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 9201398..fd2dbb5 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -182,7 +182,7 @@
};
struct msm_bus_board_algorithm {
- const int board_nfab;
+ int board_nfab;
void (*assign_iids)(struct msm_bus_fabric_registration *fabreg,
int fabid);
int (*get_iid)(int id);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_id.c b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
index 693c51e..7e9883f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_id.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
@@ -19,6 +19,7 @@
#include <mach/msm_bus_board.h>
#include <mach/board.h>
#include <mach/rpm.h>
+#include <mach/socinfo.h>
#include "msm_bus_core.h"
#include "msm_bus_noc.h"
#include "msm_bus_bimc.h"
@@ -67,7 +68,6 @@
static struct msm_bus_board_algorithm msm_bus_id_algo = {
- .board_nfab = NFAB,
.get_iid = msm_bus_get_iid,
.assign_iids = msm_bus_assign_iids,
};
@@ -79,5 +79,10 @@
void msm_bus_board_init(struct msm_bus_fabric_registration *pdata)
{
+ if (machine_is_msm8226())
+ msm_bus_id_algo.board_nfab = NFAB_MSM8226;
+ else if (machine_is_msm8610())
+ msm_bus_id_algo.board_nfab = NFAB_MSM8610;
+
pdata->board_algo = &msm_bus_id_algo;
}
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index 1589623..f70022e 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -213,7 +213,9 @@
switch (val) {
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
+ case PM_POST_RESTORE:
rq_info.hotplug_disabled = 0;
+ break;
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
rq_info.hotplug_disabled = 1;
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index ef10cdc..4778d5b 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -568,6 +568,6 @@
return platform_driver_register(&msm_watchdog_driver);
}
-late_initcall(init_watchdog);
+pure_initcall(init_watchdog);
MODULE_DESCRIPTION("MSM Watchdog Driver");
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 868fd1a..8afe695 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -377,6 +377,7 @@
static int destroy_region(struct ocmem_region *region)
{
+ idr_destroy(®ion->region_idr);
kfree(region);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 6bd087c..edaa60c 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -25,6 +25,7 @@
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/wcnss_wlan.h>
+#include <linux/of_gpio.h>
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
@@ -82,6 +83,8 @@
bool crash;
struct delayed_work cancel_vote_work;
int irq;
+ unsigned int err_fatal_irq;
+ int force_stop_gpio;
struct ramdump_device *ramdump_dev;
};
@@ -302,25 +305,22 @@
subsystem_restart_dev(drv->subsys);
}
-static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
- uint32_t new_state)
+static irqreturn_t wcnss_err_fatal_intr_handler(int irq, void *dev_id)
{
- struct pronto_data *drv = data;
+ struct pronto_data *drv = dev_id;
+
+ pr_err("Fatal error on the wcnss.\n");
drv->crash = true;
-
- pr_err("wcnss smsm state changed\n");
-
- if (!(new_state & SMSM_RESET))
- return;
-
if (drv->restart_inprogress) {
- pr_err("wcnss: Ignoring smsm reset req, restart in progress\n");
- return;
+ pr_err("wcnss: Ignoring error fatal, restart in progress\n");
+ return IRQ_HANDLED;
}
drv->restart_inprogress = true;
restart_wcnss(drv);
+
+ return IRQ_HANDLED;
}
static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
@@ -389,7 +389,7 @@
pr_err("wcnss crash shutdown %d\n", drv->crash);
if (!drv->crash)
- smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+ gpio_set_value(drv->force_stop_gpio, 1);
}
static int wcnss_ramdump(int enable, const struct subsys_desc *subsys)
@@ -407,7 +407,7 @@
struct pronto_data *drv;
struct resource *res;
struct pil_desc *desc;
- int ret;
+ int ret, err_fatal_gpio, irq;
uint32_t regval;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -440,6 +440,23 @@
if (ret)
return ret;
+ err_fatal_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-fatal", 0);
+ if (err_fatal_gpio < 0)
+ return err_fatal_gpio;
+
+ irq = gpio_to_irq(err_fatal_gpio);
+ if (irq < 0)
+ return irq;
+
+ drv->err_fatal_irq = irq;
+
+ drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-force-stop", 0);
+ if (drv->force_stop_gpio < 0)
+ return drv->force_stop_gpio;
+
+
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
desc->proxy_timeout = 10000;
@@ -478,11 +495,6 @@
if (ret)
return ret;
- ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
- smsm_state_cb_hdlr, drv);
- if (ret < 0)
- goto err_smsm;
-
drv->subsys_desc.name = desc->name;
drv->subsys_desc.dev = &pdev->dev;
drv->subsys_desc.owner = THIS_MODULE;
@@ -506,6 +518,14 @@
if (ret < 0)
goto err_irq;
+ ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
+ wcnss_err_fatal_intr_handler,
+ IRQF_TRIGGER_RISING, "pil-pronto", drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to register SMP2P err fatal handler!\n");
+ goto err_irq;
+ }
+
drv->ramdump_dev = create_ramdump_device("pronto", &pdev->dev);
if (!drv->ramdump_dev) {
ret = -ENOMEM;
@@ -520,12 +540,10 @@
writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
return 0;
+
err_irq:
subsys_unregister(drv->subsys);
err_subsys:
- smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
- smsm_state_cb_hdlr, drv);
-err_smsm:
pil_desc_release(desc);
return ret;
}
@@ -534,8 +552,6 @@
{
struct pronto_data *drv = platform_get_drvdata(pdev);
subsys_unregister(drv->subsys);
- smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
- smsm_state_cb_hdlr, drv);
pil_desc_release(&drv->desc);
destroy_ramdump_device(drv->ramdump_dev);
return 0;
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 599b24c..06de8cc 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -25,6 +25,7 @@
#include <linux/regulator/consumer.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
+#include <linux/dma-mapping.h>
#include <mach/subsystem_restart.h>
#include <mach/clk.h>
@@ -78,10 +79,8 @@
#define BHS_TIMEOUT_US 50
struct mba_data {
- void __iomem *metadata_base;
void __iomem *rmb_base;
void __iomem *io_clamp_reg;
- unsigned long metadata_phys;
struct pil_desc desc;
struct subsys_device *subsys;
struct subsys_desc subsys_desc;
@@ -364,18 +363,28 @@
const u8 *metadata, size_t size)
{
struct mba_data *drv = dev_get_drvdata(pil->dev);
+ void *mdata_virt;
+ dma_addr_t mdata_phys;
s32 status;
int ret;
- /* Copy metadata to assigned shared buffer location */
- memcpy(drv->metadata_base, metadata, size);
+ /* Make metadata physically contiguous and 4K aligned. */
+ mdata_virt = dma_alloc_coherent(pil->dev, size, &mdata_phys,
+ GFP_KERNEL);
+ if (!mdata_virt) {
+ dev_err(pil->dev, "MBA metadata buffer allocation failed\n");
+ return -ENOMEM;
+ }
+ memcpy(mdata_virt, metadata, size);
+ /* wmb() ensures copy completes prior to starting authentication. */
+ wmb();
/* Initialize length counter to 0 */
writel_relaxed(0, drv->rmb_base + RMB_PMI_CODE_LENGTH);
drv->img_length = 0;
/* Pass address of meta-data to the MBA and perform authentication */
- writel_relaxed(drv->metadata_phys, drv->rmb_base + RMB_PMI_META_DATA);
+ writel_relaxed(mdata_phys, drv->rmb_base + RMB_PMI_META_DATA);
writel_relaxed(CMD_META_DATA_READY, drv->rmb_base + RMB_MBA_COMMAND);
ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
@@ -388,6 +397,8 @@
ret = -EINVAL;
}
+ dma_free_coherent(pil->dev, size, mdata_virt, mdata_phys);
+
return ret;
}
@@ -716,15 +727,6 @@
drv->rmb_base = devm_request_and_ioremap(&pdev->dev, res);
if (!drv->rmb_base)
return -ENOMEM;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "metadata_base");
- if (res) {
- drv->metadata_base = devm_ioremap(&pdev->dev,
- res->start, resource_size(res));
- if (!drv->metadata_base)
- return -ENOMEM;
- drv->metadata_phys = res->start;
- }
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index 7472b46..e74fdf9 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -56,9 +56,6 @@
goto fail;
}
- /* Query the DSP to check if resources are available */
- msleep(Q6_PIL_GET_DELAY_MS);
-
/* Set the state of the ADSP in APR driver */
apr_set_q6_state(APR_SUBSYS_LOADED);
} else if (adsp_state == APR_SUBSYS_LOADED) {
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 5969a3c..8a2c23f 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -32,22 +32,36 @@
#include <mach/msm_smd.h>
#include <mach/subsystem_restart.h>
#include <mach/socinfo.h>
+#include <mach/msm_ipc_logging.h>
#include "smd_private.h"
#define MAX_SMD_TTYS 37
#define MAX_TTY_BUF_SIZE 2048
#define MAX_RA_WAKE_LOCK_NAME_LEN 32
+#define SMD_TTY_LOG_PAGES 2
+#define SMD_TTY_INFO(buf...) \
+do { \
+ if (smd_tty_log_ctx) { \
+ ipc_log_string(smd_tty_log_ctx, buf); \
+ } \
+} while (0)
+
+#define SMD_TTY_ERR(buf...) \
+do { \
+ if (smd_tty_log_ctx) \
+ ipc_log_string(smd_tty_log_ctx, buf); \
+ pr_err(buf); \
+} while (0)
+
+static void *smd_tty_log_ctx;
static DEFINE_MUTEX(smd_tty_lock);
-static uint smd_tty_modem_wait;
-module_param_named(modem_wait, smd_tty_modem_wait,
- uint, S_IRUGO | S_IWUSR | S_IWGRP);
-
struct smd_tty_info {
smd_channel_t *ch;
struct tty_port port;
+ struct device *device_ptr;
struct wake_lock wake_lock;
int open_count;
struct tasklet_struct tty_tsklt;
@@ -58,6 +72,7 @@
int in_reset;
int in_reset_updated;
int is_open;
+ unsigned int open_wait;
wait_queue_head_t ch_opened_wait_queue;
spinlock_t reset_lock;
spinlock_t ra_lock; /* Read Available Lock*/
@@ -120,6 +135,57 @@
spin_unlock_irqrestore(&info->reset_lock, flags);
}
+static ssize_t open_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned int num_dev;
+ unsigned long wait;
+ if (dev == NULL) {
+ SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+ return -EINVAL;
+ }
+ for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+ if (dev == smd_tty[num_dev].device_ptr)
+ break;
+ }
+ if (num_dev >= MAX_SMD_TTYS) {
+ SMD_TTY_ERR("[%s]: Device Not found", __func__);
+ return -EINVAL;
+ }
+ if (!kstrtoul(buf, 10, &wait)) {
+ smd_tty[num_dev].open_wait = wait;
+ return n;
+ } else {
+ SMD_TTY_INFO("[%s]: Unable to convert %s to an int",
+ __func__, buf);
+ return -EINVAL;
+ }
+}
+
+static ssize_t open_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int num_dev;
+
+ if (dev == NULL) {
+ SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+ return -EINVAL;
+ }
+ for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+ if (dev == smd_tty[num_dev].device_ptr)
+ break;
+ }
+ if (num_dev >= MAX_SMD_TTYS)
+ SMD_TTY_ERR("[%s]: Device Not Found", __func__);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ smd_tty[num_dev].open_wait);
+}
+
+static DEVICE_ATTR
+ (open_timeout, 0664, open_timeout_show, open_timeout_store);
+
static void smd_tty_read(unsigned long param)
{
unsigned char *ptr;
@@ -165,7 +231,9 @@
** context here and nobody else could 'steal' our
** characters.
*/
- printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
+ SMD_TTY_ERR(
+ "%s - Possible smd_tty_buffer mismatch for %s",
+ __func__, info->ch->name);
}
wake_lock_timeout(&info->wake_lock, HZ / 2);
@@ -270,6 +338,16 @@
if (peripheral) {
info->pil = subsystem_get(peripheral);
if (IS_ERR(info->pil)) {
+ SMD_TTY_INFO(
+ "%s failed on smd_tty device :%s subsystem_get failed for %s",
+ __func__, smd_tty[n].smd->port_name,
+ peripheral);
+ /*
+ * Sleep, inorder to reduce the frequency of
+ * retry by user-space modules and to avoid
+ * possible watchdog bite.
+ */
+ msleep((smd_tty[n].open_wait * 1000));
res = PTR_ERR(info->pil);
goto out;
}
@@ -292,21 +370,22 @@
* Wait for a channel to be allocated so we know
* the modem is ready enough.
*/
- if (smd_tty_modem_wait) {
+ if (smd_tty[n].open_wait) {
res = wait_for_completion_interruptible_timeout(
&info->ch_allocated,
- msecs_to_jiffies(smd_tty_modem_wait *
+ msecs_to_jiffies(smd_tty[n].open_wait *
1000));
if (res == 0) {
- pr_err("Timed out waiting for SMD"
- " channel\n");
+ SMD_TTY_INFO(
+ "Timed out waiting for SMD channel %s",
+ smd_tty[n].smd->port_name);
res = -ETIMEDOUT;
goto release_pil;
} else if (res < 0) {
- pr_err("Error waiting for SMD channel:"
- " %d\n",
- res);
+ SMD_TTY_INFO(
+ "Error waiting for SMD channel %s : %d\n",
+ smd_tty[n].smd->port_name, res);
goto release_pil;
}
@@ -329,8 +408,10 @@
&info->ch, info,
smd_tty_notify);
if (res < 0) {
- pr_err("%s: %s open failed %d\n", __func__,
- smd_tty[n].smd->port_name, res);
+ SMD_TTY_INFO(
+ "%s: %s open failed %d\n",
+ __func__, smd_tty[n].smd->port_name,
+ res);
goto release_pil;
}
@@ -340,12 +421,16 @@
if (res == 0)
res = -ETIMEDOUT;
if (res < 0) {
- pr_err("%s: wait for %s smd_open failed %d\n",
+ SMD_TTY_INFO(
+ "%s: wait for %s smd_open failed %d\n",
__func__, smd_tty[n].smd->port_name,
res);
goto release_pil;
}
res = 0;
+ SMD_TTY_INFO("%s with PID %u opened port %s",
+ current->comm, current->pid,
+ smd_tty[n].smd->port_name);
}
}
@@ -382,6 +467,9 @@
wake_lock_destroy(&info->wake_lock);
wake_lock_destroy(&info->ra_wake_lock);
}
+ SMD_TTY_INFO("%s with PID %u closed port %s",
+ current->comm, current->pid,
+ info->smd->port_name);
tty->driver_data = 0;
del_timer(&info->buf_req_timer);
if (info->ch) {
@@ -430,6 +518,8 @@
}
if (len > avail)
len = avail;
+ SMD_TTY_INFO("[WRITE]: PID %u -> port %s %x bytes",
+ current->pid, info->smd->port_name, len);
return smd_write(info->ch, buf, len);
}
@@ -480,6 +570,8 @@
tiocm |= TIOCM_OUT2;
info->in_reset_updated = 0;
}
+ SMD_TTY_INFO("PID %u --> %s TIOCM is %x ",
+ current->pid, __func__, tiocm);
spin_unlock_irqrestore(&info->reset_lock, flags);
return tiocm;
@@ -493,6 +585,8 @@
if (info->in_reset)
return -ENETRESET;
+ SMD_TTY_INFO("PID %u --> %s Set: %x Clear: %x",
+ current->pid, __func__, set, clear);
return smd_tiocmset(info->ch, set, clear);
}
@@ -540,11 +634,25 @@
return 0;
}
}
- pr_err("%s: unknown device '%s'\n", __func__, pdev->name);
+ SMD_TTY_ERR("[ERR]%s: unknown device '%s'\n", __func__, pdev->name);
return -ENODEV;
}
+/**
+ * smd_tty_log_init()- Init function for IPC logging
+ *
+ * Initialize the buffer that is used to provide the log information
+ * pertaining to the smd_tty module.
+ */
+static void smd_tty_log_init(void)
+{
+ smd_tty_log_ctx = ipc_log_context_create(SMD_TTY_LOG_PAGES,
+ "smd_tty");
+ if (!smd_tty_log_ctx)
+ pr_err("%s: Unable to create IPC log", __func__);
+}
+
static struct tty_driver *smd_tty_driver;
static int __init smd_tty_init(void)
@@ -554,9 +662,12 @@
int idx;
struct tty_port *port;
+ smd_tty_log_init();
smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
- if (smd_tty_driver == 0)
+ if (smd_tty_driver == 0) {
+ SMD_TTY_ERR("%s - Driver allocation failed", __func__);
return -ENOMEM;
+ }
smd_tty_driver->owner = THIS_MODULE;
smd_tty_driver->driver_name = "smd_tty_driver";
@@ -577,7 +688,7 @@
ret = tty_register_driver(smd_tty_driver);
if (ret) {
put_tty_driver(smd_tty_driver);
- pr_err("%s: driver registration failed %d\n", __func__, ret);
+ SMD_TTY_ERR("%s: driver registration failed %d", __func__, ret);
return ret;
}
@@ -612,7 +723,14 @@
tty_port_init(port);
port->ops = &smd_tty_port_ops;
/* TODO: For kernel >= 3.7 use tty_port_register_device */
- tty_register_device(smd_tty_driver, idx, 0);
+ smd_tty[idx].device_ptr =
+ tty_register_device(smd_tty_driver, idx, 0);
+ if (device_create_file(smd_tty[idx].device_ptr,
+ &dev_attr_open_timeout))
+ SMD_TTY_ERR(
+ "%s: Unable to create device attributes for %s",
+ __func__, smd_configs[n].port_name);
+
init_completion(&smd_tty[idx].ch_allocated);
/* register platform device */
@@ -628,7 +746,8 @@
ret = platform_driver_register(&smd_tty[idx].driver);
if (ret) {
- pr_err("%s: init failed %d (%d)\n", __func__, idx, ret);
+ SMD_TTY_ERR(
+ "%s: init failed %d (%d)", __func__, idx, ret);
smd_tty[idx].driver.probe = NULL;
goto out;
}
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index c8e2dd3..233c5a5 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -33,6 +33,7 @@
};
struct msm_spm_device {
+ bool initialized;
struct msm_spm_driver_data reg_data;
struct msm_spm_power_modes *modes;
uint32_t num_modes;
@@ -55,6 +56,8 @@
struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+ if (!dev->initialized)
+ return;
dev->cpu_vdd = info->vlevel;
info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
}
@@ -119,6 +122,9 @@
uint32_t start_addr = 0;
int ret = -EINVAL;
+ if (!dev->initialized)
+ return -ENXIO;
+
if (mode == MSM_SPM_MODE_DISABLED) {
ret = msm_spm_drv_set_spm_enable(&dev->reg_data, false);
} else if (!msm_spm_drv_set_spm_enable(&dev->reg_data, true)) {
@@ -170,6 +176,7 @@
dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
}
msm_spm_drv_flush_seq_entry(&dev->reg_data);
+ dev->initialized = true;
return 0;
spm_failed_init:
@@ -278,6 +285,8 @@
void msm_spm_l2_reinit(void)
{
+ if (!msm_spm_l2_device.initialized)
+ return;
msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
}
EXPORT_SYMBOL(msm_spm_l2_reinit);
@@ -288,6 +297,8 @@
*/
int msm_spm_apcs_set_vdd(unsigned int vlevel)
{
+ if (!msm_spm_l2_device.initialized)
+ return -ENXIO;
return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
}
EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
@@ -298,6 +309,8 @@
*/
int msm_spm_apcs_set_phase(unsigned int phase_cnt)
{
+ if (!msm_spm_l2_device.initialized)
+ return -ENXIO;
return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
MSM_SPM_PMIC_PHASE_PORT, phase_cnt);
}
@@ -309,6 +322,8 @@
*/
int msm_spm_enable_fts_lpm(uint32_t mode)
{
+ if (!msm_spm_l2_device.initialized)
+ return -ENXIO;
return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
MSM_SPM_PMIC_PFM_PORT, mode);
}
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 45c9023..ed91480 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -227,7 +227,7 @@
pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
(unsigned long)base, (unsigned long)size / SZ_1M);
- dma_contiguous_reserve_area(size, &base, MEMBLOCK_ALLOC_ANYWHERE, name);
+ dma_contiguous_reserve_area(size, &base, 0, name);
return 0;
}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 071dd69..9e36e1e 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -314,6 +314,9 @@
diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
diag_send_feature_mask_update(smd_info->ch, smd_info->peripheral);
+ if (smd_info->notify_context == SMD_EVENT_OPEN)
+ diag_send_diag_mode_update_by_smd(smd_info, MODE_REALTIME);
+
smd_info->notify_context = 0;
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9d9df2a..6f37608 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -20,6 +20,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
+#include <linux/wakelock.h>
#include <mach/msm_smd.h>
#include <asm/atomic.h>
#include <asm/mach-types.h>
@@ -76,6 +77,9 @@
#define DIAG_STATUS_OPEN (0x00010000) /* DCI channel open status mask */
#define DIAG_STATUS_CLOSED (0x00020000) /* DCI channel closed status mask */
+#define MODE_REALTIME 1
+#define MODE_NONREALTIME 0
+
#define NUM_SMD_DATA_CHANNELS 3
#define NUM_SMD_CONTROL_CHANNELS 3
#define NUM_SMD_DCI_CHANNELS 1
@@ -143,6 +147,14 @@
int pid;
};
+struct diag_nrt_wake_lock {
+ int enabled;
+ int ref_count;
+ int copy_count;
+ struct wake_lock read_lock;
+ spinlock_t read_spinlock;
+};
+
/* This structure is defined in USB header file */
#ifndef CONFIG_DIAG_OVER_USB
struct diag_request {
@@ -173,6 +185,8 @@
struct diag_request *write_ptr_1;
struct diag_request *write_ptr_2;
+ struct diag_nrt_wake_lock nrt_lock;
+
struct work_struct diag_read_smd_work;
struct work_struct diag_notify_update_smd_work;
int notify_context;
@@ -239,6 +253,7 @@
struct diag_ctrl_msg_mask *msg_mask;
struct diag_ctrl_feature_mask *feature_mask;
/* State for diag forwarding */
+ int real_time_mode;
struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
@@ -255,6 +270,7 @@
unsigned char *hdlc_buf;
unsigned hdlc_count;
unsigned hdlc_escape;
+ int in_busy_pktdata;
#ifdef CONFIG_DIAG_OVER_USB
int usb_connected;
struct usb_diag_ch *legacy_ch;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 65fc89f..a0c32f5 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -20,6 +20,7 @@
#include <linux/diagchar.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
+#include <linux/ratelimit.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
#endif
@@ -278,10 +279,11 @@
/* If the SD logging process exits, change logging to USB mode */
if (driver->logging_process_id == current->tgid) {
driver->logging_mode = USB_MODE;
+ diag_send_diag_mode_update(MODE_REALTIME);
diagfwd_connect();
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diag_clear_hsic_tbl();
- diagfwd_cancel_hsic();
+ diagfwd_cancel_hsic(REOPEN_HSIC);
diagfwd_connect_bridge(0);
#endif
}
@@ -707,6 +709,11 @@
diag_clear_hsic_tbl();
} else if (old_mode == NO_LOGGING_MODE && new_mode
== MEMORY_DEVICE_MODE) {
+ int i;
+ for (i = 0; i < MAX_HSIC_CH; i++)
+ if (diag_hsic[i].hsic_inited)
+ diag_hsic[i].hsic_data_requested =
+ driver->real_time_mode ? 1 : 0;
diagfwd_connect_bridge(0);
} else if (old_mode == USB_MODE && new_mode
== NO_LOGGING_MODE) {
@@ -716,12 +723,15 @@
diagfwd_connect_bridge(0);
} else if (old_mode == USB_MODE && new_mode
== MEMORY_DEVICE_MODE) {
- diagfwd_cancel_hsic();
+ if (driver->real_time_mode)
+ diagfwd_cancel_hsic(REOPEN_HSIC);
+ else
+ diagfwd_cancel_hsic(DONT_REOPEN_HSIC);
diagfwd_connect_bridge(0);
} else if (old_mode == MEMORY_DEVICE_MODE && new_mode
== USB_MODE) {
diag_clear_hsic_tbl();
- diagfwd_cancel_hsic();
+ diagfwd_cancel_hsic(REOPEN_HSIC);
diagfwd_connect_bridge(0);
}
}
@@ -770,12 +780,25 @@
int diag_switch_logging(unsigned long ioarg)
{
int i, temp, success = -EINVAL, status;
+ int temp_realtime_mode = driver->real_time_mode;
+
mutex_lock(&driver->diagchar_mutex);
temp = driver->logging_mode;
driver->logging_mode = (int)ioarg;
+
+ if (driver->logging_mode == MEMORY_DEVICE_MODE_NRT) {
+ diag_send_diag_mode_update(MODE_NONREALTIME);
+ driver->logging_mode = MEMORY_DEVICE_MODE;
+ } else {
+ diag_send_diag_mode_update(MODE_REALTIME);
+ }
+
if (temp == driver->logging_mode) {
mutex_unlock(&driver->diagchar_mutex);
- pr_err("diag: forbidden logging change requested\n");
+ if (driver->logging_mode != MEMORY_DEVICE_MODE ||
+ temp_realtime_mode)
+ pr_info_ratelimited("diag: Already in logging mode change requested, mode: %d\n",
+ driver->logging_mode);
return 0;
}
@@ -1097,6 +1120,7 @@
int num_data = 0, data_type;
int remote_token;
int exit_stat;
+ int clear_read_wakelock;
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
@@ -1111,6 +1135,7 @@
driver->data_ready[index]);
mutex_lock(&driver->diagchar_mutex);
+ clear_read_wakelock = 0;
if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
logging_mode == MEMORY_DEVICE_MODE)) {
remote_token = 0;
@@ -1172,6 +1197,10 @@
COPY_USER_SPACE_OR_EXIT(buf+ret,
*(data->buf_in_1),
data->write_ptr_1->length);
+ if (!driver->real_time_mode) {
+ process_lock_on_copy(&data->nrt_lock);
+ clear_read_wakelock++;
+ }
data->in_busy_1 = 0;
}
if (data->in_busy_2 == 1) {
@@ -1183,6 +1212,10 @@
COPY_USER_SPACE_OR_EXIT(buf+ret,
*(data->buf_in_2),
data->write_ptr_2->length);
+ if (!driver->real_time_mode) {
+ process_lock_on_copy(&data->nrt_lock);
+ clear_read_wakelock++;
+ }
data->in_busy_2 = 0;
}
}
@@ -1277,6 +1310,7 @@
COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->pkt_buf),
driver->pkt_length);
driver->data_ready[index] ^= PKT_TYPE;
+ driver->in_busy_pktdata = 0;
goto exit;
}
@@ -1308,6 +1342,11 @@
goto exit;
}
exit:
+ if (clear_read_wakelock) {
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
+ process_lock_on_copy_complete(
+ &driver->smd_data[i].nrt_lock);
+ }
mutex_unlock(&driver->diagchar_mutex);
return ret;
}
@@ -1359,6 +1398,117 @@
payload_size);
return err;
}
+ if (pkt_type == CALLBACK_DATA_TYPE) {
+ err = copy_from_user(driver->user_space_data, buf + 4,
+ payload_size);
+ if (err) {
+ pr_err("diag: copy failed for user space data\n");
+ return -EIO;
+ }
+ /* Check for proc_type */
+ remote_proc = diag_get_remote(*(int *)driver->user_space_data);
+
+ if (!remote_proc) {
+ wait_event_interruptible(driver->wait_q,
+ (driver->in_busy_pktdata == 0));
+ return diag_process_apps_pkt(driver->user_space_data,
+ payload_size);
+ }
+ /* The packet is for the remote processor */
+ token_offset = 4;
+ payload_size -= 4;
+ buf += 4;
+ /* Perform HDLC encoding on incoming data */
+ send.state = DIAG_STATE_START;
+ send.pkt = (void *)(driver->user_space_data + token_offset);
+ send.last = (void *)(driver->user_space_data + token_offset -
+ 1 + payload_size);
+ send.terminate = 1;
+
+ mutex_lock(&driver->diagchar_mutex);
+ if (!buf_hdlc)
+ buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
+ POOL_TYPE_HDLC);
+ if (!buf_hdlc) {
+ ret = -ENOMEM;
+ goto fail_free_hdlc;
+ }
+ if (HDLC_OUT_BUF_SIZE < (2 * payload_size) + 3) {
+ pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
+ ((2*payload_size) + 3));
+ driver->dropped_count++;
+ ret = -EBADMSG;
+ diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
+ goto fail_free_hdlc;
+ }
+ enc.dest = buf_hdlc + driver->used;
+ enc.dest_last = (void *)(buf_hdlc + driver->used +
+ (2 * payload_size) + token_offset - 1);
+ diag_hdlc_encode(&send, &enc);
+
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ /* send masks to 9k too */
+ if (driver->sdio_ch && (remote_proc == MDM)) {
+ wait_event_interruptible(driver->wait_q,
+ (sdio_write_avail(driver->sdio_ch) >=
+ payload_size));
+ if (driver->sdio_ch && (payload_size > 0)) {
+ sdio_write(driver->sdio_ch, (void *)
+ (char *)buf_hdlc, payload_size + 3);
+ }
+ }
+#endif
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ /* send masks to All 9k */
+ if ((remote_proc >= MDM) && (remote_proc <= MDM4)) {
+ index = remote_proc - MDM;
+ if (diag_hsic[index].hsic_ch && (payload_size > 0)) {
+ /* wait sending mask updates
+ * if HSIC ch not ready */
+ if (diag_hsic[index].in_busy_hsic_write)
+ wait_event_interruptible(driver->wait_q,
+ (diag_hsic[index].
+ in_busy_hsic_write != 1));
+ diag_hsic[index].in_busy_hsic_write = 1;
+ diag_hsic[index].in_busy_hsic_read_on_device =
+ 0;
+ err = diag_bridge_write(index,
+ (char *)buf_hdlc, payload_size + 3);
+ if (err) {
+ pr_err("diag: err sending mask to MDM: %d\n",
+ err);
+ /*
+ * If the error is recoverable, then
+ * clear the write flag, so we will
+ * resubmit a write on the next frame.
+ * Otherwise, don't resubmit a write
+ * on the next frame.
+ */
+ if ((-ESHUTDOWN) != err)
+ diag_hsic[index].
+ in_busy_hsic_write = 0;
+ }
+ }
+ }
+ if (driver->diag_smux_enabled && (remote_proc == QSC)
+ && driver->lcid) {
+ if (payload_size > 0) {
+ err = msm_smux_write(driver->lcid, NULL,
+ (char *)buf_hdlc, payload_size + 3);
+ if (err) {
+ pr_err("diag:send mask to MDM err %d",
+ err);
+ ret = err;
+ }
+ }
+ }
+#endif
+ diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
+ buf_hdlc = NULL;
+ driver->used = 0;
+ mutex_unlock(&driver->diagchar_mutex);
+ return ret;
+ }
if (pkt_type == USER_SPACE_DATA_TYPE) {
err = copy_from_user(driver->user_space_data, buf + 4,
payload_size);
@@ -1405,9 +1555,19 @@
#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
/* send masks to All 9k */
- if ((remote_proc >= MDM) && (remote_proc <= MDM4)) {
+ if ((remote_proc >= MDM) && (remote_proc <= MDM4) &&
+ (payload_size > 0)) {
index = remote_proc - MDM;
- if (diag_hsic[index].hsic_ch && (payload_size > 0)) {
+ /*
+ * If hsic data is being requested for this remote
+ * processor and its hsic in not open
+ */
+ if (!diag_hsic[index].hsic_device_opened) {
+ diag_hsic[index].hsic_data_requested = 1;
+ connect_bridge(0, index);
+ }
+
+ if (diag_hsic[index].hsic_ch) {
/* wait sending mask updates
* if HSIC ch not ready */
if (diag_hsic[index].in_busy_hsic_write)
@@ -1791,6 +1951,7 @@
driver->socket_process = NULL;
driver->callback_process = NULL;
driver->mask_check = 0;
+ driver->in_busy_pktdata = 0;
mutex_init(&driver->diagchar_mutex);
init_waitqueue_head(&driver->wait_q);
init_waitqueue_head(&driver->smd_wait_q);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 79a73f3..5b929d7 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -227,6 +227,93 @@
}
}
+void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (real_time)
+ lock->enabled = 0;
+ else
+ lock->enabled = 1;
+ lock->ref_count = 0;
+ lock->copy_count = 0;
+ wake_unlock(&lock->read_lock);
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_notify(struct diag_nrt_wake_lock *lock)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ /*
+ * Do not work with ref_count here in case
+ * of spurious interrupt
+ */
+ if (lock->enabled)
+ wake_lock(&lock->read_lock);
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (lock->enabled) {
+ if (pkt_len > 0) {
+ /*
+ * We have an data that is read that
+ * needs to be processed, make sure the
+ * processor does not go to sleep
+ */
+ lock->ref_count++;
+ if (!wake_lock_active(&lock->read_lock))
+ wake_lock(&lock->read_lock);
+ } else {
+ /*
+ * There was no data associated with the
+ * read from the smd, unlock the wake lock
+ * if it is not needed.
+ */
+ if (lock->ref_count < 1) {
+ if (wake_lock_active(&lock->read_lock))
+ wake_unlock(&lock->read_lock);
+ lock->ref_count = 0;
+ lock->copy_count = 0;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_copy(struct diag_nrt_wake_lock *lock)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (lock->enabled)
+ lock->copy_count++;
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (lock->enabled) {
+ lock->ref_count -= lock->copy_count;
+ if (lock->ref_count < 1) {
+ wake_unlock(&lock->read_lock);
+ lock->ref_count = 0;
+ }
+ lock->copy_count = 0;
+ }
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
/* Process the data read from the smd data channel */
int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd)
@@ -324,6 +411,8 @@
smd_read(smd_info->ch, temp_buf, r);
temp_buf += r;
}
+ if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
+ process_lock_on_read(&smd_info->nrt_lock, pkt_len);
if (total_recd > 0) {
if (!buf) {
@@ -552,9 +641,10 @@
unsigned char *temp = buf;
mutex_lock(&driver->diagchar_mutex);
- if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
+ if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
memcpy(ptr, temp , driver->pkt_length);
- else
+ driver->in_busy_pktdata = 1;
+ } else
printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
mutex_unlock(&driver->diagchar_mutex);
}
@@ -629,7 +719,7 @@
}
}
-static int diag_process_apps_pkt(unsigned char *buf, int len)
+int diag_process_apps_pkt(unsigned char *buf, int len)
{
uint16_t subsys_cmd_code;
int subsys_id, ssid_first, ssid_last, ssid_range;
@@ -1321,6 +1411,9 @@
diag_dci_notify_client(smd_info->peripheral_mask,
DIAG_STATUS_OPEN);
}
+ } else if (event == SMD_EVENT_DATA && !driver->real_time_mode &&
+ smd_info->type == SMD_DATA_TYPE) {
+ process_lock_on_notify(&smd_info->nrt_lock);
}
wake_up(&driver->smd_wait_q);
@@ -1413,6 +1506,9 @@
void diag_smd_destructor(struct diag_smd_info *smd_info)
{
+ if (smd_info->type == SMD_DATA_TYPE)
+ wake_lock_destroy(&smd_info->nrt_lock.read_lock);
+
if (smd_info->ch)
smd_close(smd_info->ch);
@@ -1524,6 +1620,30 @@
goto err;
}
+ smd_info->nrt_lock.enabled = 0;
+ smd_info->nrt_lock.ref_count = 0;
+ smd_info->nrt_lock.copy_count = 0;
+ if (type == SMD_DATA_TYPE) {
+ spin_lock_init(&smd_info->nrt_lock.read_spinlock);
+
+ switch (peripheral) {
+ case MODEM_DATA:
+ wake_lock_init(&smd_info->nrt_lock.read_lock,
+ WAKE_LOCK_SUSPEND, "diag_nrt_modem_read");
+ break;
+ case LPASS_DATA:
+ wake_lock_init(&smd_info->nrt_lock.read_lock,
+ WAKE_LOCK_SUSPEND, "diag_nrt_lpass_read");
+ break;
+ case WCNSS_DATA:
+ wake_lock_init(&smd_info->nrt_lock.read_lock,
+ WAKE_LOCK_SUSPEND, "diag_nrt_wcnss_read");
+ break;
+ default:
+ break;
+ }
+ }
+
return 1;
err:
kfree(smd_info->buf_in_1);
@@ -1544,6 +1664,7 @@
diag_debug_buf_idx = 0;
driver->read_len_legacy = 0;
driver->use_device_tree = has_device_tree();
+ driver->real_time_mode = 1;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index afbe4be..09f2f5e 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -23,6 +23,11 @@
void diagfwd_exit(void);
void diag_process_hdlc(void *data, unsigned len);
void diag_smd_send_req(struct diag_smd_info *smd_info);
+void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time);
+void process_lock_on_notify(struct diag_nrt_wake_lock *lock);
+void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len);
+void process_lock_on_copy(struct diag_nrt_wake_lock *lock);
+void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock);
void diag_usb_legacy_notifier(void *, unsigned, struct diag_request *);
long diagchar_ioctl(struct file *, unsigned int, unsigned long);
int diag_device_write(void *, int, struct diag_request *);
@@ -43,6 +48,7 @@
int diag_command_reg(unsigned long);
void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
+int diag_process_apps_pkt(unsigned char *buf, int len);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index b934805..475f5ba 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -65,7 +65,9 @@
driver->in_busy_smux = 0;
diagfwd_connect_smux();
} else {
- if (diag_hsic[index].hsic_device_enabled) {
+ if (diag_hsic[index].hsic_device_enabled &&
+ (driver->logging_mode != MEMORY_DEVICE_MODE ||
+ diag_hsic[index].hsic_data_requested)) {
diag_hsic[index].in_busy_hsic_read_on_device = 0;
diag_hsic[index].in_busy_hsic_write = 0;
/* If the HSIC (diag_bridge) platform
@@ -126,20 +128,24 @@
usb_diag_free_req(diag_bridge[i].ch);
}
- if (i == SMUX && driver->diag_smux_enabled &&
+ if (i == SMUX) {
+ if (driver->diag_smux_enabled &&
driver->logging_mode == USB_MODE) {
- driver->in_busy_smux = 1;
- driver->lcid = LCID_INVALID;
- driver->smux_connected = 0;
- /* Turn off communication over usb and smux */
- msm_smux_close(LCID_VALID);
+ driver->in_busy_smux = 1;
+ driver->lcid = LCID_INVALID;
+ driver->smux_connected = 0;
+ /*
+ * Turn off communication over usb
+ * and smux
+ */
+ msm_smux_close(LCID_VALID);
+ }
} else {
if (diag_hsic[i].hsic_device_enabled &&
- driver->logging_mode !=
- MEMORY_DEVICE_MODE) {
+ (driver->logging_mode != MEMORY_DEVICE_MODE
+ || !diag_hsic[i].hsic_data_requested)) {
diag_hsic[i].
- in_busy_hsic_read_on_device
- = 1;
+ in_busy_hsic_read_on_device = 1;
diag_hsic[i].in_busy_hsic_write = 1;
/* Turn off communication over usb
* and HSIC */
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 7e58249..c3ff7dc 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
#include <linux/diagchar.h>
#include <linux/platform_device.h>
#include <linux/kmemleak.h>
+#include <linux/delay.h>
#include "diagchar.h"
#include "diagfwd.h"
#include "diagfwd_cntl.h"
@@ -85,14 +86,15 @@
range = buf+HDR_SIZ+
sizeof(struct diag_ctrl_msg);
pkt_params->count = msg->count_entries;
- temp = kzalloc(pkt_params->count * sizeof(struct
- bindpkt_params), GFP_KERNEL);
- if (temp == NULL) {
+ pkt_params->params = kzalloc(pkt_params->count *
+ sizeof(struct bindpkt_params), GFP_KERNEL);
+ if (pkt_params->params == NULL) {
pr_alert("diag: In %s, Memory alloc fail\n",
__func__);
kfree(pkt_params);
return flag;
}
+ temp = pkt_params->params;
for (j = 0; j < pkt_params->count; j++) {
temp->cmd_code = msg->cmd_code;
temp->subsys_id = msg->subsysid;
@@ -103,8 +105,6 @@
range++;
temp++;
}
- temp -= pkt_params->count;
- pkt_params->params = temp;
flag = 1;
/* peripheral undergoing SSR should not
* record new registration
@@ -115,7 +115,7 @@
else
pr_err("diag: drop reg proc %d\n",
smd_info->peripheral);
- kfree(temp);
+ kfree(pkt_params->params);
} else if ((type == DIAG_CTRL_MSG_FEATURE) &&
(smd_info->peripheral == MODEM_DATA)) {
feature_mask_len = *(int *)(buf + 8);
@@ -131,6 +131,83 @@
return flag;
}
+void diag_send_diag_mode_update(int real_time)
+{
+ int i;
+
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i],
+ real_time);
+}
+
+void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info,
+ int real_time)
+{
+ struct diag_ctrl_msg_diagmode diagmode;
+ char buf[sizeof(struct diag_ctrl_msg_diagmode)];
+ int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
+ int wr_size = -ENOMEM, retry_count = 0, timer;
+
+ /* For now only allow the modem to receive the message */
+ if (!smd_info || smd_info->type != SMD_CNTL_TYPE ||
+ (smd_info->peripheral != MODEM_DATA))
+ return;
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
+ diagmode.ctrl_pkt_data_len = 36;
+ diagmode.version = 1;
+ diagmode.sleep_vote = real_time ? 1 : 0;
+ /*
+ * 0 - Disables real-time logging (to prevent
+ * frequent APPS wake-ups, etc.).
+ * 1 - Enable real-time logging
+ */
+ diagmode.real_time = real_time;
+ diagmode.use_nrt_values = 0;
+ diagmode.commit_threshold = 0;
+ diagmode.sleep_threshold = 0;
+ diagmode.sleep_time = 0;
+ diagmode.drain_timer_val = 0;
+ diagmode.event_stale_timer_val = 0;
+
+ memcpy(buf, &diagmode, msg_size);
+
+ if (smd_info->ch) {
+ while (retry_count < 3) {
+ wr_size = smd_write(smd_info->ch, buf, msg_size);
+ if (wr_size == -ENOMEM) {
+ /*
+ * The smd channel is full. Delay while
+ * smd processes existing data and smd
+ * has memory become available. The delay
+ * of 2000 was determined empirically as
+ * best value to use.
+ */
+ retry_count++;
+ for (timer = 0; timer < 5; timer++)
+ udelay(2000);
+ } else {
+ struct diag_smd_info *data =
+ &driver->smd_data[smd_info->peripheral];
+ driver->real_time_mode = real_time;
+ process_lock_enabling(&data->nrt_lock,
+ real_time);
+ break;
+ }
+ }
+ if (wr_size != msg_size)
+ pr_err("diag: proc %d fail feature update %d, tried %d",
+ smd_info->peripheral,
+ wr_size, msg_size);
+ } else {
+ pr_err("diag: ch invalid, feature update on proc %d\n",
+ smd_info->peripheral);
+ }
+
+ mutex_unlock(&driver->diag_cntl_mutex);
+}
+
static int diag_smd_cntl_probe(struct platform_device *pdev)
{
int r = 0;
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index c28b06d..7cd1866 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -84,11 +84,28 @@
/* Copy feature mask here */
} __packed;
+struct diag_ctrl_msg_diagmode {
+ uint32_t ctrl_pkt_id;
+ uint32_t ctrl_pkt_data_len;
+ uint32_t version;
+ uint32_t sleep_vote;
+ uint32_t real_time;
+ uint32_t use_nrt_values;
+ uint32_t commit_threshold;
+ uint32_t sleep_threshold;
+ uint32_t sleep_time;
+ uint32_t drain_timer_val;
+ uint32_t event_stale_timer_val;
+} __packed;
+
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
void diag_clean_reg_fn(struct work_struct *work);
int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd);
+void diag_send_diag_mode_update(int real_time);
+void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info,
+ int real_time);
#endif
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index 616c498..fa46aab 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -227,8 +227,12 @@
if (diag_hsic[index].in_busy_hsic_write)
return -EBUSY;
- /* Don't allow suspend if in MEMORY_DEVICE_MODE */
- if (driver->logging_mode == MEMORY_DEVICE_MODE)
+ /*
+ * Don't allow suspend if in MEMORY_DEVICE_MODE and if there
+ * has been hsic data requested
+ */
+ if (driver->logging_mode == MEMORY_DEVICE_MODE &&
+ diag_hsic[index].hsic_ch)
return -EBUSY;
diag_hsic[index].hsic_suspend = 1;
@@ -288,7 +292,7 @@
}
/* diagfwd_cancel_hsic is called to cancel outstanding read/writes */
-int diagfwd_cancel_hsic(void)
+int diagfwd_cancel_hsic(int reopen)
{
int err, i;
@@ -302,17 +306,24 @@
diag_hsic[i].hsic_ch = 0;
diag_hsic[i].hsic_device_opened = 0;
diag_bridge_close(i);
- hsic_diag_bridge_ops[i].ctxt = (void *)(i);
- err = diag_bridge_open(i,
- &hsic_diag_bridge_ops[i]);
- if (err) {
- pr_err("diag: HSIC %d channel open error: %d\n",
- i, err);
+ if (reopen) {
+ hsic_diag_bridge_ops[i].ctxt =
+ (void *)(i);
+ err = diag_bridge_open(i,
+ &hsic_diag_bridge_ops[i]);
+ if (err) {
+ pr_err("diag: HSIC %d channel open error: %d\n",
+ i, err);
+ } else {
+ pr_debug("diag: opened HSIC channel: %d\n",
+ i);
+ diag_hsic[i].
+ hsic_device_opened = 1;
+ diag_hsic[i].hsic_ch = 1;
+ }
+ diag_hsic[i].hsic_data_requested = 1;
} else {
- pr_debug("diag: opened HSIC channel: %d\n",
- i);
- diag_hsic[i].hsic_device_opened = 1;
- diag_hsic[i].hsic_ch = 1;
+ diag_hsic[i].hsic_data_requested = 0;
}
}
}
@@ -428,15 +439,20 @@
diagmem_hsic_init(pdev->id);
INIT_WORK(&(diag_hsic[pdev->id].diag_read_hsic_work),
diag_read_hsic_work_fn);
+ diag_hsic[pdev->id].hsic_data_requested =
+ (driver->logging_mode == MEMORY_DEVICE_MODE) ? 0 : 1;
diag_hsic[pdev->id].hsic_inited = 1;
}
/*
* The probe function was called after the usb was connected
- * on the legacy channel OR ODL is turned on. Communication over usb
- * mdm and HSIC needs to be turned on.
+ * on the legacy channel OR ODL is turned on and hsic data is
+ * requested. Communication over usb mdm and HSIC needs to be
+ * turned on.
*/
- if (diag_bridge[pdev->id].usb_connected || (driver->logging_mode ==
- MEMORY_DEVICE_MODE)) {
+ if ((diag_bridge[pdev->id].usb_connected &&
+ (driver->logging_mode != MEMORY_DEVICE_MODE)) ||
+ ((driver->logging_mode == MEMORY_DEVICE_MODE) &&
+ diag_hsic[pdev->id].hsic_data_requested)) {
if (diag_hsic[pdev->id].hsic_device_opened) {
/* should not happen. close it before re-opening */
pr_warn("diag: HSIC channel already opened in probe\n");
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index d171efa..64556f2 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -19,8 +19,10 @@
#define N_MDM_READ 1
#define NUM_HSIC_BUF_TBL_ENTRIES N_MDM_WRITE
#define MAX_HSIC_CH 4
+#define REOPEN_HSIC 1
+#define DONT_REOPEN_HSIC 0
int diagfwd_write_complete_hsic(struct diag_request *, int index);
-int diagfwd_cancel_hsic(void);
+int diagfwd_cancel_hsic(int reopen);
void diag_read_usb_hsic_work_fn(struct work_struct *work);
void diag_usb_read_complete_hsic_fn(struct work_struct *w);
extern struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH];
@@ -37,6 +39,7 @@
int hsic_device_enabled;
int hsic_device_opened;
int hsic_suspend;
+ int hsic_data_requested;
int in_busy_hsic_read_on_device;
int in_busy_hsic_write;
struct work_struct diag_read_hsic_work;
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 4774c76..988d1c9 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -158,7 +158,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
index e077edf..6a8d412 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -402,7 +402,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cti-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
index d52ab28..31f85dc 100644
--- a/drivers/coresight/coresight-etb.c
+++ b/drivers/coresight/coresight-etb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -375,7 +375,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "etb-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 1033233..2777769 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -2090,7 +2090,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "etm-base");
if (!res)
return -ENODEV;
reg_size = resource_size(res);
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index 7f39a3e..625f481 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -187,7 +187,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "funnel-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
index fe37e5e..d4afa42 100644
--- a/drivers/coresight/coresight-replicator.c
+++ b/drivers/coresight/coresight-replicator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -139,7 +139,8 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "replicator-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 1db499b..87cf63a 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -806,7 +806,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "stm-base");
if (!res)
return -ENODEV;
@@ -814,7 +814,8 @@
if (!drvdata->base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "stm-data-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 86276b7..4a9a97a 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1090,7 +1090,7 @@
return -ENOMEM;
drvdata->bamdata = bamdata;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bam-base");
if (!res)
return -ENODEV;
@@ -1147,7 +1147,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tmc-base");
if (!res)
return -ENODEV;
reg_size = resource_size(res);
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 73800dd..7ea71d3 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -710,7 +710,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tpiu-base");
if (!res)
return -ENODEV;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1134f90..8545a5c 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -2728,6 +2728,7 @@
rc = clk_set_rate(pce_dev->ce_core_src_clk, 100000000);
if (rc) {
clk_put(pce_dev->ce_core_src_clk);
+ pce_dev->ce_core_src_clk = NULL;
pr_err("Unable to set the core src clk @100Mhz.\n");
goto err_clk;
}
@@ -2735,7 +2736,6 @@
pr_warn("Unable to get CE core src clk, set to NULL\n");
pce_dev->ce_core_src_clk = NULL;
}
- pce_dev->ce_core_src_clk = ce_core_src_clk;
/* Get CE core clk */
ce_core_clk = clk_get(pce_dev->pdev, "core_clk");
@@ -2805,34 +2805,29 @@
int rc = 0;
/* Enable CE core clk */
- rc = clk_prepare_enable(pce_dev->ce_core_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE core clk\n");
- return rc;
+ if (pce_dev->ce_core_clk != NULL) {
+ rc = clk_prepare_enable(pce_dev->ce_core_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE core clk\n");
+ return rc;
+ }
}
/* Enable CE clk */
- rc = clk_prepare_enable(pce_dev->ce_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- clk_disable_unprepare(pce_dev->ce_core_clk);
- return rc;
+ if (pce_dev->ce_clk != NULL) {
+ rc = clk_prepare_enable(pce_dev->ce_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ clk_disable_unprepare(pce_dev->ce_core_clk);
+ return rc;
+ }
}
/* Enable AXI clk */
- rc = clk_prepare_enable(pce_dev->ce_bus_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE BUS clk\n");
- clk_disable_unprepare(pce_dev->ce_clk);
- clk_disable_unprepare(pce_dev->ce_core_clk);
- return rc;
- }
- /* Enable CORE SRC (INTERFACE) clk */
- if (pce_dev->ce_core_src_clk != NULL) {
- rc = clk_prepare_enable(pce_dev->ce_core_src_clk);
+ if (pce_dev->ce_bus_clk != NULL) {
+ rc = clk_prepare_enable(pce_dev->ce_bus_clk);
if (rc) {
pr_err("Unable to enable/prepare CE BUS clk\n");
clk_disable_unprepare(pce_dev->ce_clk);
clk_disable_unprepare(pce_dev->ce_core_clk);
- clk_disable_unprepare(pce_dev->ce_bus_clk);
return rc;
}
}
@@ -2846,8 +2841,6 @@
if (pce_dev->ce_clk != NULL)
clk_disable_unprepare(pce_dev->ce_clk);
- if (pce_dev->ce_core_src_clk != NULL)
- clk_disable_unprepare(pce_dev->ce_core_src_clk);
if (pce_dev->ce_core_clk != NULL)
clk_disable_unprepare(pce_dev->ce_core_clk);
if (pce_dev->ce_bus_clk != NULL)
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 9128177..16c2900 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -39,7 +39,6 @@
#include <mach/iommu_domains.h>
#include "ion_priv.h"
-#define DEBUG
/**
* struct ion_device - the metadata of the ion device node
@@ -107,6 +106,12 @@
unsigned int iommu_map_cnt;
};
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
+{
+ return ((buffer->flags & ION_FLAG_CACHED) &&
+ !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
+}
+
static void ion_iommu_release(struct kref *kref);
/* this function should only be called while dev->lock is held */
@@ -190,6 +195,8 @@
return NULL;
}
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
+
/* this function should only be called while dev->lock is held */
static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
struct ion_device *dev,
@@ -199,13 +206,15 @@
{
struct ion_buffer *buffer;
struct sg_table *table;
- int ret;
+ struct scatterlist *sg;
+ int i, ret;
buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
buffer->heap = heap;
+ buffer->flags = flags;
kref_init(&buffer->ref);
ret = heap->ops->allocate(heap, buffer, len, align, flags);
@@ -216,19 +225,54 @@
buffer->dev = dev;
buffer->size = len;
- buffer->flags = flags;
- table = buffer->heap->ops->map_dma(buffer->heap, buffer);
+ table = heap->ops->map_dma(heap, buffer);
if (IS_ERR_OR_NULL(table)) {
heap->ops->free(buffer);
kfree(buffer);
return ERR_PTR(PTR_ERR(table));
}
buffer->sg_table = table;
+ if (ion_buffer_fault_user_mappings(buffer)) {
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents,
+ i) {
+ if (sg_dma_len(sg) == PAGE_SIZE)
+ continue;
+ pr_err("%s: cached mappings that will be faulted in "
+ "must have pagewise sg_lists\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = ion_buffer_alloc_dirty(buffer);
+ if (ret)
+ goto err;
+ }
+
+ buffer->dev = dev;
+ buffer->size = len;
+ INIT_LIST_HEAD(&buffer->vmas);
mutex_init(&buffer->lock);
+ /* this will set up dma addresses for the sglist -- it is not
+ technically correct as per the dma api -- a specific
+ device isn't really taking ownership here. However, in practice on
+ our systems the only dma_address space is physical addresses.
+ Additionally, we can't afford the overhead of invalidating every
+ allocation via dma_map_sg. The implicit contract here is that
+ memory comming from the heaps is ready for dma, ie if it has a
+ cached mapping that mapping has been invalidated */
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+ if (sg_dma_address(sg) == 0)
+ sg_dma_address(sg) = sg_phys(sg);
+ }
ion_buffer_add(dev, buffer);
return buffer;
+
+err:
+ heap->ops->unmap_dma(heap, buffer);
+ heap->ops->free(buffer);
+ kfree(buffer);
+ return ERR_PTR(ret);
}
/**
@@ -276,7 +320,6 @@
if (WARN_ON(buffer->kmap_cnt > 0))
buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
-
buffer->heap->ops->unmap_dma(buffer->heap, buffer);
ion_delayed_unsecure(buffer);
@@ -285,6 +328,8 @@
mutex_lock(&dev->lock);
rb_erase(&buffer->node, &dev->buffers);
mutex_unlock(&dev->lock);
+ if (buffer->flags & ION_FLAG_CACHED)
+ kfree(buffer->dirty);
kfree(buffer);
}
@@ -419,6 +464,16 @@
dbg_str[0] = '\0';
/*
+ * For now, we don't want to fault in pages individually since
+ * clients are already doing manual cache maintenance. In
+ * other words, the implicit caching infrastructure is in
+ * place (in code) but should not be used.
+ */
+ flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
+ pr_debug("%s: len %d align %d heap_mask %u flags %x\n", __func__, len,
+ align, heap_mask, flags);
+ /*
* traverse the list of heaps available in this system in priority
* order. If the heap type is supported by the client, and matches the
* request of the caller allocate from it. Repeat until allocate has
@@ -1205,12 +1260,46 @@
}
EXPORT_SYMBOL(ion_sg_table);
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+ size_t chunk_size, size_t total_size)
+{
+ struct sg_table *table;
+ int i, n_chunks, ret;
+ struct scatterlist *sg;
+
+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+
+ n_chunks = DIV_ROUND_UP(total_size, chunk_size);
+ pr_debug("creating sg_table with %d chunks\n", n_chunks);
+
+ ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
+ if (ret)
+ goto err0;
+
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ dma_addr_t addr = buffer_base + i * chunk_size;
+ sg_dma_address(sg) = addr;
+ }
+
+ return table;
+err0:
+ kfree(table);
+ return ERR_PTR(ret);
+}
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+ struct device *dev,
+ enum dma_data_direction direction);
+
static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
enum dma_data_direction direction)
{
struct dma_buf *dmabuf = attachment->dmabuf;
struct ion_buffer *buffer = dmabuf->priv;
+ ion_buffer_sync_for_device(buffer, attachment->dev, direction);
return buffer->sg_table;
}
@@ -1220,24 +1309,119 @@
{
}
-static void ion_vma_close(struct vm_area_struct *vma)
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer)
+{
+ unsigned long pages = buffer->sg_table->nents;
+ unsigned long length = (pages + BITS_PER_LONG - 1)/BITS_PER_LONG;
+
+ buffer->dirty = kzalloc(length * sizeof(unsigned long), GFP_KERNEL);
+ if (!buffer->dirty)
+ return -ENOMEM;
+ return 0;
+}
+
+struct ion_vma_list {
+ struct list_head list;
+ struct vm_area_struct *vma;
+};
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+ struct device *dev,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+ struct ion_vma_list *vma_list;
+
+ pr_debug("%s: syncing for device %s\n", __func__,
+ dev ? dev_name(dev) : "null");
+
+ if (!ion_buffer_fault_user_mappings(buffer))
+ return;
+
+ mutex_lock(&buffer->lock);
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+ if (!test_bit(i, buffer->dirty))
+ continue;
+ dma_sync_sg_for_device(dev, sg, 1, dir);
+ clear_bit(i, buffer->dirty);
+ }
+ list_for_each_entry(vma_list, &buffer->vmas, list) {
+ struct vm_area_struct *vma = vma_list->vma;
+
+ zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start,
+ NULL);
+ }
+ mutex_unlock(&buffer->lock);
+}
+
+int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct ion_buffer *buffer = vma->vm_private_data;
+ struct scatterlist *sg;
+ int i;
- pr_debug("%s: %d\n", __func__, __LINE__);
+ mutex_lock(&buffer->lock);
+ set_bit(vmf->pgoff, buffer->dirty);
+
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+ if (i != vmf->pgoff)
+ continue;
+ dma_sync_sg_for_cpu(NULL, sg, 1, DMA_BIDIRECTIONAL);
+ vm_insert_page(vma, (unsigned long)vmf->virtual_address,
+ sg_page(sg));
+ break;
+ }
+ mutex_unlock(&buffer->lock);
+ return VM_FAULT_NOPAGE;
+}
+
+static void ion_vm_open(struct vm_area_struct *vma)
+{
+ struct ion_buffer *buffer = vma->vm_private_data;
+ struct ion_vma_list *vma_list;
+
+ vma_list = kmalloc(sizeof(struct ion_vma_list), GFP_KERNEL);
+ if (!vma_list)
+ return;
+ vma_list->vma = vma;
+ mutex_lock(&buffer->lock);
+ list_add(&vma_list->list, &buffer->vmas);
+ mutex_unlock(&buffer->lock);
+ pr_debug("%s: adding %p\n", __func__, vma);
+}
+
+static void ion_vm_close(struct vm_area_struct *vma)
+{
+ struct ion_buffer *buffer = vma->vm_private_data;
+ struct ion_vma_list *vma_list, *tmp;
+
+ pr_debug("%s\n", __func__);
+ mutex_lock(&buffer->lock);
+ list_for_each_entry_safe(vma_list, tmp, &buffer->vmas, list) {
+ if (vma_list->vma != vma)
+ continue;
+ list_del(&vma_list->list);
+ kfree(vma_list);
+ pr_debug("%s: deleting %p\n", __func__, vma);
+ break;
+ }
+ mutex_unlock(&buffer->lock);
if (buffer->heap->ops->unmap_user)
buffer->heap->ops->unmap_user(buffer->heap, buffer);
}
-static struct vm_operations_struct ion_vm_ops = {
- .close = ion_vma_close,
+struct vm_operations_struct ion_vma_ops = {
+ .open = ion_vm_open,
+ .close = ion_vm_close,
+ .fault = ion_vm_fault,
};
static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
struct ion_buffer *buffer = dmabuf->priv;
- int ret;
+ int ret = 0;
if (!buffer->heap->ops->map_user) {
pr_err("%s: this heap does not define a method for mapping "
@@ -1245,22 +1429,26 @@
return -EINVAL;
}
+ if (ion_buffer_fault_user_mappings(buffer)) {
+ vma->vm_private_data = buffer;
+ vma->vm_ops = &ion_vma_ops;
+ vma->vm_flags |= VM_MIXEDMAP;
+ ion_vm_open(vma);
+ return 0;
+ }
+
+ if (!(buffer->flags & ION_FLAG_CACHED))
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
mutex_lock(&buffer->lock);
/* now map it to userspace */
ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma);
mutex_unlock(&buffer->lock);
- if (ret) {
+ if (ret)
pr_err("%s: failure mapping buffer to userspace\n",
__func__);
- } else {
- vma->vm_ops = &ion_vm_ops;
- /*
- * move the buffer into the vm_private_data so we can access it
- * from vma_open/close
- */
- vma->vm_private_data = buffer;
- }
+
return ret;
}
@@ -1396,6 +1584,30 @@
}
EXPORT_SYMBOL(ion_import_dma_buf);
+static int ion_sync_for_device(struct ion_client *client, int fd)
+{
+ struct dma_buf *dmabuf;
+ struct ion_buffer *buffer;
+
+ dmabuf = dma_buf_get(fd);
+ if (IS_ERR_OR_NULL(dmabuf))
+ return PTR_ERR(dmabuf);
+
+ /* if this memory came from ion */
+ if (dmabuf->ops != &dma_buf_ops) {
+ pr_err("%s: can not sync dmabuf from another exporter\n",
+ __func__);
+ dma_buf_put(dmabuf);
+ return -EINVAL;
+ }
+ buffer = dmabuf->priv;
+
+ dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
+ buffer->sg_table->nents, DMA_BIDIRECTIONAL);
+ dma_buf_put(dmabuf);
+ return 0;
+}
+
static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct ion_client *client = filp->private_data;
@@ -1468,6 +1680,15 @@
return ret;
break;
}
+ case ION_IOC_SYNC:
+ {
+ struct ion_fd_data data;
+ if (copy_from_user(&data, (void __user *)arg,
+ sizeof(struct ion_fd_data)))
+ return -EFAULT;
+ ion_sync_for_device(client, data.fd);
+ break;
+ }
case ION_IOC_CUSTOM:
{
struct ion_device *dev = client->dev;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 798c027..9610dfe 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -112,26 +112,13 @@
struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- struct sg_table *table;
- int ret;
+ size_t chunk_size = buffer->size;
- table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (!table)
- return ERR_PTR(-ENOMEM);
+ if (ION_IS_CACHED(buffer->flags))
+ chunk_size = PAGE_SIZE;
- ret = sg_alloc_table(table, 1, GFP_KERNEL);
- if (ret)
- goto err0;
-
- table->sgl->length = buffer->size;
- table->sgl->offset = 0;
- table->sgl->dma_address = buffer->priv_phys;
-
- return table;
-
-err0:
- kfree(table);
- return ERR_PTR(ret);
+ return ion_create_chunked_sg_table(buffer->priv_phys, chunk_size,
+ buffer->size);
}
void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 3000252..2ef285b 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -457,6 +457,12 @@
struct ion_cp_buffer *buf;
phys_addr_t addr;
+ /*
+ * we never want Ion to fault pages in for us with this
+ * heap. We want to set up the mappings ourselves in .map_user
+ */
+ flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
return ION_CP_ALLOCATE_FAIL;
@@ -491,9 +497,6 @@
struct sg_table *ion_cp_heap_create_sg_table(struct ion_buffer *buffer)
{
size_t chunk_size = buffer->size;
- struct sg_table *table;
- int ret, i, n_chunks;
- struct scatterlist *sg;
struct ion_cp_buffer *buf = buffer->priv_virt;
if (ION_IS_CACHED(buffer->flags))
@@ -501,26 +504,8 @@
else if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M))
chunk_size = SZ_1M;
- table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (!table)
- return ERR_PTR(-ENOMEM);
-
- n_chunks = DIV_ROUND_UP(buffer->size, chunk_size);
-
- ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
- if (ret)
- goto err0;
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- sg_dma_address(sg) = buf->buffer + i * chunk_size;
- sg->length = chunk_size;
- sg->offset = 0;
- }
-
- return table;
-err0:
- kfree(table);
- return ERR_PTR(ret);
+ return ion_create_chunked_sg_table(buf->buffer, chunk_size,
+ buffer->size);
}
struct sg_table *ion_cp_heap_map_dma(struct ion_heap *heap,
@@ -614,6 +599,11 @@
int i;
pgprot_t pgprot;
+ if (!pages) {
+ mutex_unlock(&cp_heap->lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
if (ION_IS_CACHED(buffer->flags))
pgprot = PAGE_KERNEL;
else
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index ba48b50..9ab6b85 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -330,6 +330,14 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
+ /* Use the biggest alignment to allow bigger IOMMU mappings.
+ * Use the first entry since the first entry will always be the
+ * biggest entry. To take advantage of bigger mapping sizes both the
+ * VA and PA addresses have to be aligned to the biggest size.
+ */
+ if (buffer->sg_table->sgl->length > align)
+ align = buffer->sg_table->sgl->length;
+
ret = msm_allocate_iova_address(domain_num, partition_num,
data->mapped_size, align,
&data->iova_addr);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 2ab2ed6..28ef1a5 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -98,6 +98,8 @@
void *vaddr;
int dmap_cnt;
struct sg_table *sg_table;
+ unsigned long *dirty;
+ struct list_head vmas;
unsigned int iommu_map_cnt;
struct rb_root iommu_maps;
int marked;
@@ -179,6 +181,15 @@
};
/**
+ * ion_buffer_fault_user_mappings - fault in user mappings of this buffer
+ * @buffer: buffer
+ *
+ * indicates whether userspace mappings of this buffer will be faulted
+ * in, this can affect how buffers are allocated from the heap.
+ */
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer);
+
+/**
* struct mem_map_data - represents information about the memory map for a heap
* @node: rb node used to store in the tree of mem_map_data
* @addr: start address of memory region.
@@ -330,4 +341,16 @@
int ion_heap_allow_heap_secure(enum ion_heap_type type);
int ion_heap_allow_handle_secure(enum ion_heap_type type);
+
+/**
+ * ion_create_chunked_sg_table - helper function to create sg table
+ * with specified chunk size
+ * @buffer_base: The starting address used for the sg dma address
+ * @chunk_size: The size of each entry in the sg table
+ * @total_size: The total size of the sg table (i.e. the sum of the
+ * entries). This will be rounded up to the nearest
+ * multiple of `chunk_size'
+ */
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+ size_t chunk_size, size_t total_size);
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 7ca2cd2..ceb30a4 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -15,7 +15,10 @@
*
*/
+#include <asm/page.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
+#include <linux/highmem.h>
#include <linux/ion.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
@@ -35,6 +38,37 @@
static unsigned int system_heap_has_outer_cache;
static unsigned int system_heap_contig_has_outer_cache;
+struct page_info {
+ struct page *page;
+ unsigned long order;
+ struct list_head list;
+};
+
+static struct page_info *alloc_largest_available(unsigned long size,
+ bool split_pages)
+{
+ static unsigned int orders[] = {8, 4, 0};
+ struct page *page;
+ struct page_info *info;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(orders); i++) {
+ if (size < (1 << orders[i]) * PAGE_SIZE)
+ continue;
+ page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO |
+ __GFP_NOWARN | __GFP_NORETRY, orders[i]);
+ if (!page)
+ continue;
+ if (split_pages)
+ split_page(page, orders[i]);
+ info = kmap(page);
+ info->page = page;
+ info->order = orders[i];
+ return info;
+ }
+ return NULL;
+}
+
static int ion_system_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
@@ -42,31 +76,73 @@
{
struct sg_table *table;
struct scatterlist *sg;
- int i, j;
- int npages = PAGE_ALIGN(size) / PAGE_SIZE;
+ int ret;
+ struct list_head pages;
+ struct page_info *info, *tmp_info;
+ int i = 0;
+ long size_remaining = PAGE_ALIGN(size);
+ bool split_pages = ion_buffer_fault_user_mappings(buffer);
+
+
+ INIT_LIST_HEAD(&pages);
+ while (size_remaining > 0) {
+ info = alloc_largest_available(size_remaining, split_pages);
+ if (!info)
+ goto err;
+ list_add_tail(&info->list, &pages);
+ size_remaining -= (1 << info->order) * PAGE_SIZE;
+ i++;
+ }
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
- return -ENOMEM;
- i = sg_alloc_table(table, npages, GFP_KERNEL);
- if (i)
- goto err0;
- for_each_sg(table->sgl, sg, table->nents, i) {
- struct page *page;
- page = alloc_page(GFP_KERNEL|__GFP_ZERO);
- if (!page)
- goto err1;
- sg_set_page(sg, page, PAGE_SIZE, 0);
+ goto err;
+
+ if (split_pages)
+ ret = sg_alloc_table(table, PAGE_ALIGN(size) / PAGE_SIZE,
+ GFP_KERNEL);
+ else
+ ret = sg_alloc_table(table, i, GFP_KERNEL);
+
+ if (ret)
+ goto err1;
+
+ sg = table->sgl;
+ list_for_each_entry_safe(info, tmp_info, &pages, list) {
+ struct page *page = info->page;
+
+ if (split_pages) {
+ for (i = 0; i < (1 << info->order); i++) {
+ sg_set_page(sg, page + i, PAGE_SIZE, 0);
+ sg = sg_next(sg);
+ }
+ } else {
+ sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE,
+ 0);
+ sg = sg_next(sg);
+ }
+ list_del(&info->list);
+ kunmap(page);
}
+
+ dma_sync_sg_for_device(NULL, table->sgl, table->nents,
+ DMA_BIDIRECTIONAL);
+
buffer->priv_virt = table;
atomic_add(size, &system_heap_allocated);
return 0;
err1:
- for_each_sg(table->sgl, sg, i, j)
- __free_page(sg_page(sg));
- sg_free_table(table);
-err0:
kfree(table);
+err:
+ list_for_each_entry(info, &pages, list) {
+ if (split_pages)
+ for (i = 0; i < (1 << info->order); i++)
+ __free_page(info->page + i);
+ else
+ __free_pages(info->page, info->order);
+
+ kunmap(info->page);
+ }
return -ENOMEM;
}
@@ -77,7 +153,7 @@
struct sg_table *table = buffer->priv_virt;
for_each_sg(table->sgl, sg, table->nents, i)
- __free_page(sg_page(sg));
+ __free_pages(sg_page(sg), get_order(sg_dma_len(sg)));
if (buffer->sg_table)
sg_free_table(buffer->sg_table);
kfree(buffer->sg_table);
@@ -99,25 +175,33 @@
void *ion_system_heap_map_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- if (!ION_IS_CACHED(buffer->flags)) {
- pr_err("%s: cannot map system heap uncached\n", __func__);
- return ERR_PTR(-EINVAL);
- } else {
- struct scatterlist *sg;
- int i;
- void *vaddr;
- struct sg_table *table = buffer->priv_virt;
- struct page **pages = kmalloc(
- sizeof(struct page *) * table->nents,
- GFP_KERNEL);
+ struct scatterlist *sg;
+ int i, j;
+ void *vaddr;
+ pgprot_t pgprot;
+ struct sg_table *table = buffer->priv_virt;
+ int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+ struct page **pages = kzalloc(sizeof(struct page *) * npages,
+ GFP_KERNEL);
+ struct page **tmp = pages;
- for_each_sg(table->sgl, sg, table->nents, i)
- pages[i] = sg_page(sg);
- vaddr = vmap(pages, table->nents, VM_MAP, PAGE_KERNEL);
- kfree(pages);
+ if (buffer->flags & ION_FLAG_CACHED)
+ pgprot = PAGE_KERNEL;
+ else
+ pgprot = pgprot_writecombine(PAGE_KERNEL);
- return vaddr;
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE;
+ struct page *page = sg_page(sg);
+ BUG_ON(i >= npages);
+ for (j = 0; j < npages_this_entry; j++) {
+ *(tmp++) = page++;
+ }
}
+ vaddr = vmap(pages, npages, VM_MAP, pgprot);
+ kfree(pages);
+
+ return vaddr;
}
void ion_system_heap_unmap_kernel(struct ion_heap *heap,
@@ -155,26 +239,27 @@
int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
+ struct sg_table *table = buffer->priv_virt;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff;
+ struct scatterlist *sg;
+ int i;
+
if (!ION_IS_CACHED(buffer->flags)) {
pr_err("%s: cannot map system heap uncached\n", __func__);
return -EINVAL;
- } else {
- struct sg_table *table = buffer->priv_virt;
- unsigned long addr = vma->vm_start;
- unsigned long offset = vma->vm_pgoff;
- struct scatterlist *sg;
- int i;
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- if (offset) {
- offset--;
- continue;
- }
- vm_insert_page(vma, addr, sg_page(sg));
- addr += PAGE_SIZE;
- }
- return 0;
}
+
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ if (offset) {
+ offset--;
+ continue;
+ }
+ remap_pfn_range(vma, addr, page_to_pfn(sg_page(sg)),
+ sg_dma_len(sg), vma->vm_page_prot);
+ addr += sg_dma_len(sg);
+ }
+ return 0;
}
int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
@@ -271,6 +356,14 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
+ /* Use the biggest alignment to allow bigger IOMMU mappings.
+ * Use the first entry since the first entry will always be the
+ * biggest entry. To take advantage of bigger mapping sizes both the
+ * VA and PA addresses have to be aligned to the biggest size.
+ */
+ if (table->sgl->length > align)
+ align = table->sgl->length;
+
ret = msm_allocate_iova_address(domain_num, partition_num,
data->mapped_size, align,
&data->iova_addr);
@@ -374,7 +467,7 @@
}
struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
- struct ion_buffer *buffer)
+ struct ion_buffer *buffer)
{
struct sg_table *table;
int ret;
@@ -392,6 +485,13 @@
return table;
}
+void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ sg_free_table(buffer->sg_table);
+ kfree(buffer->sg_table);
+}
+
int ion_system_contig_heap_map_user(struct ion_heap *heap,
struct ion_buffer *buffer,
struct vm_area_struct *vma)
@@ -553,7 +653,7 @@
.free = ion_system_contig_heap_free,
.phys = ion_system_contig_heap_phys,
.map_dma = ion_system_contig_heap_map_dma,
- .unmap_dma = ion_system_heap_unmap_dma,
+ .unmap_dma = ion_system_contig_heap_unmap_dma,
.map_kernel = ion_system_contig_heap_map_kernel,
.unmap_kernel = ion_system_contig_heap_unmap_kernel,
.map_user = ion_system_contig_heap_map_user,
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index ed351bd..a2f0e60 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -66,15 +66,103 @@
#define A3XX_RBBM_INT_0_MASK 0x063
#define A3XX_RBBM_INT_0_STATUS 0x064
#define A3XX_RBBM_PERFCTR_CTL 0x80
+#define A3XX_RBBM_PERFCTR_LOAD_CMD0 0x81
+#define A3XX_RBBM_PERFCTR_LOAD_CMD1 0x82
+#define A3XX_RBBM_PERFCTR_LOAD_VALUE_LO 0x84
+#define A3XX_RBBM_PERFCTR_LOAD_VALUE_HI 0x85
+#define A3XX_RBBM_PERFCOUNTER0_SELECT 0x86
+#define A3XX_RBBM_PERFCOUNTER1_SELECT 0x87
#define A3XX_RBBM_GPU_BUSY_MASKED 0x88
+#define A3XX_RBBM_PERFCTR_CP_0_LO 0x90
+#define A3XX_RBBM_PERFCTR_CP_0_HI 0x91
+#define A3XX_RBBM_PERFCTR_RBBM_0_LO 0x92
+#define A3XX_RBBM_PERFCTR_RBBM_0_HI 0x93
+#define A3XX_RBBM_PERFCTR_RBBM_1_LO 0x94
+#define A3XX_RBBM_PERFCTR_RBBM_1_HI 0x95
+#define A3XX_RBBM_PERFCTR_PC_0_LO 0x96
+#define A3XX_RBBM_PERFCTR_PC_0_HI 0x97
+#define A3XX_RBBM_PERFCTR_PC_1_LO 0x98
+#define A3XX_RBBM_PERFCTR_PC_1_HI 0x99
+#define A3XX_RBBM_PERFCTR_PC_2_LO 0x9A
+#define A3XX_RBBM_PERFCTR_PC_2_HI 0x9B
+#define A3XX_RBBM_PERFCTR_PC_3_LO 0x9C
+#define A3XX_RBBM_PERFCTR_PC_3_HI 0x9D
+#define A3XX_RBBM_PERFCTR_VFD_0_LO 0x9E
+#define A3XX_RBBM_PERFCTR_VFD_0_HI 0x9F
+#define A3XX_RBBM_PERFCTR_VFD_1_LO 0xA0
+#define A3XX_RBBM_PERFCTR_VFD_1_HI 0xA1
+#define A3XX_RBBM_PERFCTR_HLSQ_0_LO 0xA2
+#define A3XX_RBBM_PERFCTR_HLSQ_0_HI 0xA3
+#define A3XX_RBBM_PERFCTR_HLSQ_1_LO 0xA4
+#define A3XX_RBBM_PERFCTR_HLSQ_1_HI 0xA5
+#define A3XX_RBBM_PERFCTR_HLSQ_2_LO 0xA6
+#define A3XX_RBBM_PERFCTR_HLSQ_2_HI 0xA7
+#define A3XX_RBBM_PERFCTR_HLSQ_3_LO 0xA8
+#define A3XX_RBBM_PERFCTR_HLSQ_3_HI 0xA9
+#define A3XX_RBBM_PERFCTR_HLSQ_4_LO 0xAA
+#define A3XX_RBBM_PERFCTR_HLSQ_4_HI 0xAB
+#define A3XX_RBBM_PERFCTR_HLSQ_5_LO 0xAC
+#define A3XX_RBBM_PERFCTR_HLSQ_5_HI 0xAD
+#define A3XX_RBBM_PERFCTR_VPC_0_LO 0xAE
+#define A3XX_RBBM_PERFCTR_VPC_0_HI 0xAF
+#define A3XX_RBBM_PERFCTR_VPC_1_LO 0xB0
+#define A3XX_RBBM_PERFCTR_VPC_1_HI 0xB1
+#define A3XX_RBBM_PERFCTR_TSE_0_LO 0xB2
+#define A3XX_RBBM_PERFCTR_TSE_0_HI 0xB3
+#define A3XX_RBBM_PERFCTR_TSE_1_LO 0xB4
+#define A3XX_RBBM_PERFCTR_TSE_1_HI 0xB5
+#define A3XX_RBBM_PERFCTR_RAS_0_LO 0xB6
+#define A3XX_RBBM_PERFCTR_RAS_0_HI 0xB7
+#define A3XX_RBBM_PERFCTR_RAS_1_LO 0xB8
+#define A3XX_RBBM_PERFCTR_RAS_1_HI 0xB9
+#define A3XX_RBBM_PERFCTR_UCHE_0_LO 0xBA
+#define A3XX_RBBM_PERFCTR_UCHE_0_HI 0xBB
+#define A3XX_RBBM_PERFCTR_UCHE_1_LO 0xBC
+#define A3XX_RBBM_PERFCTR_UCHE_1_HI 0xBD
+#define A3XX_RBBM_PERFCTR_UCHE_2_LO 0xBE
+#define A3XX_RBBM_PERFCTR_UCHE_2_HI 0xBF
+#define A3XX_RBBM_PERFCTR_UCHE_3_LO 0xC0
+#define A3XX_RBBM_PERFCTR_UCHE_3_HI 0xC1
+#define A3XX_RBBM_PERFCTR_UCHE_4_LO 0xC2
+#define A3XX_RBBM_PERFCTR_UCHE_4_HI 0xC3
+#define A3XX_RBBM_PERFCTR_UCHE_5_LO 0xC4
+#define A3XX_RBBM_PERFCTR_UCHE_5_HI 0xC5
+#define A3XX_RBBM_PERFCTR_TP_0_LO 0xC6
+#define A3XX_RBBM_PERFCTR_TP_0_HI 0xC7
+#define A3XX_RBBM_PERFCTR_TP_1_LO 0xC8
+#define A3XX_RBBM_PERFCTR_TP_1_HI 0xC9
+#define A3XX_RBBM_PERFCTR_TP_2_LO 0xCA
+#define A3XX_RBBM_PERFCTR_TP_2_HI 0xCB
+#define A3XX_RBBM_PERFCTR_TP_3_LO 0xCC
+#define A3XX_RBBM_PERFCTR_TP_3_HI 0xCD
+#define A3XX_RBBM_PERFCTR_TP_4_LO 0xCE
+#define A3XX_RBBM_PERFCTR_TP_4_HI 0xCF
+#define A3XX_RBBM_PERFCTR_TP_5_LO 0xD0
+#define A3XX_RBBM_PERFCTR_TP_5_HI 0xD1
+#define A3XX_RBBM_PERFCTR_SP_0_LO 0xD2
+#define A3XX_RBBM_PERFCTR_SP_0_HI 0xD3
+#define A3XX_RBBM_PERFCTR_SP_1_LO 0xD4
+#define A3XX_RBBM_PERFCTR_SP_1_HI 0xD5
+#define A3XX_RBBM_PERFCTR_SP_2_LO 0xD6
+#define A3XX_RBBM_PERFCTR_SP_2_HI 0xD7
+#define A3XX_RBBM_PERFCTR_SP_3_LO 0xD8
+#define A3XX_RBBM_PERFCTR_SP_3_HI 0xD9
+#define A3XX_RBBM_PERFCTR_SP_4_LO 0xDA
+#define A3XX_RBBM_PERFCTR_SP_4_HI 0xDB
#define A3XX_RBBM_PERFCTR_SP_5_LO 0xDC
#define A3XX_RBBM_PERFCTR_SP_5_HI 0xDD
#define A3XX_RBBM_PERFCTR_SP_6_LO 0xDE
#define A3XX_RBBM_PERFCTR_SP_6_HI 0xDF
#define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0
#define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1
+#define A3XX_RBBM_PERFCTR_RB_0_LO 0xE2
+#define A3XX_RBBM_PERFCTR_RB_0_HI 0xE3
+#define A3XX_RBBM_PERFCTR_RB_1_LO 0xE4
+#define A3XX_RBBM_PERFCTR_RB_1_HI 0xE5
+
#define A3XX_RBBM_RBBM_CTL 0x100
-#define A3XX_RBBM_RBBM_CTL 0x100
+#define A3XX_RBBM_PERFCTR_PWR_0_LO 0x0EA
+#define A3XX_RBBM_PERFCTR_PWR_0_HI 0x0EB
#define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
#define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
#define A3XX_RBBM_DEBUG_BUS_CTL 0x111
@@ -90,6 +178,7 @@
#define A3XX_CP_MERCIU_DATA2 0x1D3
#define A3XX_CP_MEQ_ADDR 0x1DA
#define A3XX_CP_MEQ_DATA 0x1DB
+#define A3XX_CP_PERFCOUNTER_SELECT 0x445
#define A3XX_CP_HW_FAULT 0x45C
#define A3XX_CP_AHB_FAULT 0x54D
#define A3XX_CP_PROTECT_CTRL 0x45E
@@ -138,6 +227,14 @@
#define A3XX_VSC_PIPE_CONFIG_7 0xC1B
#define A3XX_VSC_PIPE_DATA_ADDRESS_7 0xC1C
#define A3XX_VSC_PIPE_DATA_LENGTH_7 0xC1D
+#define A3XX_PC_PERFCOUNTER0_SELECT 0xC48
+#define A3XX_PC_PERFCOUNTER1_SELECT 0xC49
+#define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A
+#define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B
+#define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88
+#define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89
+#define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A
+#define A3XX_GRAS_PERFCOUNTER3_SELECT 0xC8B
#define A3XX_GRAS_CL_USER_PLANE_X0 0xCA0
#define A3XX_GRAS_CL_USER_PLANE_Y0 0xCA1
#define A3XX_GRAS_CL_USER_PLANE_Z0 0xCA2
@@ -163,14 +260,42 @@
#define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
#define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
#define A3XX_RB_GMEM_BASE_ADDR 0xCC0
+#define A3XX_RB_PERFCOUNTER0_SELECT 0xCC6
+#define A3XX_RB_PERFCOUNTER1_SELECT 0xCC7
+#define A3XX_HLSQ_PERFCOUNTER0_SELECT 0xE00
+#define A3XX_HLSQ_PERFCOUNTER1_SELECT 0xE01
+#define A3XX_HLSQ_PERFCOUNTER2_SELECT 0xE02
+#define A3XX_HLSQ_PERFCOUNTER3_SELECT 0xE03
+#define A3XX_HLSQ_PERFCOUNTER4_SELECT 0xE04
+#define A3XX_HLSQ_PERFCOUNTER5_SELECT 0xE05
#define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44
+#define A3XX_VFD_PERFCOUNTER1_SELECT 0xE45
#define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
#define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
+#define A3XX_VPC_PERFCOUNTER0_SELECT 0xE64
+#define A3XX_VPC_PERFCOUNTER1_SELECT 0xE65
#define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
+#define A3XX_UCHE_PERFCOUNTER0_SELECT 0xE84
+#define A3XX_UCHE_PERFCOUNTER1_SELECT 0xE85
+#define A3XX_UCHE_PERFCOUNTER2_SELECT 0xE86
+#define A3XX_UCHE_PERFCOUNTER3_SELECT 0xE87
+#define A3XX_UCHE_PERFCOUNTER4_SELECT 0xE88
+#define A3XX_UCHE_PERFCOUNTER5_SELECT 0xE89
#define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
+#define A3XX_SP_PERFCOUNTER0_SELECT 0xEC4
+#define A3XX_SP_PERFCOUNTER1_SELECT 0xEC5
+#define A3XX_SP_PERFCOUNTER2_SELECT 0xEC6
+#define A3XX_SP_PERFCOUNTER3_SELECT 0xEC7
+#define A3XX_SP_PERFCOUNTER4_SELECT 0xEC8
#define A3XX_SP_PERFCOUNTER5_SELECT 0xEC9
#define A3XX_SP_PERFCOUNTER6_SELECT 0xECA
#define A3XX_SP_PERFCOUNTER7_SELECT 0xECB
+#define A3XX_TP_PERFCOUNTER0_SELECT 0xF04
+#define A3XX_TP_PERFCOUNTER1_SELECT 0xF05
+#define A3XX_TP_PERFCOUNTER2_SELECT 0xF06
+#define A3XX_TP_PERFCOUNTER3_SELECT 0xF07
+#define A3XX_TP_PERFCOUNTER4_SELECT 0xF08
+#define A3XX_TP_PERFCOUNTER5_SELECT 0xF09
#define A3XX_GRAS_CL_CLIP_CNTL 0x2040
#define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
#define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
@@ -273,8 +398,10 @@
#define A3XX_VBIF_OUT_AXI_AOOO 0x305F
/* Bit flags for RBBM_CTL */
-#define RBBM_RBBM_CTL_RESET_PWR_CTR1 (1 << 1)
-#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1 (1 << 17)
+#define RBBM_RBBM_CTL_RESET_PWR_CTR0 BIT(0)
+#define RBBM_RBBM_CTL_RESET_PWR_CTR1 BIT(1)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR0 BIT(16)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1 BIT(17)
/* Various flags used by the context switch code */
@@ -540,6 +667,7 @@
/* RBBM_CLOCK_CTL default value */
#define A305_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAA
+#define A305C_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAA
#define A320_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF
#define A330_RBBM_CLOCK_CTL_DEFAULT 0xBFFCFFFF
#define A330v2_RBBM_CLOCK_CTL_DEFAULT 0xBFFCFFFF
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 9f4d791..6f7e61d 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -213,8 +213,318 @@
{ ADRENO_REV_A305B, 3, 0, 5, 0x10,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_128K, NO_VER, NO_VER },
+ { ADRENO_REV_A305C, 3, 0, 5, 0x20,
+ "a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
+ 512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
};
+/**
+ * adreno_perfcounter_init: Reserve kernel performance counters
+ * @device: device to configure
+ *
+ * The kernel needs/wants a certain group of performance counters for
+ * its own activities. Reserve these performance counters at init time
+ * to ensure that they are always reserved for the kernel. The performance
+ * counters used by the kernel can be obtained by the user, but these
+ * performance counters will remain active as long as the device is alive.
+ */
+
+static void adreno_perfcounter_init(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ if (adreno_dev->gpudev->perfcounter_init)
+ adreno_dev->gpudev->perfcounter_init(adreno_dev);
+};
+
+/**
+ * adreno_perfcounter_start: Enable performance counters
+ * @adreno_dev: Adreno device to configure
+ *
+ * Ensure all performance counters are enabled that are allocated. Since
+ * the device was most likely stopped, we can't trust that the counters
+ * are still valid so make it so.
+ */
+
+static void adreno_perfcounter_start(struct adreno_device *adreno_dev)
+{
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ unsigned int i, j;
+
+ /* group id iter */
+ for (i = 0; i < counters->group_count; i++) {
+ group = &(counters->groups[i]);
+
+ /* countable iter */
+ for (j = 0; j < group->reg_count; j++) {
+ if (group->regs[j].countable ==
+ KGSL_PERFCOUNTER_NOT_USED)
+ continue;
+
+ if (adreno_dev->gpudev->perfcounter_enable)
+ adreno_dev->gpudev->perfcounter_enable(
+ adreno_dev, i, j,
+ group->regs[j].countable);
+ }
+ }
+}
+
+/**
+ * adreno_perfcounter_read_group: Determine which countables are in counters
+ * @adreno_dev: Adreno device to configure
+ * @reads: List of kgsl_perfcounter_read_groups
+ * @count: Length of list
+ *
+ * Read the performance counters for the groupid/countable pairs and return
+ * the 64 bit result for each pair
+ */
+
+int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
+ struct kgsl_perfcounter_read_group *reads, unsigned int count)
+{
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ struct kgsl_perfcounter_read_group *list = NULL;
+ unsigned int i, j;
+ int ret = 0;
+
+ /* perfcounter get/put/query/read not allowed on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return -EINVAL;
+
+ /* sanity check for later */
+ if (!adreno_dev->gpudev->perfcounter_read)
+ return -EINVAL;
+
+ /* sanity check params passed in */
+ if (reads == NULL || count == 0 || count > 100)
+ return -EINVAL;
+
+ /* verify valid inputs group ids and countables */
+ for (i = 0; i < count; i++) {
+ if (reads[i].groupid >= counters->group_count)
+ return -EINVAL;
+ }
+
+ list = kmalloc(sizeof(struct kgsl_perfcounter_read_group) * count,
+ GFP_KERNEL);
+ if (!list)
+ return -ENOMEM;
+
+ if (copy_from_user(list, reads,
+ sizeof(struct kgsl_perfcounter_read_group) * count)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* list iterator */
+ for (j = 0; j < count; j++) {
+ list[j].value = 0;
+
+ group = &(counters->groups[list[j].groupid]);
+
+ /* group/counter iterator */
+ for (i = 0; i < group->reg_count; i++) {
+ if (group->regs[i].countable == list[j].countable) {
+ list[j].value =
+ adreno_dev->gpudev->perfcounter_read(
+ adreno_dev, list[j].groupid,
+ i, group->regs[i].offset);
+ break;
+ }
+ }
+ }
+
+ /* write the data */
+ if (copy_to_user(reads, list,
+ sizeof(struct kgsl_perfcounter_read_group) *
+ count) != 0)
+ ret = -EFAULT;
+
+done:
+ kfree(list);
+ return ret;
+}
+
+/**
+ * adreno_perfcounter_query_group: Determine which countables are in counters
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countables: Return list of all countables in the groups counters
+ * @count: Max length of the array
+ * @max_counters: max counters for the groupid
+ *
+ * Query the current state of counters for the group.
+ */
+
+int adreno_perfcounter_query_group(struct adreno_device *adreno_dev,
+ unsigned int groupid, unsigned int *countables, unsigned int count,
+ unsigned int *max_counters)
+{
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ unsigned int i;
+
+ *max_counters = 0;
+
+ /* perfcounter get/put/query not allowed on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return -EINVAL;
+
+ if (groupid >= counters->group_count)
+ return -EINVAL;
+
+ group = &(counters->groups[groupid]);
+ *max_counters = group->reg_count;
+
+ /*
+ * if NULL countable or *count of zero, return max reg_count in
+ * *max_counters and return success
+ */
+ if (countables == NULL || count == 0)
+ return 0;
+
+ /*
+ * Go through all available counters. Write upto *count * countable
+ * values.
+ */
+ for (i = 0; i < group->reg_count && i < count; i++) {
+ if (copy_to_user(&countables[i], &(group->regs[i].countable),
+ sizeof(unsigned int)) != 0)
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * adreno_perfcounter_get: Try to put a countable in an available counter
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countable: Countable desired to be in a counter
+ * @offset: Return offset of the countable
+ * @flags: Used to setup kernel perf counters
+ *
+ * Try to place a countable in an available counter. If the countable is
+ * already in a counter, reference count the counter/countable pair resource
+ * and return success
+ */
+
+int adreno_perfcounter_get(struct adreno_device *adreno_dev,
+ unsigned int groupid, unsigned int countable, unsigned int *offset,
+ unsigned int flags)
+{
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ unsigned int i, empty = -1;
+
+ /* always clear return variables */
+ if (offset)
+ *offset = 0;
+
+ /* perfcounter get/put/query not allowed on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return -EINVAL;
+
+ if (groupid >= counters->group_count)
+ return -EINVAL;
+
+ group = &(counters->groups[groupid]);
+
+ /*
+ * Check if the countable is already associated with a counter.
+ * Refcount and return the offset, otherwise, try and find an empty
+ * counter and assign the countable to it.
+ */
+ for (i = 0; i < group->reg_count; i++) {
+ if (group->regs[i].countable == countable) {
+ /* Countable already associated with counter */
+ group->regs[i].refcount++;
+ group->regs[i].flags |= flags;
+ if (offset)
+ *offset = group->regs[i].offset;
+ return 0;
+ } else if (group->regs[i].countable ==
+ KGSL_PERFCOUNTER_NOT_USED) {
+ /* keep track of unused counter */
+ empty = i;
+ }
+ }
+
+ /* no available counters, so do nothing else */
+ if (empty == -1)
+ return -EBUSY;
+
+ /* initialize the new counter */
+ group->regs[empty].countable = countable;
+ group->regs[empty].refcount = 1;
+
+ /* enable the new counter */
+ adreno_dev->gpudev->perfcounter_enable(adreno_dev, groupid, empty,
+ countable);
+
+ group->regs[empty].flags = flags;
+
+ if (offset)
+ *offset = group->regs[empty].offset;
+
+ return 0;
+}
+
+
+/**
+ * adreno_perfcounter_put: Release a countable from counter resource
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countable: Countable desired to be freed from a counter
+ *
+ * Put a performance counter/countable pair that was previously received. If
+ * noone else is using the countable, free up the counter for others.
+ */
+int adreno_perfcounter_put(struct adreno_device *adreno_dev,
+ unsigned int groupid, unsigned int countable)
+{
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+
+ unsigned int i;
+
+ /* perfcounter get/put/query not allowed on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return -EINVAL;
+
+ if (groupid >= counters->group_count)
+ return -EINVAL;
+
+ group = &(counters->groups[groupid]);
+
+ for (i = 0; i < group->reg_count; i++) {
+ if (group->regs[i].countable == countable) {
+ if (group->regs[i].refcount > 0) {
+ group->regs[i].refcount--;
+
+ /*
+ * book keeping to ensure we never free a
+ * perf counter used by kernel
+ */
+ if (group->regs[i].flags &&
+ group->regs[i].refcount == 0)
+ group->regs[i].refcount++;
+
+ /* make available if not used */
+ if (group->regs[i].refcount == 0)
+ group->regs[i].countable =
+ KGSL_PERFCOUNTER_NOT_USED;
+ }
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
{
irqreturn_t result;
@@ -310,8 +620,14 @@
struct kgsl_context *context;
struct adreno_context *adreno_ctx = NULL;
- if (!adreno_dev->drawctxt_active)
+ /*
+ * If we're idle and we don't need to use the GPU to save context
+ * state, use the CPU instead of the GPU to reprogram the
+ * iommu for simplicity's sake.
+ */
+ if (!adreno_dev->drawctxt_active || device->ftbl->isidle(device))
return kgsl_mmu_device_setstate(&device->mmu, flags);
+
num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
context = idr_find(&device->context_idr, context_id);
@@ -1225,10 +1541,10 @@
return 0;
}
-static int adreno_start(struct kgsl_device *device, unsigned int init_ram)
+static int adreno_init(struct kgsl_device *device)
{
- int status = -EINVAL;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
if (KGSL_STATE_DUMP_AND_FT != device->state)
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
@@ -1254,10 +1570,9 @@
if (adreno_dev->gpurev == ADRENO_REV_UNKNOWN) {
KGSL_DRV_ERR(device, "Unknown chip ID %x\n",
adreno_dev->chip_id);
- goto error_clk_off;
+ BUG_ON(1);
}
-
/*
* Check if firmware supports the sync lock PM4 packets needed
* for IOMMUv1
@@ -1269,7 +1584,32 @@
adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pfp_ver))
device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC;
- /* Set up the MMU */
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
+
+ /* Assign correct RBBM status register to hang detect regs
+ */
+ ft_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
+
+ adreno_perfcounter_init(device);
+
+ /* Power down the device */
+ kgsl_pwrctrl_disable(device);
+
+ return 0;
+}
+
+static int adreno_start(struct kgsl_device *device)
+{
+ int status = -EINVAL;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ if (KGSL_STATE_DUMP_AND_FT != device->state)
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+
+ /* Power up the device */
+ kgsl_pwrctrl_enable(device);
+
+ /* Set up a2xx special case */
if (adreno_is_a2xx(adreno_dev)) {
/*
* the MH_CLNT_INTF_CTRL_CONFIG registers aren't present
@@ -1283,20 +1623,6 @@
kgsl_mh_start(device);
}
- /* Assign correct RBBM status register to hang detect regs
- */
- ft_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
-
- /* Add A3XX specific registers for hang detection */
- if (adreno_is_a3xx(adreno_dev)) {
- ft_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
- ft_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
- ft_detect_regs[8] = A3XX_RBBM_PERFCTR_SP_6_LO;
- ft_detect_regs[9] = A3XX_RBBM_PERFCTR_SP_6_HI;
- ft_detect_regs[10] = A3XX_RBBM_PERFCTR_SP_5_LO;
- ft_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
- }
-
status = kgsl_mmu_start(device);
if (status)
goto error_clk_off;
@@ -1313,7 +1639,7 @@
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
device->ftbl->irqctrl(device, 1);
- status = adreno_ringbuffer_start(&adreno_dev->ringbuffer, init_ram);
+ status = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
if (status)
goto error_irq_off;
@@ -1322,6 +1648,8 @@
if (KGSL_STATE_DUMP_AND_FT != device->state)
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
+ adreno_perfcounter_start(adreno_dev);
+
device->reset_counter++;
return 0;
@@ -1712,7 +2040,12 @@
return 1;
}
- if (adreno_start(device, true)) {
+ if (adreno_init(device)) {
+ KGSL_FT_ERR(device, "Device init failed\n");
+ return 1;
+ }
+
+ if (adreno_start(device)) {
KGSL_FT_ERR(device, "Device start failed\n");
return 1;
}
@@ -3173,27 +3506,55 @@
static long adreno_ioctl(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
+ struct kgsl_device *device = dev_priv->device;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int result = 0;
- struct kgsl_drawctxt_set_bin_base_offset *binbase;
- struct kgsl_context *context;
switch (cmd) {
- case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET:
+ case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET: {
+ struct kgsl_drawctxt_set_bin_base_offset *binbase = data;
+ struct kgsl_context *context;
+
binbase = data;
context = kgsl_find_context(dev_priv, binbase->drawctxt_id);
if (context) {
adreno_drawctxt_set_bin_base_offset(
- dev_priv->device, context, binbase->offset);
+ device, context, binbase->offset);
} else {
result = -EINVAL;
- KGSL_DRV_ERR(dev_priv->device,
+ KGSL_DRV_ERR(device,
"invalid drawctxt drawctxt_id %d "
"device_id=%d\n",
- binbase->drawctxt_id, dev_priv->device->id);
+ binbase->drawctxt_id, device->id);
}
break;
-
+ }
+ case IOCTL_KGSL_PERFCOUNTER_GET: {
+ struct kgsl_perfcounter_get *get = data;
+ result = adreno_perfcounter_get(adreno_dev, get->groupid,
+ get->countable, &get->offset, PERFCOUNTER_FLAG_NONE);
+ break;
+ }
+ case IOCTL_KGSL_PERFCOUNTER_PUT: {
+ struct kgsl_perfcounter_put *put = data;
+ result = adreno_perfcounter_put(adreno_dev, put->groupid,
+ put->countable);
+ break;
+ }
+ case IOCTL_KGSL_PERFCOUNTER_QUERY: {
+ struct kgsl_perfcounter_query *query = data;
+ result = adreno_perfcounter_query_group(adreno_dev,
+ query->groupid, query->countables,
+ query->count, &query->max_counters);
+ break;
+ }
+ case IOCTL_KGSL_PERFCOUNTER_READ: {
+ struct kgsl_perfcounter_read *read = data;
+ result = adreno_perfcounter_read_group(adreno_dev,
+ read->reads, read->count);
+ break;
+ }
default:
KGSL_DRV_INFO(dev_priv->device,
"invalid ioctl code %08x\n", cmd);
@@ -3270,6 +3631,7 @@
.idle = adreno_idle,
.isidle = adreno_isidle,
.suspend_context = adreno_suspend_context,
+ .init = adreno_init,
.start = adreno_start,
.stop = adreno_stop,
.getproperty = adreno_getproperty,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 6c57078..90d6027 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -73,6 +73,7 @@
ADRENO_REV_A220 = 220,
ADRENO_REV_A225 = 225,
ADRENO_REV_A305 = 305,
+ ADRENO_REV_A305C = 306,
ADRENO_REV_A320 = 320,
ADRENO_REV_A330 = 330,
ADRENO_REV_A305B = 335,
@@ -115,6 +116,44 @@
unsigned int gpu_cycles;
};
+#define PERFCOUNTER_FLAG_NONE 0x0
+#define PERFCOUNTER_FLAG_KERNEL 0x1
+
+/* Structs to maintain the list of active performance counters */
+
+/**
+ * struct adreno_perfcount_register: register state
+ * @countable: countable the register holds
+ * @refcount: number of users of the register
+ * @offset: register hardware offset
+ */
+struct adreno_perfcount_register {
+ unsigned int countable;
+ unsigned int refcount;
+ unsigned int offset;
+ unsigned int flags;
+};
+
+/**
+ * struct adreno_perfcount_group: registers for a hardware group
+ * @regs: available registers for this group
+ * @reg_count: total registers for this group
+ */
+struct adreno_perfcount_group {
+ struct adreno_perfcount_register *regs;
+ unsigned int reg_count;
+};
+
+/**
+ * adreno_perfcounts: all available perfcounter groups
+ * @groups: available groups for this device
+ * @group_count: total groups for this device
+ */
+struct adreno_perfcounters {
+ struct adreno_perfcount_group *groups;
+ unsigned int group_count;
+};
+
struct adreno_gpudev {
/*
* These registers are in a different location on A3XX, so define
@@ -126,6 +165,8 @@
/* keeps track of when we need to execute the draw workaround code */
int ctx_switches_since_last_draw;
+ struct adreno_perfcounters *perfcounters;
+
/* GPU specific function hooks */
int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
@@ -137,8 +178,14 @@
unsigned int (*irq_pending)(struct adreno_device *);
void * (*snapshot)(struct adreno_device *, void *, int *, int);
int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
+ void (*perfcounter_init)(struct adreno_device *);
void (*start)(struct adreno_device *);
unsigned int (*busy_cycles)(struct adreno_device *);
+ void (*perfcounter_enable)(struct adreno_device *, unsigned int group,
+ unsigned int counter, unsigned int countable);
+ uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
+ unsigned int group, unsigned int counter,
+ unsigned int offset);
};
/*
@@ -258,6 +305,13 @@
unsigned int adreno_ft_detect(struct kgsl_device *device,
unsigned int *prev_reg_val);
+int adreno_perfcounter_get(struct adreno_device *adreno_dev,
+ unsigned int groupid, unsigned int countable, unsigned int *offset,
+ unsigned int flags);
+
+int adreno_perfcounter_put(struct adreno_device *adreno_dev,
+ unsigned int groupid, unsigned int countable);
+
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
return (adreno_dev->gpurev == ADRENO_REV_A200);
@@ -314,6 +368,11 @@
return (adreno_dev->gpurev == ADRENO_REV_A305B);
}
+static inline int adreno_is_a305c(struct adreno_device *adreno_dev)
+{
+ return (adreno_dev->gpurev == ADRENO_REV_A305C);
+}
+
static inline int adreno_is_a320(struct adreno_device *adreno_dev)
{
return (adreno_dev->gpurev == ADRENO_REV_A320);
@@ -438,6 +497,7 @@
*cmds++ = 0;
if ((adreno_dev->gpurev == ADRENO_REV_A305) ||
+ (adreno_dev->gpurev == ADRENO_REV_A305C) ||
(adreno_dev->gpurev == ADRENO_REV_A320)) {
*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
*cmds++ = 0;
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index f1024d6..19d9ca2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -450,6 +450,8 @@
{
if (adreno_is_a305(adreno_dev))
return A305_RBBM_CLOCK_CTL_DEFAULT;
+ else if (adreno_is_a305c(adreno_dev))
+ return A305C_RBBM_CLOCK_CTL_DEFAULT;
else if (adreno_is_a320(adreno_dev))
return A320_RBBM_CLOCK_CTL_DEFAULT;
else if (adreno_is_a330v2(adreno_dev))
@@ -2603,6 +2605,213 @@
queue_work(device->work_queue, &device->ts_expired_ws);
}
+/**
+ * struct a3xx_perfcounter_register - Define a performance counter register
+ * @load_bit: the bit to set in RBBM_LOAD_CMD0/RBBM_LOAD_CMD1 to force the RBBM
+ * to load the reset value into the appropriate counter
+ * @select: The dword offset of the register to write the selected
+ * countable into
+ */
+
+struct a3xx_perfcounter_register {
+ unsigned int load_bit;
+ unsigned int select;
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_cp[] = {
+ { 0, A3XX_CP_PERFCOUNTER_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rbbm[] = {
+ { 1, A3XX_RBBM_PERFCOUNTER0_SELECT },
+ { 2, A3XX_RBBM_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_pc[] = {
+ { 3, A3XX_PC_PERFCOUNTER0_SELECT },
+ { 4, A3XX_PC_PERFCOUNTER1_SELECT },
+ { 5, A3XX_PC_PERFCOUNTER2_SELECT },
+ { 6, A3XX_PC_PERFCOUNTER3_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vfd[] = {
+ { 7, A3XX_VFD_PERFCOUNTER0_SELECT },
+ { 8, A3XX_VFD_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_hlsq[] = {
+ { 9, A3XX_HLSQ_PERFCOUNTER0_SELECT },
+ { 10, A3XX_HLSQ_PERFCOUNTER1_SELECT },
+ { 11, A3XX_HLSQ_PERFCOUNTER2_SELECT },
+ { 12, A3XX_HLSQ_PERFCOUNTER3_SELECT },
+ { 13, A3XX_HLSQ_PERFCOUNTER4_SELECT },
+ { 14, A3XX_HLSQ_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vpc[] = {
+ { 15, A3XX_VPC_PERFCOUNTER0_SELECT },
+ { 16, A3XX_VPC_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tse[] = {
+ { 17, A3XX_GRAS_PERFCOUNTER0_SELECT },
+ { 18, A3XX_GRAS_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_ras[] = {
+ { 19, A3XX_GRAS_PERFCOUNTER2_SELECT },
+ { 20, A3XX_GRAS_PERFCOUNTER3_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_uche[] = {
+ { 21, A3XX_UCHE_PERFCOUNTER0_SELECT },
+ { 22, A3XX_UCHE_PERFCOUNTER1_SELECT },
+ { 23, A3XX_UCHE_PERFCOUNTER2_SELECT },
+ { 24, A3XX_UCHE_PERFCOUNTER3_SELECT },
+ { 25, A3XX_UCHE_PERFCOUNTER4_SELECT },
+ { 26, A3XX_UCHE_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tp[] = {
+ { 27, A3XX_TP_PERFCOUNTER0_SELECT },
+ { 28, A3XX_TP_PERFCOUNTER1_SELECT },
+ { 29, A3XX_TP_PERFCOUNTER2_SELECT },
+ { 30, A3XX_TP_PERFCOUNTER3_SELECT },
+ { 31, A3XX_TP_PERFCOUNTER4_SELECT },
+ { 32, A3XX_TP_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_sp[] = {
+ { 33, A3XX_SP_PERFCOUNTER0_SELECT },
+ { 34, A3XX_SP_PERFCOUNTER1_SELECT },
+ { 35, A3XX_SP_PERFCOUNTER2_SELECT },
+ { 36, A3XX_SP_PERFCOUNTER3_SELECT },
+ { 37, A3XX_SP_PERFCOUNTER4_SELECT },
+ { 38, A3XX_SP_PERFCOUNTER5_SELECT },
+ { 39, A3XX_SP_PERFCOUNTER6_SELECT },
+ { 40, A3XX_SP_PERFCOUNTER7_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rb[] = {
+ { 41, A3XX_RB_PERFCOUNTER0_SELECT },
+ { 42, A3XX_RB_PERFCOUNTER1_SELECT },
+};
+
+#define REGCOUNTER_GROUP(_x) { (_x), ARRAY_SIZE((_x)) }
+
+static struct {
+ struct a3xx_perfcounter_register *regs;
+ int count;
+} a3xx_perfcounter_reglist[] = {
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_cp),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_rbbm),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_pc),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_vfd),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_hlsq),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_vpc),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_tse),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_ras),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_uche),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_tp),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_sp),
+ REGCOUNTER_GROUP(a3xx_perfcounter_reg_rb),
+};
+
+static void a3xx_perfcounter_enable_pwr(struct kgsl_device *device,
+ unsigned int countable)
+{
+ unsigned int in, out;
+
+ adreno_regread(device, A3XX_RBBM_RBBM_CTL, &in);
+
+ if (countable == 0)
+ out = in | RBBM_RBBM_CTL_RESET_PWR_CTR0;
+ else
+ out = in | RBBM_RBBM_CTL_RESET_PWR_CTR1;
+
+ adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+
+ if (countable == 0)
+ out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR0;
+ else
+ out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR1;
+
+ adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+
+ return;
+}
+
+/*
+ * a3xx_perfcounter_enable - Configure a performance counter for a countable
+ * @adreno_dev - Adreno device to configure
+ * @group - Desired performance counter group
+ * @counter - Desired performance counter in the group
+ * @countable - Desired countable
+ *
+ * Physically set up a counter within a group with the desired countable
+ */
+
+static void a3xx_perfcounter_enable(struct adreno_device *adreno_dev,
+ unsigned int group, unsigned int counter, unsigned int countable)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ unsigned int val = 0;
+ struct a3xx_perfcounter_register *reg;
+
+ if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+ return;
+
+ if (counter > a3xx_perfcounter_reglist[group].count)
+ return;
+
+ /* Special case - power */
+ if (group == KGSL_PERFCOUNTER_GROUP_PWR)
+ return a3xx_perfcounter_enable_pwr(device, countable);
+
+ reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+
+ /* Select the desired perfcounter */
+ adreno_regwrite(device, reg->select, countable);
+
+ if (reg->load_bit < 32) {
+ val = 1 << reg->load_bit;
+ adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
+ } else {
+ val = 1 << (reg->load_bit - 32);
+ adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
+ }
+}
+
+static uint64_t a3xx_perfcounter_read(struct adreno_device *adreno_dev,
+ unsigned int group, unsigned int counter,
+ unsigned int offset)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ struct a3xx_perfcounter_register *reg = NULL;
+ unsigned int lo = 0, hi = 0;
+ unsigned int val;
+
+ if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+ return 0;
+
+ reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+
+ /* Freeze the counter */
+ adreno_regread(device, A3XX_RBBM_PERFCTR_CTL, &val);
+ val &= ~reg->load_bit;
+ adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+
+ /* Read the values */
+ adreno_regread(device, offset, &lo);
+ adreno_regread(device, offset + 1, &hi);
+
+ /* Re-Enable the counter */
+ val |= reg->load_bit;
+ adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+
+ return (((uint64_t) hi) << 32) | lo;
+}
+
#define A3XX_IRQ_CALLBACK(_c) { .func = _c }
#define A3XX_INT_MASK \
@@ -2757,6 +2966,19 @@
{0, 0},
};
+static struct a3xx_vbif_data a305c_vbif[] = {
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x00101010 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x00101010 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00000010 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00000010 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000101 },
+ { A3XX_VBIF_ARB_CTL, 0x00000010 },
+ /* Set up AOOO */
+ { A3XX_VBIF_OUT_AXI_AOOO_EN, 0x00000007 },
+ { A3XX_VBIF_OUT_AXI_AOOO, 0x00070007 },
+ {0, 0},
+};
+
static struct a3xx_vbif_data a320_vbif[] = {
/* Set up 16 deep read/write request queues */
{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
@@ -2828,6 +3050,7 @@
struct a3xx_vbif_data *vbif;
} a3xx_vbif_platforms[] = {
{ adreno_is_a305, a305_vbif },
+ { adreno_is_a305c, a305c_vbif },
{ adreno_is_a320, a320_vbif },
/* A330v2 needs to be ahead of A330 so the right device matches */
{ adreno_is_a330v2, a330v2_vbif },
@@ -2835,12 +3058,45 @@
{ adreno_is_a305b, a305b_vbif },
};
+static void a3xx_perfcounter_init(struct adreno_device *adreno_dev)
+{
+ /*
+ * Set SP to count SP_ALU_ACTIVE_CYCLES, it includes
+ * all ALU instruction execution regardless precision or shader ID.
+ * Set SP to count SP0_ICL1_MISSES, It counts
+ * USP L1 instruction miss request.
+ * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
+ * counts USP flow control instruction execution.
+ * we will use this to augment our hang detection
+ */
+ if (adreno_dev->fast_hang_detect) {
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6],
+ PERFCOUNTER_FLAG_KERNEL);
+ ft_detect_regs[7] = ft_detect_regs[6] + 1;
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP0_ICL1_MISSES, &ft_detect_regs[8],
+ PERFCOUNTER_FLAG_KERNEL);
+ ft_detect_regs[9] = ft_detect_regs[8] + 1;
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
+ PERFCOUNTER_FLAG_KERNEL);
+ ft_detect_regs[11] = ft_detect_regs[10] + 1;
+ }
+
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL);
+
+ /* Reserve and start countable 1 in the PWR perfcounter group */
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
+ NULL, PERFCOUNTER_FLAG_KERNEL);
+}
+
static void a3xx_start(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = &adreno_dev->dev;
struct a3xx_vbif_data *vbif = NULL;
int i;
- unsigned int reg;
for (i = 0; i < ARRAY_SIZE(a3xx_vbif_platforms); i++) {
if (a3xx_vbif_platforms[i].devfunc(adreno_dev)) {
@@ -2904,39 +3160,121 @@
/* Turn on performance counters */
adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
- /*
- * Set SP perfcounter 5 to count SP_ALU_ACTIVE_CYCLES, it includes
- * all ALU instruction execution regardless precision or shader ID.
- * Set SP perfcounter 6 to count SP0_ICL1_MISSES, It counts
- * USP L1 instruction miss request.
- * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS, it
- * counts USP flow control instruction execution.
- * we will use this to augment our hang detection
- */
- if (adreno_dev->fast_hang_detect) {
- adreno_regwrite(device, A3XX_SP_PERFCOUNTER5_SELECT,
- SP_ALU_ACTIVE_CYCLES);
- adreno_regwrite(device, A3XX_SP_PERFCOUNTER6_SELECT,
- SP0_ICL1_MISSES);
- adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
- SP_FS_CFLOW_INSTRUCTIONS);
- }
-
- adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
- SP_FS_FULL_ALU_INSTRUCTIONS);
-
/* Turn on the GPU busy counter and let it run free */
adreno_dev->gpu_cycles = 0;
-
- adreno_regread(device, A3XX_RBBM_RBBM_CTL, ®);
- reg |= RBBM_RBBM_CTL_RESET_PWR_CTR1;
- adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg);
- reg &= ~RBBM_RBBM_CTL_RESET_PWR_CTR1;
- reg |= RBBM_RBBM_CTL_ENABLE_PWR_CTR1;
- adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg);
}
+/*
+ * Define the available perfcounter groups - these get used by
+ * adreno_perfcounter_get and adreno_perfcounter_put
+ */
+
+static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_CP_0_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_1_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_2_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_3_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_1_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_2_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_3_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_4_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_1_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_2_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_3_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_4_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_5_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_6_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_7_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_0_LO, 0 },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_1_LO, 0 },
+};
+
+static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
+ { a3xx_perfcounters_cp, ARRAY_SIZE(a3xx_perfcounters_cp) },
+ { a3xx_perfcounters_rbbm, ARRAY_SIZE(a3xx_perfcounters_rbbm) },
+ { a3xx_perfcounters_pc, ARRAY_SIZE(a3xx_perfcounters_pc) },
+ { a3xx_perfcounters_vfd, ARRAY_SIZE(a3xx_perfcounters_vfd) },
+ { a3xx_perfcounters_hlsq, ARRAY_SIZE(a3xx_perfcounters_hlsq) },
+ { a3xx_perfcounters_vpc, ARRAY_SIZE(a3xx_perfcounters_vpc) },
+ { a3xx_perfcounters_tse, ARRAY_SIZE(a3xx_perfcounters_tse) },
+ { a3xx_perfcounters_ras, ARRAY_SIZE(a3xx_perfcounters_ras) },
+ { a3xx_perfcounters_uche, ARRAY_SIZE(a3xx_perfcounters_uche) },
+ { a3xx_perfcounters_tp, ARRAY_SIZE(a3xx_perfcounters_tp) },
+ { a3xx_perfcounters_sp, ARRAY_SIZE(a3xx_perfcounters_sp) },
+ { a3xx_perfcounters_rb, ARRAY_SIZE(a3xx_perfcounters_rb) },
+ { a3xx_perfcounters_pwr, ARRAY_SIZE(a3xx_perfcounters_pwr) },
+};
+
+static struct adreno_perfcounters a3xx_perfcounters = {
+ a3xx_perfcounter_groups,
+ ARRAY_SIZE(a3xx_perfcounter_groups),
+};
+
/* Defined in adreno_a3xx_snapshot.c */
void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
int *remain, int hang);
@@ -2945,16 +3283,20 @@
.reg_rbbm_status = A3XX_RBBM_STATUS,
.reg_cp_pfp_ucode_addr = A3XX_CP_PFP_UCODE_ADDR,
.reg_cp_pfp_ucode_data = A3XX_CP_PFP_UCODE_DATA,
+ .perfcounters = &a3xx_perfcounters,
.ctxt_create = a3xx_drawctxt_create,
.ctxt_save = a3xx_drawctxt_save,
.ctxt_restore = a3xx_drawctxt_restore,
.ctxt_draw_workaround = NULL,
.rb_init = a3xx_rb_init,
+ .perfcounter_init = a3xx_perfcounter_init,
.irq_control = a3xx_irq_control,
.irq_handler = a3xx_irq_handler,
.irq_pending = a3xx_irq_pending,
.busy_cycles = a3xx_busy_cycles,
.start = a3xx_start,
.snapshot = a3xx_snapshot,
+ .perfcounter_enable = a3xx_perfcounter_enable,
+ .perfcounter_read = a3xx_perfcounter_read,
};
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 29d689b..5396196 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -702,7 +702,7 @@
" %08X\n", r1, r2, r3);
KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ",
- kgsl_mmu_get_ptsize());
+ kgsl_mmu_get_ptsize(&device->mmu));
kgsl_regread(device, MH_MMU_TRAN_ERROR, &r1);
KGSL_LOG_DUMP(device, " TRAN_ERROR = %08X\n", r1);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 4333f2f..8c23a13 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -319,7 +319,7 @@
return 0;
}
-int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
+int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
{
int status;
/*cp_rb_cntl_u cp_rb_cntl; */
@@ -331,9 +331,6 @@
if (rb->flags & KGSL_FLAGS_STARTED)
return 0;
- if (init_ram)
- rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
-
kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
sizeof(struct kgsl_rbmemptrs));
@@ -433,7 +430,8 @@
return status;
/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
- if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
+ if (adreno_is_a305(adreno_dev) || adreno_is_a305c(adreno_dev) ||
+ adreno_is_a320(adreno_dev))
adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
else if (adreno_is_a330(adreno_dev) || adreno_is_a305b(adreno_dev))
adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x003E2008);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index fa03c05..e563ec7 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -97,8 +97,7 @@
int adreno_ringbuffer_init(struct kgsl_device *device);
-int adreno_ringbuffer_start(struct adreno_ringbuffer *rb,
- unsigned int init_ram);
+int adreno_ringbuffer_start(struct adreno_ringbuffer *rb);
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2b0d5d9..af25a3f 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -671,9 +671,10 @@
if (kgsl_mmu_enabled())
{
unsigned long pt_name;
+ struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
pt_name = task_tgid_nr(current);
- private->pagetable = kgsl_mmu_getpagetable(pt_name);
+ private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
if (private->pagetable == NULL) {
kfree(private);
private = NULL;
@@ -821,12 +822,14 @@
kgsl_sharedmem_set(&device->memstore, 0, 0,
device->memstore.size);
- result = device->ftbl->start(device, true);
-
- if (result) {
- mutex_unlock(&device->mutex);
+ result = device->ftbl->init(device);
+ if (result)
goto err_freedevpriv;
- }
+
+ result = device->ftbl->start(device);
+ if (result)
+ goto err_freedevpriv;
+
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
}
device->open_count++;
@@ -856,8 +859,8 @@
result = device->ftbl->stop(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
}
- mutex_unlock(&device->mutex);
err_freedevpriv:
+ mutex_unlock(&device->mutex);
filep->private_data = NULL;
kfree(dev_priv);
err_pmruntime:
@@ -872,7 +875,7 @@
{
struct rb_node *node = private->mem_rb.rb_node;
- if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
+ if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
return NULL;
while (node != NULL) {
@@ -925,7 +928,7 @@
struct rb_node *node = private->mem_rb.rb_node;
- if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
+ if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
return 0;
/* don't overflow */
@@ -1193,7 +1196,9 @@
}
for (i = 0; i < param->numibs; i++) {
- if (!kgsl_mmu_gpuaddr_in_range(ibdesc[i].gpuaddr)) {
+ struct kgsl_pagetable *pt = dev_priv->process_priv->pagetable;
+
+ if (!kgsl_mmu_gpuaddr_in_range(pt, ibdesc[i].gpuaddr)) {
result = -ERANGE;
KGSL_DRV_ERR(dev_priv->device,
"invalid ib base GPU virtual addr %x\n",
@@ -1767,13 +1772,6 @@
return -ENOMEM;
}
-static inline int
-can_use_cpu_map(void)
-{
- return (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
- && kgsl_mmu_is_perprocess());
-}
-
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -1805,7 +1803,7 @@
| KGSL_MEMFLAGS_USE_CPU_MAP;
entry->memdesc.flags = param->flags;
- if (!can_use_cpu_map())
+ if (!kgsl_mmu_use_cpu_map(private->pagetable->mmu))
entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
switch (memtype) {
@@ -2092,7 +2090,7 @@
struct kgsl_mem_entry *entry = NULL;
int result;
- if (!can_use_cpu_map())
+ if (!kgsl_mmu_use_cpu_map(private->pagetable->mmu))
param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index aca5660..37b5730 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -73,7 +73,8 @@
int (*idle) (struct kgsl_device *device);
unsigned int (*isidle) (struct kgsl_device *device);
int (*suspend_context) (struct kgsl_device *device);
- int (*start) (struct kgsl_device *device, unsigned int init_ram);
+ int (*init) (struct kgsl_device *device);
+ int (*start) (struct kgsl_device *device);
int (*stop) (struct kgsl_device *device);
int (*getproperty) (struct kgsl_device *device,
enum kgsl_property_type type, void *value,
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index cb206ac..5cc0dff 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -19,6 +19,7 @@
#include "kgsl.h"
#include "kgsl_mmu.h"
+#include "kgsl_gpummu.h"
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
#include "kgsl_trace.h"
@@ -364,10 +365,9 @@
return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
}
-void kgsl_gpummu_destroy_pagetable(void *mmu_specific_pt)
+void kgsl_gpummu_destroy_pagetable(struct kgsl_pagetable *pt)
{
- struct kgsl_gpummu_pt *gpummu_pt = (struct kgsl_gpummu_pt *)
- mmu_specific_pt;
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
kgsl_ptpool_free((struct kgsl_ptpool *)kgsl_driver.ptpool,
gpummu_pt->base.hostptr);
@@ -528,6 +528,11 @@
*/
int status = 0;
+ mmu->pt_base = KGSL_PAGETABLE_BASE;
+ mmu->pt_size = CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
+ mmu->pt_per_process = KGSL_MMU_USE_PER_PROCESS_PT;
+ mmu->use_cpu_map = false;
+
/* sub-client MMU lookups require address translation */
if ((mmu->config & ~0x1) > 0) {
/*make sure virtual address range is a multiple of 64Kb */
@@ -584,7 +589,7 @@
if (mmu->defaultpagetable == NULL)
mmu->defaultpagetable =
- kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+ kgsl_mmu_getpagetable(mmu, KGSL_MMU_GLOBAL_PT);
/* Return error if the default pagetable doesn't exist */
if (mmu->defaultpagetable == NULL)
@@ -604,14 +609,14 @@
}
static int
-kgsl_gpummu_unmap(void *mmu_specific_pt,
+kgsl_gpummu_unmap(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int *tlb_flags)
{
unsigned int numpages;
unsigned int pte, ptefirst, ptelast, superpte;
unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
- struct kgsl_gpummu_pt *gpummu_pt = mmu_specific_pt;
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
functions purturb the gpuaddr with an offset, so apply the
@@ -653,13 +658,13 @@
GSL_TLBFLUSH_FILTER_ISDIRTY((_p) / GSL_PT_SUPER_PTE))
static int
-kgsl_gpummu_map(void *mmu_specific_pt,
+kgsl_gpummu_map(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int protflags,
unsigned int *tlb_flags)
{
unsigned int pte;
- struct kgsl_gpummu_pt *gpummu_pt = mmu_specific_pt;
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
struct scatterlist *s;
int flushtlb = 0;
int i;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 0bd22d3..f327c04 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -604,9 +604,9 @@
*
* Return - void
*/
-static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
+static void kgsl_iommu_destroy_pagetable(struct kgsl_pagetable *pt)
{
- struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
if (iommu_pt->domain)
iommu_domain_free(iommu_pt->domain);
kfree(iommu_pt);
@@ -829,7 +829,7 @@
if (KGSL_DEVICE_3D0 != mmu->device->id ||
!msm_soc_version_supports_iommu_v0() ||
- !kgsl_mmu_is_perprocess() ||
+ !kgsl_mmu_is_perprocess(mmu) ||
iommu->sync_lock_vars)
return 0;
@@ -870,7 +870,7 @@
uint32_t page_offset = 0;
if (!msm_soc_version_supports_iommu_v0() ||
- !kgsl_mmu_is_perprocess())
+ !kgsl_mmu_is_perprocess(mmu))
return status;
/*
@@ -1268,6 +1268,32 @@
if (status)
goto done;
+ /* We presently do not support per-process for IOMMU-v1 */
+ mmu->pt_per_process = KGSL_MMU_USE_PER_PROCESS_PT &&
+ msm_soc_version_supports_iommu_v0();
+
+ /*
+ * For IOMMU per-process pagetables, the allocatable range
+ * and the kernel global range must both be outside
+ * the userspace address range. There is a 1Mb gap
+ * between these address ranges to make overrun
+ * detection easier.
+ * For the shared pagetable case use 2GB and because
+ * mirroring the CPU address space is not possible and
+ * we're better off with extra room.
+ */
+ if (mmu->pt_per_process) {
+ mmu->pt_base = PAGE_OFFSET;
+ mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE
+ - kgsl_mmu_get_base_addr(mmu) - SZ_1M;
+ mmu->use_cpu_map = true;
+ } else {
+ mmu->pt_base = KGSL_PAGETABLE_BASE;
+ mmu->pt_size = SZ_2G;
+ mmu->use_cpu_map = false;
+ }
+
+
iommu->iommu_reg_list = kgsl_iommuv0_reg;
iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V0;
@@ -1321,7 +1347,8 @@
* switching on the 3D side for which a separate table is allocated */
if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v0()) {
mmu->priv_bank_table =
- kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
+ kgsl_mmu_getpagetable(mmu,
+ KGSL_MMU_PRIV_BANK_TABLE_NAME);
if (mmu->priv_bank_table == NULL) {
status = -ENOMEM;
goto err;
@@ -1330,7 +1357,7 @@
if (status)
goto err;
}
- mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+ mmu->defaultpagetable = kgsl_mmu_getpagetable(mmu, KGSL_MMU_GLOBAL_PT);
/* Return error if the default pagetable doesn't exist */
if (mmu->defaultpagetable == NULL) {
status = -ENOMEM;
@@ -1534,13 +1561,13 @@
}
static int
-kgsl_iommu_unmap(void *mmu_specific_pt,
+kgsl_iommu_unmap(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int *tlb_flags)
{
int ret;
unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
- struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
functions purturb the gpuaddr with an offset, so apply the
@@ -1561,20 +1588,20 @@
* Flushing only required if per process pagetables are used. With
* global case, flushing will happen inside iommu_map function
*/
- if (!ret && kgsl_mmu_is_perprocess())
+ if (!ret && kgsl_mmu_is_perprocess(pt->mmu))
*tlb_flags = UINT_MAX;
return 0;
}
static int
-kgsl_iommu_map(void *mmu_specific_pt,
+kgsl_iommu_map(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int protflags,
unsigned int *tlb_flags)
{
int ret;
unsigned int iommu_virt_addr;
- struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
BUG_ON(NULL == iommu_pt);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index ccaceb3..4e95373 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -23,6 +23,7 @@
#include "kgsl.h"
#include "kgsl_mmu.h"
+#include "kgsl_gpummu.h"
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
#include "adreno.h"
@@ -103,7 +104,7 @@
if (pagetable->pool)
gen_pool_destroy(pagetable->pool);
- pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv);
+ pagetable->pt_ops->mmu_destroy_pagetable(pagetable);
kfree(pagetable);
}
@@ -193,7 +194,7 @@
if (pt) {
ret += snprintf(buf, PAGE_SIZE, "0x%x\n",
- kgsl_mmu_get_ptsize());
+ kgsl_mmu_get_ptsize(pt->mmu));
}
kgsl_put_pagetable(pt);
@@ -444,7 +445,8 @@
}
EXPORT_SYMBOL(kgsl_mh_intrcallback);
-static struct kgsl_pagetable *kgsl_mmu_createpagetableobject(
+static struct kgsl_pagetable *
+kgsl_mmu_createpagetableobject(struct kgsl_mmu *mmu,
unsigned int name)
{
int status = 0;
@@ -463,8 +465,8 @@
spin_lock_init(&pagetable->lock);
- ptsize = kgsl_mmu_get_ptsize();
-
+ ptsize = kgsl_mmu_get_ptsize(mmu);
+ pagetable->mmu = mmu;
pagetable->name = name;
pagetable->max_entries = KGSL_PAGETABLE_ENTRIES(ptsize);
pagetable->fault_addr = 0xFFFFFFFF;
@@ -497,7 +499,7 @@
goto err_kgsl_pool;
}
- if (gen_pool_add(pagetable->pool, kgsl_mmu_get_base_addr(),
+ if (gen_pool_add(pagetable->pool, kgsl_mmu_get_base_addr(mmu),
ptsize, -1)) {
KGSL_CORE_ERR("gen_pool_add failed\n");
goto err_pool;
@@ -526,7 +528,7 @@
return pagetable;
err_mmu_create:
- pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv);
+ pagetable->pt_ops->mmu_destroy_pagetable(pagetable);
err_pool:
gen_pool_destroy(pagetable->pool);
err_kgsl_pool:
@@ -538,20 +540,21 @@
return NULL;
}
-struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name)
+struct kgsl_pagetable *kgsl_mmu_getpagetable(struct kgsl_mmu *mmu,
+ unsigned long name)
{
struct kgsl_pagetable *pt;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return (void *)(-1);
- if (!kgsl_mmu_is_perprocess())
+ if (!kgsl_mmu_is_perprocess(mmu))
name = KGSL_MMU_GLOBAL_PT;
pt = kgsl_get_pagetable(name);
if (pt == NULL)
- pt = kgsl_mmu_createpagetableobject(name);
+ pt = kgsl_mmu_createpagetableobject(mmu, name);
return pt;
}
@@ -688,7 +691,7 @@
if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
- ret = pagetable->pt_ops->mmu_map(pagetable->priv, memdesc, protflags,
+ ret = pagetable->pt_ops->mmu_map(pagetable, memdesc, protflags,
&pagetable->tlb_flags);
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
@@ -741,7 +744,7 @@
if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
- pagetable->pt_ops->mmu_unmap(pagetable->priv, memdesc,
+ pagetable->pt_ops->mmu_unmap(pagetable, memdesc,
&pagetable->tlb_flags);
/* If buffer is unmapped 0 fault addr */
@@ -894,15 +897,16 @@
}
EXPORT_SYMBOL(kgsl_mmu_set_mmutype);
-int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+int kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pt, unsigned int gpuaddr)
{
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return 1;
- if (gpuaddr >= kgsl_mmu_get_base_addr() &&
- gpuaddr < kgsl_mmu_get_base_addr() + kgsl_mmu_get_ptsize())
+ if (gpuaddr >= kgsl_mmu_get_base_addr(pt->mmu) &&
+ gpuaddr < kgsl_mmu_get_base_addr(pt->mmu) +
+ kgsl_mmu_get_ptsize(pt->mmu))
return 1;
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
- && kgsl_mmu_is_perprocess())
+ && kgsl_mmu_is_perprocess(pt->mmu))
return (gpuaddr > 0 && gpuaddr < TASK_SIZE);
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 2d48e86..d7d9516 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -24,6 +24,13 @@
#define KGSL_MMU_ALIGN_MASK (~((1 << PAGE_SHIFT) - 1))
+/* defconfig option for disabling per process pagetables */
+#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
+#define KGSL_MMU_USE_PER_PROCESS_PT true
+#else
+#define KGSL_MMU_USE_PER_PROCESS_PT false
+#endif
+
/* Identifier for the global page table */
/* Per process page tables will probably pass in the thread group
as an identifier */
@@ -116,6 +123,7 @@
unsigned int tlb_flags;
unsigned int fault_addr;
void *priv;
+ struct kgsl_mmu *mmu;
};
struct kgsl_mmu;
@@ -160,15 +168,15 @@
};
struct kgsl_mmu_pt_ops {
- int (*mmu_map) (void *mmu_pt,
+ int (*mmu_map) (struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int protflags,
unsigned int *tlb_flags);
- int (*mmu_unmap) (void *mmu_pt,
+ int (*mmu_unmap) (struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int *tlb_flags);
void *(*mmu_create_pagetable) (void);
- void (*mmu_destroy_pagetable) (void *pt);
+ void (*mmu_destroy_pagetable) (struct kgsl_pagetable *);
};
#define KGSL_MMU_FLAGS_IOMMU_SYNC BIT(31)
@@ -187,14 +195,19 @@
const struct kgsl_mmu_ops *mmu_ops;
void *priv;
int fault;
+ unsigned long pt_base;
+ unsigned long pt_size;
+ bool pt_per_process;
+ bool use_cpu_map;
};
-#include "kgsl_gpummu.h"
-
extern struct kgsl_mmu_ops iommu_ops;
extern struct kgsl_mmu_pt_ops iommu_pt_ops;
+extern struct kgsl_mmu_ops gpummu_ops;
+extern struct kgsl_mmu_pt_ops gpummu_pt_ops;
-struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name);
+struct kgsl_pagetable *kgsl_mmu_getpagetable(struct kgsl_mmu *,
+ unsigned long name);
void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable);
void kgsl_mh_start(struct kgsl_device *device);
void kgsl_mh_intrcallback(struct kgsl_device *device);
@@ -221,7 +234,7 @@
int kgsl_mmu_enabled(void);
void kgsl_mmu_set_mmutype(char *mmutype);
enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
-int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr);
+int kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pt, unsigned int gpuaddr);
/*
* Static inline functions of MMU that simply call the SMMU specific
@@ -335,75 +348,51 @@
/*
* kgsl_mmu_is_perprocess() - Runtime check for per-process
* pagetables.
+ * @mmu: the mmu
*
- * Returns non-zero if per-process pagetables are enabled,
- * 0 if not.
+ * Returns true if per-process pagetables are enabled,
+ * false if not.
*/
-#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
-static inline int kgsl_mmu_is_perprocess(void)
+static inline int kgsl_mmu_is_perprocess(struct kgsl_mmu *mmu)
{
+ return mmu->pt_per_process;
+}
- /* We presently do not support per-process for IOMMU-v1 */
- return (kgsl_mmu_get_mmutype() != KGSL_MMU_TYPE_IOMMU)
- || msm_soc_version_supports_iommu_v0();
-}
-#else
-static inline int kgsl_mmu_is_perprocess(void)
+/*
+ * kgsl_mmu_use_cpu_map() - Runtime check for matching the CPU
+ * address space on the GPU.
+ * @mmu: the mmu
+ *
+ * Returns true if supported false if not.
+ */
+static inline int kgsl_mmu_use_cpu_map(struct kgsl_mmu *mmu)
{
- return 0;
+ return mmu->pt_per_process;
}
-#endif
/*
* kgsl_mmu_base_addr() - Get gpu virtual address base.
+ * @mmu: the mmu
*
* Returns the start address of the allocatable gpu
* virtual address space. Other mappings that mirror
* the CPU address space are possible outside this range.
*/
-static inline unsigned int kgsl_mmu_get_base_addr(void)
+static inline unsigned int kgsl_mmu_get_base_addr(struct kgsl_mmu *mmu)
{
- if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()
- || !kgsl_mmu_is_perprocess())
- return KGSL_PAGETABLE_BASE;
- /*
- * This is the start of the kernel address
- * space, so allocations from this range will
- * never conflict with userpace addresses
- */
- return PAGE_OFFSET;
+ return mmu->pt_base;
}
/*
* kgsl_mmu_get_ptsize() - Get gpu pagetable size
+ * @mmu: the mmu
*
* Returns the usable size of the gpu allocatable
* address space.
*/
-static inline unsigned int kgsl_mmu_get_ptsize(void)
+static inline unsigned int kgsl_mmu_get_ptsize(struct kgsl_mmu *mmu)
{
- /*
- * For IOMMU per-process pagetables, the allocatable range
- * and the kernel global range must both be outside
- * the userspace address range. There is a 1Mb gap
- * between these address ranges to make overrun
- * detection easier.
- * For the shared pagetable case use 2GB and because
- * mirroring the CPU address space is not possible and
- * we're better off with extra room.
- */
- enum kgsl_mmutype mmu_type = kgsl_mmu_get_mmutype();
-
- if (KGSL_MMU_TYPE_GPU == mmu_type)
- return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
- else if (KGSL_MMU_TYPE_IOMMU == mmu_type) {
- if (kgsl_mmu_is_perprocess())
- return KGSL_IOMMU_GLOBAL_MEM_BASE
- - kgsl_mmu_get_base_addr() - SZ_1M;
- else
- return SZ_2G;
- }
- return 0;
+ return mmu->pt_size;
}
static inline int kgsl_mmu_sync_lock(struct kgsl_mmu *mmu,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index c716731..2f8d93e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1289,7 +1289,7 @@
kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
switch (device->state) {
case KGSL_STATE_SLUMBER:
- status = device->ftbl->start(device, 0);
+ status = device->ftbl->start(device);
if (status) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
KGSL_DRV_ERR(device, "start failed %d\n", status);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index f0410d6..b78c6fe 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -93,7 +93,8 @@
#define Z180_CMDWINDOW_TARGET_SHIFT 0
#define Z180_CMDWINDOW_ADDR_SHIFT 8
-static int z180_start(struct kgsl_device *device, unsigned int init_ram);
+static int z180_init(struct kgsl_device *device);
+static int z180_start(struct kgsl_device *device);
static int z180_stop(struct kgsl_device *device);
static int z180_wait(struct kgsl_device *device,
struct kgsl_context *context,
@@ -319,16 +320,11 @@
*p++ = ADDR_VGV3_LAST << 24;
}
-static void z180_cmdstream_start(struct kgsl_device *device, int init_ram)
+static void z180_cmdstream_start(struct kgsl_device *device)
{
struct z180_device *z180_dev = Z180_DEVICE(device);
unsigned int cmd = VGV3_NEXTCMD_JUMP << VGV3_NEXTCMD_NEXTCMD_FSHIFT;
- if (init_ram) {
- z180_dev->timestamp = 0;
- z180_dev->current_timestamp = 0;
- }
-
addmarker(&z180_dev->ringbuffer, 0);
z180_cmdwindow_write(device, ADDR_VGV3_MODE, 4);
@@ -552,7 +548,17 @@
return 0;
}
-static int z180_start(struct kgsl_device *device, unsigned int init_ram)
+static int z180_init(struct kgsl_device *device)
+{
+ struct z180_device *z180_dev = Z180_DEVICE(device);
+
+ z180_dev->timestamp = 0;
+ z180_dev->current_timestamp = 0;
+
+ return 0;
+}
+
+static int z180_start(struct kgsl_device *device)
{
int status = 0;
@@ -569,7 +575,7 @@
if (status)
goto error_clk_off;
- z180_cmdstream_start(device, init_ram);
+ z180_cmdstream_start(device);
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
@@ -919,6 +925,7 @@
.idle = z180_idle,
.isidle = z180_isidle,
.suspend_context = z180_suspend_context,
+ .init = z180_init,
.start = z180_start,
.stop = z180_stop,
.getproperty = z180_getproperty,
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 2fdf791..b52df44 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -212,7 +212,7 @@
bool descending = 1;
uint32_t i = 0;
- if ((pts == NULL) || (output == NULL))
+ if (pts == NULL)
return -EINVAL;
/* Check if table is descending or ascending */
@@ -258,7 +258,7 @@
bool descending = 1;
uint32_t i = 0;
- if ((pts == NULL) || (output == NULL))
+ if (pts == NULL)
return -EINVAL;
/* Check if table is descending or ascending */
@@ -365,14 +365,14 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
+EXPORT_SYMBOL(qpnp_adc_scale_pmic_therm);
int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph btm_param;
- int64_t *low_output = 0, *high_output = 0;
+ int64_t low_output = 0, high_output = 0;
int rc = 0;
rc = qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_ABSOLUTE);
@@ -382,25 +382,25 @@
}
/* Convert to Kelvin and account for voltage to be written as 2mV/K */
- *low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
+ low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
/* Convert to voltage threshold */
- *low_output *= btm_param.dy;
- do_div(*low_output, btm_param.adc_vref);
- *low_output += btm_param.adc_gnd;
+ low_output *= btm_param.dy;
+ do_div(low_output, btm_param.adc_vref);
+ low_output += btm_param.adc_gnd;
/* Convert to Kelvin and account for voltage to be written as 2mV/K */
- *high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
+ high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
/* Convert to voltage threshold */
- *high_output *= btm_param.dy;
- do_div(*high_output, btm_param.adc_vref);
- *high_output += btm_param.adc_gnd;
+ high_output *= btm_param.dy;
+ do_div(high_output, btm_param.adc_vref);
+ high_output += btm_param.adc_gnd;
- low_threshold = (uint32_t *) low_output;
- high_threshold = (uint32_t *) high_output;
+ *low_threshold = low_output;
+ *high_threshold = high_output;
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
+EXPORT_SYMBOL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
/* Scales the ADC code to degC using the mapping
* table for the XO thermistor.
@@ -426,7 +426,7 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
+EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -444,7 +444,7 @@
bat_voltage,
&adc_chan_result->physical);
}
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
+EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -462,7 +462,7 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu1);
+EXPORT_SYMBOL(qpnp_adc_scale_therm_pu1);
int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -480,7 +480,7 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
+EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2);
int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
{
@@ -506,7 +506,7 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
+EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2);
int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
{
@@ -537,7 +537,7 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
+EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2);
int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -553,7 +553,7 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
+EXPORT_SYMBOL(qpnp_adc_scale_batt_id);
int32_t qpnp_adc_scale_default(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -610,9 +610,8 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
+EXPORT_SYMBOL(qpnp_adc_scale_default);
-/* Converts millivolts to ADC high/low threshold code */
int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
@@ -632,7 +631,7 @@
param->low_thr);
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
+EXPORT_SYMBOL(qpnp_adc_usb_scaler);
int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
@@ -653,50 +652,59 @@
param->low_thr);
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_vbatt_rscaler);
+EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
-/* Converts decidegreesC to voltage based on the mapping table */
int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph btm_param;
- int64_t *low_output = 0, *high_output = 0;
+ int64_t low_output = 0, high_output = 0;
int rc = 0;
qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
- rc = qpnp_adc_map_temp_voltage(
+ pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
+ param->low_temp);
+ rc = qpnp_adc_map_voltage_temp(
adcmap_btm_threshold,
ARRAY_SIZE(adcmap_btm_threshold),
(param->low_temp),
- low_output);
- if (rc)
+ &low_output);
+ if (rc) {
+ pr_debug("low_temp mapping failed with %d\n", rc);
return rc;
+ }
- *low_output *= btm_param.dy;
- do_div(*low_output, btm_param.adc_vref);
- *low_output += btm_param.adc_gnd;
+ pr_debug("low_output:%lld\n", low_output);
+ low_output *= btm_param.dy;
+ do_div(low_output, btm_param.adc_vref);
+ low_output += btm_param.adc_gnd;
- rc = qpnp_adc_map_temp_voltage(
+ rc = qpnp_adc_map_voltage_temp(
adcmap_btm_threshold,
ARRAY_SIZE(adcmap_btm_threshold),
(param->high_temp),
- high_output);
- if (rc)
+ &high_output);
+ if (rc) {
+ pr_debug("high temp mapping failed with %d\n", rc);
return rc;
+ }
- pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
- param->low_temp);
- *high_output *= btm_param.dy;
- do_div(*high_output, btm_param.adc_vref);
- *high_output += btm_param.adc_gnd;
+ pr_debug("high_output:%lld\n", high_output);
+ high_output *= btm_param.dy;
+ do_div(high_output, btm_param.adc_vref);
+ high_output += btm_param.adc_gnd;
- low_threshold = (uint32_t *) low_output;
- high_threshold = (uint32_t *) high_output;
+ /* btm low temperature correspondes to high voltage threshold */
+ *low_threshold = high_output;
+ /* btm high temperature correspondes to low voltage threshold */
+ *high_threshold = low_output;
+ pr_debug("high_volt:%d, low_volt:%d\n", *high_threshold,
+ *low_threshold);
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
+EXPORT_SYMBOL(qpnp_adc_btm_scaler);
int32_t qpnp_vadc_check_result(int32_t *data)
{
@@ -707,7 +715,7 @@
return 0;
}
-EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
+EXPORT_SYMBOL(qpnp_vadc_check_result);
int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
struct qpnp_adc_drv *adc_qpnp)
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 2017c8d..1fd4fee 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -404,10 +404,12 @@
iadc->adc->calib.gain_uv = (num * QPNP_ADC_GAIN_NV)/
(iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+ pr_debug("gain_uv:%d offset_uv:%d\n",
+ iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
return 0;
}
-static int32_t qpnp_iadc_calibrate_for_trim(void)
+int32_t qpnp_iadc_calibrate_for_trim(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_lsb, rslt_msb;
@@ -439,6 +441,9 @@
goto fail;
}
+ pr_debug("raw gain:0x%x, raw offset:0x%x\n",
+ iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
+
rc = qpnp_convert_raw_offset_voltage();
if (rc < 0) {
pr_err("qpnp raw_voltage conversion failed\n");
@@ -449,6 +454,8 @@
QPNP_BIT_SHIFT_8;
rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
+ pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
+
rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
QPNP_IADC_SEC_ACCESS_DATA);
if (rc < 0) {
@@ -480,6 +487,7 @@
mutex_unlock(&iadc->adc->adc_lock);
return rc;
}
+EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
static void qpnp_iadc_work(struct work_struct *work)
{
@@ -545,6 +553,8 @@
return rc;
}
+ pr_debug("rsense:0%x\n", rslt_rsense);
+
if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
sign_bit = 1;
@@ -610,6 +620,8 @@
}
rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
+ pr_debug("current raw:0%x and rsense:%d\n",
+ raw_data, rsense_n_ohms);
num = raw_data - iadc->adc->calib.offset_raw;
if (num < 0) {
@@ -658,6 +670,10 @@
result->ideal_offset_uv =
QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
result->offset_uv = iadc->adc->calib.offset_uv;
+ pr_debug("raw gain:0%x, raw offset:0%x\n",
+ result->gain_raw, result->offset_raw);
+ pr_debug("gain_uv:%d offset_uv:%d\n",
+ result->gain_uv, result->offset_uv);
mutex_unlock(&iadc->adc->adc_lock);
return 0;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index edbde44..e268541 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -491,6 +491,9 @@
goto calib_fail;
}
+ pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
+ calib_read_1, calib_read_2);
+
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
(calib_read_1 - calib_read_2);
@@ -555,6 +558,8 @@
goto calib_fail;
}
+ pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
+ calib_read_1, calib_read_2);
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
(calib_read_1 - calib_read_2);
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
@@ -736,7 +741,7 @@
return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
channel, result);
}
-EXPORT_SYMBOL_GPL(qpnp_vadc_read);
+EXPORT_SYMBOL(qpnp_vadc_read);
static void qpnp_vadc_lock(void)
{
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index 1472293..b62bb76 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -371,6 +371,55 @@
return pa;
}
+static int check_range(unsigned long *fl_table, unsigned int va,
+ unsigned int len)
+{
+ unsigned int offset = 0;
+ unsigned long *fl_pte;
+ unsigned long fl_offset;
+ unsigned long *sl_table;
+ unsigned long sl_start, sl_end;
+ int i;
+
+ fl_offset = FL_OFFSET(va); /* Upper 12 bits */
+ fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
+
+ while (offset < len) {
+ if (*fl_pte & FL_TYPE_TABLE) {
+ sl_start = SL_OFFSET(va);
+ sl_table = __va(((*fl_pte) & FL_BASE_MASK));
+ sl_end = ((len - offset) / SZ_4K) + sl_start;
+
+ if (sl_end > NUM_SL_PTE)
+ sl_end = NUM_SL_PTE;
+
+ for (i = sl_start; i < sl_end; i++) {
+ if (sl_table[i] != 0) {
+ pr_err("%08x - %08x already mapped\n",
+ va, va + SZ_4K);
+ return -EBUSY;
+ }
+ offset += SZ_4K;
+ va += SZ_4K;
+ }
+
+
+ sl_start = 0;
+ } else {
+ if (*fl_pte != 0) {
+ pr_err("%08x - %08x already mapped\n",
+ va, va + SZ_1M);
+ return -EBUSY;
+ }
+ va += SZ_1M;
+ offset += SZ_1M;
+ sl_start = 0;
+ }
+ fl_pte++;
+ }
+ return 0;
+}
+
static inline int is_fully_aligned(unsigned int va, phys_addr_t pa, size_t len,
int align)
{
@@ -406,6 +455,10 @@
fl_pte = pt->fl_table + fl_offset; /* int pointers, 4 bytes */
pa = get_phys_addr(sg);
+ ret = check_range(pt->fl_table, va, len);
+ if (ret)
+ goto fail;
+
while (offset < len) {
chunk_size = SZ_4K;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 202edc0..ac06fc5 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -61,6 +61,7 @@
#define WLED_MAX_CURR_MASK 0x19
#define WLED_OP_FDBCK_MASK 0x07
#define WLED_OP_FDBCK_BIT_SHFT 0x00
+#define WLED_OP_FDBCK_DEFAULT 0x00
#define WLED_MAX_LEVEL 4095
#define WLED_8_BIT_MASK 0xFF
@@ -90,6 +91,8 @@
#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
#define FLASH_ENABLE_CONTROL(base) (base + 0x46)
#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
+#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
+#define FLASH_LED_TORCH(base) (base + 0xE4)
#define FLASH_MAX_LEVEL 0x4F
#define FLASH_NO_MASK 0x00
@@ -99,6 +102,7 @@
#define FLASH_HEADROOM_MASK 0x03
#define FLASH_SAFETY_TIMER_MASK 0x7F
#define FLASH_CURRENT_MASK 0xFF
+#define FLASH_MAX_CURRENT_MASK 0x7F
#define FLASH_TMR_MASK 0x03
#define FLASH_TMR_WATCHDOG 0x03
#define FLASH_TMR_SAFETY 0x00
@@ -117,17 +121,26 @@
#define FLASH_ENABLE_LED_1 0x20
#define FLASH_INIT_MASK 0xE0
-#define FLASH_STROBE_ALL 0xC0
-#define FLASH_STROBE_MASK 0xC0
+#define FLASH_STROBE_SW 0xC0
+#define FLASH_STROBE_HW 0xC4
+#define FLASH_STROBE_MASK 0xC7
#define FLASH_LED_0_OUTPUT 0x80
#define FLASH_LED_1_OUTPUT 0x40
#define FLASH_CURRENT_PRGM_MIN 1
#define FLASH_CURRENT_PRGM_SHIFT 1
+#define FLASH_CURRENT_MAX 0x4F
+#define FLASH_CURRENT_TORCH 0x0F
#define FLASH_DURATION_200ms 0x13
#define FLASH_CLAMP_200mA 0x0F
+#define FLASH_TORCH_MASK 0x03
+#define FLASH_LED_TORCH_ENABLE 0x00
+#define FLASH_LED_TORCH_DISABLE 0x03
+#define FLASH_UNLOCK_SECURE 0xA5
+#define FLASH_SECURE_MASK 0xFF
+
#define LED_TRIGGER_DEFAULT "none"
#define RGB_LED_SRC_SEL(base) (base + 0x45)
@@ -245,9 +258,9 @@
u8 cp_select;
u8 ctrl_delay_us;
u8 switch_freq;
+ u8 op_fdbck;
bool dig_mod_gen_en;
bool cs_out_en;
- bool op_fdbck;
};
/**
@@ -259,9 +272,11 @@
* @enable_module - enable address for particular flash
* @trigger_flash - trigger flash
* @startup_dly - startup delay for flash
+ * @strobe_type - select between sw and hw strobe
* @current_addr - address to write for current
* @second_addr - address of secondary flash to be written
* @safety_timer - enable safety timer or watchdog timer
+ * @torch_enable - enable flash LED torch mode
*/
struct flash_config_data {
u8 current_prgm;
@@ -271,9 +286,11 @@
u8 enable_module;
u8 trigger_flash;
u8 startup_dly;
+ u8 strobe_type;
u16 current_addr;
u16 second_addr;
bool safety_timer;
+ bool torch_enable;
};
/**
@@ -456,62 +473,176 @@
/* Set led current */
if (val > 0) {
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
+ if (led->flash_cfg->torch_enable) {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_UNLOCK_SECURE(led->base),
+ FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Secure reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_TORCH(led->base),
+ FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+ FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Max current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ led->flash_cfg->current_addr,
+ FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Current reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ led->flash_cfg->second_addr,
+ FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "2nd Current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
+ } else {
+ rc = qpnp_led_masked_write(led,
+ FLASH_MAX_CURR(led->base),
+ FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Max current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
+ /* Write 0x80 to MODULE_ENABLE before writing 0xE0
+ * in order to avoid reg value goes from 0x00 to
+ * 0xE0. This causes a hardware bug.
+ */
+ rc = qpnp_led_masked_write(led,
+ FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ led->flash_cfg->current_addr,
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->current_prgm);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Current reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ led->flash_cfg->second_addr,
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->current_prgm);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "2nd Current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ FLASH_CLAMP_CURR(led->base),
+ FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Clamp Current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
}
- rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
- FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Current reg write failed(%d)\n", rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led, led->flash_cfg->second_addr,
- FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Current reg write failed(%d)\n", rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MASK,
- FLASH_ENABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
- }
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- FLASH_STROBE_MASK, FLASH_STROBE_ALL);
-
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "LED %d flash write failed(%d)\n", led->id, rc);
- return rc;
- }
- rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
- FLASH_VREG_MASK, FLASH_HW_VREG_OK);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Vreg OK reg write failed(%d)\n", rc);
- return rc;
+ if (!led->flash_cfg->strobe_type) {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_STROBE_CTRL(led->base),
+ FLASH_STROBE_MASK, FLASH_STROBE_SW);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "LED %d strobe reg write failed(%d)\n",
+ led->id, rc);
+ return rc;
+ }
+ } else {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_STROBE_CTRL(led->base),
+ FLASH_STROBE_MASK, FLASH_STROBE_HW);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "LED %d strobe reg write failed(%d)\n",
+ led->id, rc);
+ return rc;
+ }
}
} else {
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MASK,
- FLASH_DISABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
+ if (led->flash_cfg->torch_enable) {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_UNLOCK_SECURE(led->base),
+ FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Secure reg write failed(%d)\n", rc);
+ }
+
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_TORCH(led->base),
+ FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_led_masked_write(led,
+ FLASH_SAFETY_TIMER(led->base),
+ FLASH_SAFETY_TIMER_MASK,
+ led->flash_cfg->duration);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Safety timer reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
}
rc = qpnp_led_masked_write(led,
@@ -523,6 +654,15 @@
"LED %d flash write failed(%d)\n", led->id, rc);
return rc;
}
+
+ rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MASK,
+ FLASH_DISABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
}
qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
@@ -797,6 +937,66 @@
return 0;
}
+static ssize_t led_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ unsigned long state;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret = -EINVAL;
+
+ ret = kstrtoul(buf, 10, &state);
+ if (ret)
+ return ret;
+
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ /* '1' to enable torch mode; '0' to switch to flash mode */
+ if (state == 1)
+ led->flash_cfg->torch_enable = true;
+ else
+ led->flash_cfg->torch_enable = false;
+
+ return count;
+}
+
+static ssize_t led_strobe_type_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ unsigned long state;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret = -EINVAL;
+
+ ret = kstrtoul(buf, 10, &state);
+ if (ret)
+ return ret;
+
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ /* '0' for sw strobe; '1' for hw strobe */
+ if (state == 1)
+ led->flash_cfg->strobe_type = 1;
+ else
+ led->flash_cfg->strobe_type = 0;
+
+ return count;
+}
+
+static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
+static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
+
+static struct attribute *led_attrs[] = {
+ &dev_attr_led_mode.attr,
+ &dev_attr_strobe.attr,
+};
+
+static const struct attribute_group led_attr_group = {
+ .attrs = led_attrs,
+};
+
static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
{
int rc;
@@ -890,7 +1090,7 @@
return rc;
}
- /* Set led current and enable module */
+ /* Set led current and disable module */
rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
if (rc) {
@@ -906,6 +1106,10 @@
"Enable reg write failed(%d)\n", rc);
return rc;
}
+
+ led->flash_cfg->torch_enable = false;
+ led->flash_cfg->strobe_type = 0;
+
/* dump flash registers */
qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
@@ -1099,6 +1303,13 @@
else if (rc != -EINVAL)
return rc;
+ led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
+ if (!rc)
+ led->wled_cfg->op_fdbck = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
rc = of_property_read_u32(node, "qcom,switch-freq", &val);
if (!rc)
@@ -1112,9 +1323,6 @@
led->wled_cfg->cs_out_en =
of_property_read_bool(node, "qcom,cs-out-en");
- led->wled_cfg->op_fdbck =
- of_property_read_bool(node, "qcom,op-fdbck");
-
return 0;
}
@@ -1451,6 +1659,16 @@
led->id, rc);
goto fail_id_check;
}
+
+ if (led->id == QPNP_ID_FLASH1_LED0 ||
+ led->id == QPNP_ID_FLASH1_LED1) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &led_attr_group);
+ if (rc)
+ goto fail_id_check;
+
+ }
+
/* configure default state */
if (led->default_on) {
led->cdev.brightness = led->cdev.max_brightness;
@@ -1477,8 +1695,26 @@
struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
int i, parsed_leds = led_array->num_leds;
- for (i = 0; i < parsed_leds; i++)
+ for (i = 0; i < parsed_leds; i++) {
led_classdev_unregister(&led_array[i].cdev);
+ switch (led_array[i].id) {
+ case QPNP_ID_WLED:
+ break;
+ case QPNP_ID_FLASH1_LED0:
+ case QPNP_ID_FLASH1_LED1:
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &led_attr_group);
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ default:
+ dev_err(&led_array[i].spmi_dev->dev,
+ "Invalid LED(%d)\n",
+ led_array[i].id);
+ return -EINVAL;
+ }
+ }
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 2a0cde9..0fef315 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1876,13 +1876,13 @@
if (dvbdemux->dmx.debugfs_demux_dir != NULL) {
debugfs_create_u32(
"total_processing_time",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
dvbdemux->dmx.debugfs_demux_dir,
&dvbdemux->total_process_time);
debugfs_create_u32(
"total_crc_time",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
dvbdemux->dmx.debugfs_demux_dir,
&dvbdemux->total_crc_time);
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index a780526..f1bfd68 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -98,6 +98,8 @@
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
stream_info->num_planes = 2;
break;
/*TD: Add more image format*/
@@ -188,6 +190,11 @@
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width / 2;
break;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ size = plane_cfg[plane_idx].output_height *
+ plane_cfg[plane_idx].output_width;
+ break;
/*TD: Add more image format*/
default:
pr_err("%s: Invalid output format\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index f337e27..ae89500 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -418,6 +418,8 @@
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
val = CAL_WORD(pixel_per_line, 1, 8);
break;
/*TD: Add more image format*/
@@ -461,6 +463,9 @@
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
return 8;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ return 16;
/*TD: Add more image format*/
default:
pr_err("%s: Invalid output format\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 85788e9..22ce35b 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -78,7 +78,7 @@
{"camss_csi_vfe_clk1", -1},
};
-static int msm_ispif_clk_enable(struct ispif_device *ispif,
+static int msm_ispif_clk_enable_one(struct ispif_device *ispif,
enum msm_ispif_vfe_intf vfe_intf, int enable)
{
int rc = 0;
@@ -119,8 +119,8 @@
ARRAY_SIZE(ispif_8974_clk_info_vfe1), enable);
}
if (rc) {
- pr_err("%s: cannot enable clock, error = %d\n",
- __func__, rc);
+ pr_err("%s: cannot enable clock, error = %d, vfeid = %d\n",
+ __func__, rc, vfe_intf);
goto end;
}
} else {
@@ -133,17 +133,56 @@
return rc;
}
+static int msm_ispif_clk_enable(struct ispif_device *ispif,
+ struct msm_ispif_param_data *params, int enable)
+{
+ int rc = 0;
+ int i, j;
+ uint32_t vfe_intf_mask = 0;
+
+ for (i = 0; i < params->num; i++) {
+ if (vfe_intf_mask & (1 << params->entries[i].vfe_intf))
+ continue;
+ rc = msm_ispif_clk_enable_one(ispif,
+ params->entries[i].vfe_intf, 1);
+ if (rc < 0 && enable) {
+ pr_err("%s: unable to enable clocks for VFE %d",
+ __func__, params->entries[i].vfe_intf);
+ for (j = 0; j < i; j++) {
+ /* if VFE clock is not enabled do
+ * not disable the clock */
+ if (!(vfe_intf_mask & (1 <<
+ params->entries[i].vfe_intf)))
+ continue;
+ msm_ispif_clk_enable_one(ispif,
+ params->entries[j].vfe_intf, 0);
+ /* remove the VFE ID from the mask */
+ vfe_intf_mask &=
+ ~(1 << params->entries[i].vfe_intf);
+ }
+ break;
+ }
+ vfe_intf_mask |= 1 << params->entries[i].vfe_intf;
+ }
+ return rc;
+}
+
static int msm_ispif_intf_reset(struct ispif_device *ispif,
struct msm_ispif_param_data *params)
{
int i, rc = 0;
enum msm_ispif_intftype intf_type;
- uint32_t data = STROBED_RST_EN;
+ int vfe_intf = 0;
+ uint32_t data = 0;
for (i = 0; i < params->num; i++) {
+ data = STROBED_RST_EN;
+ vfe_intf = params->entries[i].vfe_intf;
intf_type = params->entries[i].intftype;
- ispif->sof_count[params->vfe_intf].sof_cnt[intf_type] = 0;
+ ispif->sof_count[params->entries[i].vfe_intf].
+ sof_cnt[intf_type] = 0;
+
switch (intf_type) {
case PIX0:
data |= (PIX_0_VFE_RST_STB | PIX_0_CSID_RST_STB);
@@ -164,35 +203,40 @@
rc = -EINVAL;
break;
}
- }
- if (data > 0x1) {
- unsigned long jiffes = msecs_to_jiffies(500);
- long lrc = 0;
- unsigned long flags;
+ if (data > 0x1) {
+ unsigned long jiffes = msecs_to_jiffies(500);
+ long lrc = 0;
+ unsigned long flags;
- spin_lock_irqsave(&ispif->auto_complete_lock, flags);
- ispif->wait_timeout[params->vfe_intf] = 0;
- init_completion(&ispif->reset_complete[params->vfe_intf]);
- spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
-
- if (params->vfe_intf == VFE0)
- msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
- else
- msm_camera_io_w(data, ispif->base +
- ISPIF_RST_CMD_1_ADDR);
-
- lrc = wait_for_completion_interruptible_timeout(
- &ispif->reset_complete[params->vfe_intf], jiffes);
- if (lrc < 0 || !lrc) {
- pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
- rc = -EIO;
-
- spin_lock_irqsave(&ispif->auto_complete_lock, flags);
- ispif->wait_timeout[params->vfe_intf] = 1;
+ spin_lock_irqsave(
+ &ispif->auto_complete_lock, flags);
+ ispif->wait_timeout[vfe_intf] = 0;
+ init_completion(&ispif->reset_complete[vfe_intf]);
spin_unlock_irqrestore(
&ispif->auto_complete_lock, flags);
+
+ if (vfe_intf == VFE0)
+ msm_camera_io_w(data, ispif->base +
+ ISPIF_RST_CMD_ADDR);
+ else
+ msm_camera_io_w(data, ispif->base +
+ ISPIF_RST_CMD_1_ADDR);
+ lrc = wait_for_completion_interruptible_timeout(
+ &ispif->reset_complete[vfe_intf], jiffes);
+ if (lrc < 0 || !lrc) {
+ pr_err("%s: wait timeout ret = %ld, vfe_id = %d\n",
+ __func__, lrc, vfe_intf);
+ rc = -EIO;
+
+ spin_lock_irqsave(
+ &ispif->auto_complete_lock, flags);
+ ispif->wait_timeout[vfe_intf] = 1;
+ spin_unlock_irqrestore(
+ &ispif->auto_complete_lock, flags);
+ }
}
}
+
return rc;
}
@@ -223,7 +267,8 @@
&ispif->reset_complete[VFE0], jiffes);
if (lrc < 0 || !lrc) {
- pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
+ pr_err("%s: wait timeout ret = %ld, vfeid = %d\n",
+ __func__, lrc, VFE0);
rc = -EIO;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
@@ -242,7 +287,8 @@
&ispif->reset_complete[VFE1], jiffes);
if (lrc < 0 || !lrc) {
- pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
+ pr_err("%s: wait timeout ret = %ld, vfeid = %d\n",
+ __func__, lrc, VFE1);
rc = -EIO;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
@@ -320,6 +366,36 @@
ISPIF_VFE_m_INPUT_SEL(vfe_intf));
}
+static void msm_ispif_enable_crop(struct ispif_device *ispif,
+ uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel,
+ uint16_t end_pixel)
+{
+ uint32_t data;
+ BUG_ON(!ispif);
+
+ if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+ pr_err("%s: invalid interface type\n", __func__);
+ return;
+ }
+
+ data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf));
+ data |= (1 << (intftype + 7));
+ msm_camera_io_w(data,
+ ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf));
+
+ if (intftype == PIX0)
+ msm_camera_io_w_mb(start_pixel | (end_pixel << 16),
+ ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0));
+ else if (intftype == PIX1)
+ msm_camera_io_w_mb(start_pixel | (end_pixel << 16),
+ ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1));
+ else {
+ pr_err("%s: invalid intftype=%d\n", __func__, intftype);
+ BUG_ON(1);
+ return;
+ }
+}
+
static void msm_ispif_enable_intf_cids(struct ispif_device *ispif,
uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable)
{
@@ -427,28 +503,30 @@
BUG_ON(!ispif);
BUG_ON(!params);
- vfe_intf = params->vfe_intf;
-
- rc = msm_ispif_clk_enable(ispif, vfe_intf, 1);
+ rc = msm_ispif_clk_enable(ispif, params, 1);
if (rc < 0) {
- pr_err("%s: unable to enable clocks for VFE%d", __func__,
- vfe_intf);
+ pr_err("%s: unable to enable clocks", __func__);
return rc;
}
-
- if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
- pr_err("%s: invalid interface type\n", __func__);
- return -EINVAL;
+ for (i = 0; i < params->num; i++) {
+ vfe_intf = params->entries[i].vfe_intf;
+ if (!msm_ispif_is_intf_valid(ispif->csid_version,
+ vfe_intf)) {
+ pr_err("%s: invalid interface type\n", __func__);
+ return -EINVAL;
+ }
+ msm_camera_io_w(0x0, ispif->base +
+ ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
+ msm_camera_io_w(0x0, ispif->base +
+ ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
+ msm_camera_io_w_mb(0x0, ispif->base +
+ ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
}
- msm_camera_io_w(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
- msm_camera_io_w(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
- msm_camera_io_w_mb(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
-
for (i = 0; i < params->num; i++) {
intftype = params->entries[i].intftype;
- vfe_intf = params->vfe_intf;
+ vfe_intf = params->entries[i].vfe_intf;
CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__,
intftype, vfe_intf, params->entries[i].csid);
@@ -475,31 +553,36 @@
¶ms->entries[i]);
msm_ispif_enable_intf_cids(ispif, intftype,
cid_mask, vfe_intf, 1);
+ if (params->entries[i].crop_enable)
+ msm_ispif_enable_crop(ispif, intftype, vfe_intf,
+ params->entries[i].crop_start_pixel,
+ params->entries[i].crop_end_pixel);
}
- msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
- ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
+ for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) {
+ msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
+ ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
- msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
- ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf));
+ msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
+ ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf));
- msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
- ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
+ msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+ ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
- msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
- ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf));
+ msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+ ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf));
- msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
- ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
+ msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+ ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
- msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
- ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf));
+ msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+ ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf));
+ }
msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
-
- rc = msm_ispif_clk_enable(ispif, vfe_intf, 0);
+ msm_ispif_clk_enable(ispif, params, 0);
return rc;
}
@@ -511,18 +594,22 @@
int i, k;
enum msm_ispif_intftype intf_type;
enum msm_ispif_cid cid;
- enum msm_ispif_vfe_intf vfe_intf = params->vfe_intf;
+ enum msm_ispif_vfe_intf vfe_intf;
BUG_ON(!ispif);
BUG_ON(!params);
- if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
- pr_err("%s: invalid interface type\n", __func__);
- return;
+ for (i = 0; i < params->num; i++) {
+ vfe_intf = params->entries[i].vfe_intf;
+ if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+ pr_err("%s: invalid interface type\n", __func__);
+ return;
+ }
}
for (i = 0; i < params->num; i++) {
intf_type = params->entries[i].intftype;
+ vfe_intf = params->entries[i].vfe_intf;
for (k = 0; k < params->entries[i].num_cids; k++) {
cid = params->entries[i].cids[k];
vc = cid % 4;
@@ -542,16 +629,19 @@
(cmd_bits << (vc * 2 + intf_type * 8));
}
}
+
+ /* cmd for PIX0, PIX1, RDI0, RDI1 */
+ if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF)
+ msm_camera_io_w_mb(
+ ispif->applied_intf_cmd[vfe_intf].intf_cmd,
+ ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf));
+
+ /* cmd for RDI2 */
+ if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF)
+ msm_camera_io_w_mb(
+ ispif->applied_intf_cmd[vfe_intf].intf_cmd1,
+ ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf));
}
- /* cmd for PIX0, PIX1, RDI0, RDI1 */
- if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) {
- msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd,
- ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf));
- }
- /* cmd for RDI2 */
- if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF)
- msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd1,
- ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf));
}
static int msm_ispif_stop_immediately(struct ispif_device *ispif,
@@ -570,7 +660,7 @@
cid_mask = msm_ispif_get_cids_mask_from_cfg(
¶ms->entries[i]);
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
- cid_mask, params->vfe_intf, 0);
+ cid_mask, params->entries[i].vfe_intf, 0);
}
return rc;
@@ -581,10 +671,9 @@
{
int rc;
- rc = msm_ispif_clk_enable(ispif, params->vfe_intf, 1);
+ rc = msm_ispif_clk_enable(ispif, params, 1);
if (rc < 0) {
- pr_err("%s: unable to enable clocks for VFE%d", __func__,
- params->vfe_intf);
+ pr_err("%s: unable to enable clocks", __func__);
return rc;
}
@@ -592,13 +681,13 @@
if (rc) {
pr_err("%s: msm_ispif_intf_reset failed. rc=%d\n",
__func__, rc);
- return rc;
+ goto end;
}
msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
- msm_ispif_clk_enable(ispif, params->vfe_intf, 0);
-
+end:
+ msm_ispif_clk_enable(ispif, params, 0);
return rc;
}
@@ -613,18 +702,20 @@
BUG_ON(!ispif);
BUG_ON(!params);
- vfe_intf = params->vfe_intf;
- rc = msm_ispif_clk_enable(ispif, params->vfe_intf, 1);
+ rc = msm_ispif_clk_enable(ispif, params, 1);
if (rc < 0) {
- pr_err("%s: unable to enable clocks for VFE%d", __func__,
- params->vfe_intf);
+ pr_err("%s: unable to enable clocks", __func__);
return rc;
}
- if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
- pr_err("%s: invalid interface type\n", __func__);
- return -EINVAL;
+ for (i = 0; i < params->num; i++) {
+ if (!msm_ispif_is_intf_valid(ispif->csid_version,
+ params->entries[i].vfe_intf)) {
+ pr_err("%s: invalid interface type\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
}
msm_ispif_intf_cmd(ispif,
@@ -633,6 +724,7 @@
for (i = 0; i < params->num; i++) {
cid_mask =
msm_ispif_get_cids_mask_from_cfg(¶ms->entries[i]);
+ vfe_intf = params->entries[i].vfe_intf;
switch (params->entries[i].intftype) {
case PIX0:
@@ -653,7 +745,8 @@
default:
pr_err("%s: invalid intftype=%d\n", __func__,
params->entries[i].intftype);
- return -EPERM;
+ rc = -EPERM;
+ goto end;
}
/* todo_bug_fix? very bad. use readl_poll_timeout */
@@ -666,7 +759,8 @@
cid_mask, vfe_intf, 0);
}
- msm_ispif_clk_enable(ispif, vfe_intf, 0);
+end:
+ msm_ispif_clk_enable(ispif, params, 0);
return rc;
}
@@ -718,6 +812,25 @@
msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2,
ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0));
+ if (ispif->vfe_info.num_vfe > 1) {
+ out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
+ ISPIF_VFE_m_IRQ_STATUS_0(VFE1));
+ msm_camera_io_w(out[VFE1].ispifIrqStatus0,
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1));
+
+ out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
+ ISPIF_VFE_m_IRQ_STATUS_1(VFE1));
+ msm_camera_io_w(out[VFE1].ispifIrqStatus1,
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1));
+
+ out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
+ ISPIF_VFE_m_IRQ_STATUS_2(VFE1));
+ msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2,
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1));
+ }
+ msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+ ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) {
unsigned long flags;
@@ -742,24 +855,7 @@
ispif_process_irq(ispif, out, VFE0);
}
- if (ispif->csid_version >= CSID_VERSION_V3 &&
- ispif->vfe_info.num_vfe > 1) {
- out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
- ISPIF_VFE_m_IRQ_STATUS_0(VFE1));
- msm_camera_io_w(out[VFE1].ispifIrqStatus0,
- ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1));
-
- out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
- ISPIF_VFE_m_IRQ_STATUS_1(VFE1));
- msm_camera_io_w(out[VFE1].ispifIrqStatus1,
- ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1));
-
- out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
- ISPIF_VFE_m_IRQ_STATUS_2(VFE1));
- msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2,
- ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1));
-
-
+ if (ispif->vfe_info.num_vfe > 1) {
if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) {
unsigned long flags;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
@@ -783,8 +879,6 @@
ispif_process_irq(ispif, out, VFE1);
}
- msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
- ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
}
static irqreturn_t msm_io_ispif_irq(int irq_num, void *data)
@@ -825,7 +919,7 @@
memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
ispif->csid_version = csid_version;
- rc = msm_ispif_clk_enable(ispif, VFE0, 1);
+ rc = msm_ispif_clk_enable_one(ispif, VFE0, 1);
if (rc < 0) {
pr_err("%s: unable to enable clocks for VFE0", __func__);
goto error_clk0;
@@ -833,7 +927,7 @@
if (ispif->csid_version >= CSID_VERSION_V3 &&
ispif->vfe_info.num_vfe > 1) {
- rc = msm_ispif_clk_enable(ispif, VFE1, 1);
+ rc = msm_ispif_clk_enable_one(ispif, VFE1, 1);
if (rc < 0) {
pr_err("%s: unable to enable clocks for VFE1",
__func__);
@@ -868,10 +962,10 @@
end:
if (ispif->csid_version >= CSID_VERSION_V3 &&
ispif->vfe_info.num_vfe > 1)
- msm_ispif_clk_enable(ispif, VFE1, 0);
+ msm_ispif_clk_enable_one(ispif, VFE1, 0);
error_clk1:
- msm_ispif_clk_enable(ispif, VFE0, 0);
+ msm_ispif_clk_enable_one(ispif, VFE0, 0);
error_clk0:
return rc;
@@ -889,7 +983,7 @@
}
for (i = 0; i < ispif->vfe_info.num_vfe; i++)
- msm_ispif_clk_enable(ispif, i, 1);
+ msm_ispif_clk_enable_one(ispif, i, 1);
/* make sure no streaming going on */
msm_ispif_reset(ispif);
@@ -899,7 +993,7 @@
iounmap(ispif->base);
for (i = 0; i < ispif->vfe_info.num_vfe; i++)
- msm_ispif_clk_enable(ispif, i, 0);
+ msm_ispif_clk_enable_one(ispif, i, 0);
ispif->ispif_state = ISPIF_POWER_DOWN;
}
@@ -961,7 +1055,7 @@
case VIDIOC_MSM_ISPIF_CFG:
return msm_ispif_cmd(sd, arg);
default:
- pr_err("%s: invalid cmd received\n", __func__);
+ pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
return -ENOIOCTLCMD;
}
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 8a21512..35210a0 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -13,9 +13,15 @@
static struct msm_buf_mngr_device *msm_buf_mngr_dev;
+struct v4l2_subdev *msm_buf_mngr_get_subdev(void)
+{
+ return &msm_buf_mngr_dev->subdev.sd;
+}
+
static int msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev,
void __user *argp)
{
+ unsigned long flags;
struct msm_buf_mngr_info *buf_info =
(struct msm_buf_mngr_info *)argp;
struct msm_get_bufs *new_entry =
@@ -35,9 +41,9 @@
}
new_entry->session_id = buf_info->session_id;
new_entry->stream_id = buf_info->stream_id;
- mutex_lock(&buf_mngr_dev->buf_q_lock);
+ spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead);
- mutex_unlock(&buf_mngr_dev->buf_q_lock);
+ spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
buf_info->index = new_entry->vb2_buf->v4l2_buf.index;
return 0;
}
@@ -45,10 +51,11 @@
static int msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev,
struct msm_buf_mngr_info *buf_info)
{
+ unsigned long flags;
struct msm_get_bufs *bufs, *save;
int ret = -EINVAL;
- mutex_lock(&buf_mngr_dev->buf_q_lock);
+ spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
if ((bufs->session_id == buf_info->session_id) &&
(bufs->stream_id == buf_info->stream_id) &&
@@ -64,7 +71,7 @@
break;
}
}
- mutex_unlock(&buf_mngr_dev->buf_q_lock);
+ spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
return ret;
}
@@ -72,10 +79,11 @@
static int msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev,
struct msm_buf_mngr_info *buf_info)
{
+ unsigned long flags;
struct msm_get_bufs *bufs, *save;
int ret = -EINVAL;
- mutex_lock(&buf_mngr_dev->buf_q_lock);
+ spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
if ((bufs->session_id == buf_info->session_id) &&
(bufs->stream_id == buf_info->stream_id) &&
@@ -87,7 +95,7 @@
break;
}
}
- mutex_unlock(&buf_mngr_dev->buf_q_lock);
+ spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
return ret;
}
@@ -163,14 +171,13 @@
&msm_buf_mngr_dev->vb2_ops);
INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead);
- mutex_init(&msm_buf_mngr_dev->buf_q_lock);
+ spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock);
end:
return rc;
}
static void __exit msm_buf_mngr_exit(void)
{
- mutex_destroy(&msm_buf_mngr_dev->buf_q_lock);
kfree(msm_buf_mngr_dev);
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
index a2b3a7e..56886cd 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -33,7 +33,7 @@
struct msm_buf_mngr_device {
struct list_head buf_qhead;
- struct mutex buf_q_lock;
+ spinlock_t buf_q_spinlock;
struct msm_sd_subdev subdev;
struct msm_sd_req_vb2_q vb2_ops;
};
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8f63d33..c06b009 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -22,7 +22,6 @@
#include <linux/regulator/consumer.h>
#include <linux/ion.h>
#include <linux/proc_fs.h>
-#include <linux/debugfs.h>
#include <linux/msm_ion.h>
#include <linux/iommu.h>
#include <mach/iommu_domains.h>
@@ -33,11 +32,14 @@
#include <media/v4l2-ioctl.h>
#include <media/msmb_camera.h>
#include <media/msmb_pproc.h>
+#include <media/msmb_generic_buf_mgr.h>
#include "msm_cpp.h"
#include "msm_camera_io_util.h"
#define MSM_CPP_DRV_NAME "msm_cpp"
+#define MSM_CPP_MAX_BUFF_QUEUE 16
+
#define CONFIG_MSM_CPP_DBG 0
#if CONFIG_MSM_CPP_DBG
@@ -126,6 +128,278 @@
return tmp;
}
+static struct msm_cpp_buff_queue_info_t *msm_cpp_get_buff_queue_entry(
+ struct cpp_device *cpp_dev, uint32_t session_id, uint32_t stream_id)
+{
+ uint32_t i = 0;
+ struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL;
+
+ for (i = 0; i < cpp_dev->num_buffq; i++) {
+ if ((cpp_dev->buff_queue[i].used == 1) &&
+ (cpp_dev->buff_queue[i].session_id == session_id) &&
+ (cpp_dev->buff_queue[i].stream_id == stream_id)) {
+ buff_queue_info = &cpp_dev->buff_queue[i];
+ break;
+ }
+ }
+
+ if (buff_queue_info == NULL) {
+ pr_err("error buffer queue entry for sess:%d strm:%d not found\n",
+ session_id, stream_id);
+ }
+ return buff_queue_info;
+}
+
+static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev,
+ struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+ uint8_t native_buff)
+{
+ unsigned long phy_add = 0;
+ struct list_head *buff_head;
+ struct msm_cpp_buffer_map_list_t *buff, *save;
+
+ if (native_buff)
+ buff_head = &buff_queue_info->native_buff_head;
+ else
+ buff_head = &buff_queue_info->vb2_buff_head;
+
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ if (buff->map_info.buff_info.index == buff_index) {
+ phy_add = buff->map_info.phy_addr;
+ break;
+ }
+ }
+
+ return phy_add;
+}
+
+static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
+ struct msm_cpp_buff_queue_info_t *buff_queue,
+ struct msm_cpp_buffer_info_t *buffer_info)
+{
+ struct list_head *buff_head;
+ struct msm_cpp_buffer_map_list_t *buff, *save;
+ int rc = 0;
+
+ if (buffer_info->native_buff)
+ buff_head = &buff_queue->native_buff_head;
+ else
+ buff_head = &buff_queue->vb2_buff_head;
+
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ if (buff->map_info.buff_info.index == buffer_info->index) {
+ pr_err("error buffer index already queued\n");
+ return -EINVAL;
+ }
+ }
+
+ buff = kzalloc(
+ sizeof(struct msm_cpp_buffer_map_list_t), GFP_KERNEL);
+ if (!buff) {
+ pr_err("error allocating memory\n");
+ return -EINVAL;
+ }
+
+ buff->map_info.buff_info = *buffer_info;
+ buff->map_info.ion_handle = ion_import_dma_buf(cpp_dev->client,
+ buffer_info->fd);
+ if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) {
+ pr_err("ION import failed\n");
+ goto QUEUE_BUFF_ERROR1;
+ }
+
+ rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle,
+ cpp_dev->domain_num, 0, SZ_4K, 0,
+ (unsigned long *)&buff->map_info.phy_addr,
+ &buff->map_info.len, 0, 0);
+ if (rc < 0) {
+ pr_err("ION mmap failed\n");
+ goto QUEUE_BUFF_ERROR2;
+ }
+
+ INIT_LIST_HEAD(&buff->entry);
+ list_add_tail(&buff->entry, buff_head);
+
+ return buff->map_info.phy_addr;
+
+QUEUE_BUFF_ERROR2:
+ ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
+ cpp_dev->domain_num, 0);
+QUEUE_BUFF_ERROR1:
+ ion_free(cpp_dev->client, buff->map_info.ion_handle);
+ buff->map_info.ion_handle = NULL;
+ kzfree(buff);
+
+ return 0;
+}
+
+static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
+ struct msm_cpp_buffer_map_list_t *buff)
+{
+ ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
+ cpp_dev->domain_num, 0);
+ ion_free(cpp_dev->client, buff->map_info.ion_handle);
+ buff->map_info.ion_handle = NULL;
+
+ list_del_init(&buff->entry);
+ kzfree(buff);
+
+ return;
+}
+
+static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev,
+ struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id,
+ uint32_t stream_id)
+{
+ unsigned long phy_addr = 0;
+ struct msm_cpp_buff_queue_info_t *buff_queue_info;
+ uint8_t native_buff = buffer_info->native_buff;
+
+ buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id,
+ stream_id);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ session_id, stream_id);
+ return phy_addr;
+ }
+
+ phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info,
+ buffer_info->index, native_buff);
+ if ((phy_addr == 0) && (native_buff)) {
+ phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info,
+ buffer_info);
+ }
+ return phy_addr;
+}
+
+static int32_t msm_cpp_enqueue_buff_info_list(struct cpp_device *cpp_dev,
+ struct msm_cpp_stream_buff_info_t *stream_buff_info)
+{
+ uint32_t j;
+ struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+ buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev,
+ (stream_buff_info->identity >> 16) & 0xFFFF,
+ stream_buff_info->identity & 0xFFFF);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ (stream_buff_info->identity >> 16) & 0xFFFF,
+ stream_buff_info->identity & 0xFFFF);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < stream_buff_info->num_buffs; j++) {
+ msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info,
+ &stream_buff_info->buffer_info[j]);
+ }
+ return 0;
+}
+
+static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev,
+ struct msm_cpp_buff_queue_info_t *buff_queue_info)
+{
+ struct msm_cpp_buffer_map_list_t *buff, *save;
+ struct list_head *buff_head;
+
+ buff_head = &buff_queue_info->native_buff_head;
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ msm_cpp_dequeue_buffer_info(cpp_dev, buff);
+ }
+
+ buff_head = &buff_queue_info->vb2_buff_head;
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ msm_cpp_dequeue_buffer_info(cpp_dev, buff);
+ }
+
+ return 0;
+}
+
+static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev,
+ uint16_t session_id, uint16_t stream_id)
+{
+ uint32_t i;
+ struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+ for (i = 0; i < cpp_dev->num_buffq; i++) {
+ if (cpp_dev->buff_queue[i].used == 0) {
+ buff_queue_info = &cpp_dev->buff_queue[i];
+ buff_queue_info->used = 1;
+ buff_queue_info->session_id = session_id;
+ buff_queue_info->stream_id = stream_id;
+ INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+ INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+ return 0;
+ }
+ }
+ pr_err("buffer queue full. error for sessionid: %d streamid: %d\n",
+ session_id, stream_id);
+ return -EINVAL;
+}
+
+static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev,
+ uint32_t session_id, uint32_t stream_id)
+{
+ struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+ buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id,
+ stream_id);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ session_id, stream_id);
+ return -EINVAL;
+ }
+
+ buff_queue_info->used = 0;
+ buff_queue_info->session_id = 0;
+ buff_queue_info->stream_id = 0;
+ INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+ INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+ return 0;
+}
+
+static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev,
+ uint32_t num_buffq)
+{
+ struct msm_cpp_buff_queue_info_t *buff_queue;
+ buff_queue = kzalloc(
+ sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq,
+ GFP_KERNEL);
+ if (!buff_queue) {
+ pr_err("Buff queue allocation failure\n");
+ return -ENOMEM;
+ }
+
+ if (cpp_dev->buff_queue) {
+ pr_err("Buff queue not empty\n");
+ kzfree(buff_queue);
+ return -EINVAL;
+ } else {
+ cpp_dev->buff_queue = buff_queue;
+ cpp_dev->num_buffq = num_buffq;
+ }
+ return 0;
+}
+
+static void msm_cpp_delete_buff_queue(struct cpp_device *cpp_dev)
+{
+ uint32_t i;
+
+ for (i = 0; i < cpp_dev->num_buffq; i++) {
+ if (cpp_dev->buff_queue[i].used == 1) {
+ pr_err("Queue not free sessionid: %d, streamid: %d\n",
+ cpp_dev->buff_queue[i].session_id,
+ cpp_dev->buff_queue[i].stream_id);
+ msm_cpp_free_buff_queue_entry(cpp_dev,
+ cpp_dev->buff_queue[i].session_id,
+ cpp_dev->buff_queue[i].stream_id);
+ }
+ }
+ kzfree(cpp_dev->buff_queue);
+ cpp_dev->buff_queue = NULL;
+ cpp_dev->num_buffq = 0;
+ return;
+}
+
static void msm_cpp_poll(void __iomem *cpp_base, u32 val)
{
uint32_t tmp, retry = 0;
@@ -176,12 +450,13 @@
static irqreturn_t msm_cpp_irq(int irq_num, void *data)
{
+ unsigned long flags;
uint32_t tx_level;
uint32_t irq_status;
- uint32_t msg_id, cmd_len;
uint32_t i;
- uint32_t tx_fifo[16];
+ uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
struct cpp_device *cpp_dev = data;
+ struct msm_cpp_tasklet_queue_cmd *queue_cmd;
irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT);
CPP_DBG("status: 0x%x\n", irq_status);
if (irq_status & 0x8) {
@@ -192,6 +467,62 @@
MSM_CPP_MICRO_FIFO_TX_DATA);
}
+ spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
+ queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx];
+ if (queue_cmd->cmd_used) {
+ pr_err("%s: cpp tasklet queue overflow\n", __func__);
+ list_del(&queue_cmd->list);
+ } else {
+ atomic_add(1, &cpp_dev->irq_cnt);
+ }
+ queue_cmd->irq_status = irq_status;
+ queue_cmd->tx_level = tx_level;
+ memset(&queue_cmd->tx_fifo[0], 0, sizeof(queue_cmd->tx_fifo));
+ for (i = 0; i < tx_level; i++)
+ queue_cmd->tx_fifo[i] = tx_fifo[i];
+
+ queue_cmd->cmd_used = 1;
+ cpp_dev->taskletq_idx =
+ (cpp_dev->taskletq_idx + 1) % MSM_CPP_TASKLETQ_SIZE;
+ list_add_tail(&queue_cmd->list, &cpp_dev->tasklet_q);
+ spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+
+ tasklet_schedule(&cpp_dev->cpp_tasklet);
+ }
+ msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
+ return IRQ_HANDLED;
+}
+
+void msm_cpp_do_tasklet(unsigned long data)
+{
+ unsigned long flags;
+ uint32_t irq_status;
+ uint32_t tx_level;
+ uint32_t msg_id, cmd_len;
+ uint32_t i;
+ uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
+ struct cpp_device *cpp_dev = (struct cpp_device *) data;
+ struct msm_cpp_tasklet_queue_cmd *queue_cmd;
+
+ while (atomic_read(&cpp_dev->irq_cnt)) {
+ spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
+ queue_cmd = list_first_entry(&cpp_dev->tasklet_q,
+ struct msm_cpp_tasklet_queue_cmd, list);
+ if (!queue_cmd) {
+ atomic_set(&cpp_dev->irq_cnt, 0);
+ spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+ return;
+ }
+ atomic_sub(1, &cpp_dev->irq_cnt);
+ list_del(&queue_cmd->list);
+ queue_cmd->cmd_used = 0;
+ irq_status = queue_cmd->irq_status;
+ tx_level = queue_cmd->tx_level;
+ for (i = 0; i < tx_level; i++)
+ tx_fifo[i] = queue_cmd->tx_fifo[i];
+
+ spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+
for (i = 0; i < tx_level; i++) {
if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) {
cmd_len = tx_fifo[i+1];
@@ -204,8 +535,6 @@
}
}
}
- msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
- return IRQ_HANDLED;
}
static void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
@@ -309,6 +638,7 @@
rc = -EBUSY;
goto req_irq_fail;
}
+ cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
}
cpp_dev->hw_info.cpp_hw_version =
@@ -318,6 +648,9 @@
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4);
pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps);
msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
+ cpp_dev->taskletq_idx = 0;
+ atomic_set(&cpp_dev->irq_cnt, 0);
+ msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
if (cpp_dev->is_firmware_loaded == 1)
msm_cpp_boot_hw(cpp_dev);
return rc;
@@ -339,9 +672,12 @@
static void cpp_release_hardware(struct cpp_device *cpp_dev)
{
- if (cpp_dev->state != CPP_STATE_BOOT)
+ if (cpp_dev->state != CPP_STATE_BOOT) {
free_irq(cpp_dev->irq->start, cpp_dev);
-
+ tasklet_kill(&cpp_dev->cpp_tasklet);
+ atomic_set(&cpp_dev->irq_cnt, 0);
+ }
+ msm_cpp_delete_buff_queue(cpp_dev);
iounmap(cpp_dev->base);
iounmap(cpp_dev->vbif_base);
iounmap(cpp_dev->cpp_hw_base);
@@ -504,6 +840,18 @@
.close = cpp_close_node,
};
+static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
+ uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info)
+{
+ int rc = -EINVAL;
+
+ rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl,
+ buff_mgr_ops, buff_mgr_info);
+ if (rc < 0)
+ pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+ return rc;
+}
+
static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
{
struct v4l2_event v4l2_evt;
@@ -511,10 +859,13 @@
struct msm_queue_cmd *event_qcmd;
struct msm_cpp_frame_info_t *processed_frame;
struct msm_device_queue *queue = &cpp_dev->processing_q;
+ struct msm_buf_mngr_info buff_mgr_info;
+ int rc = 0;
if (queue->len > 0) {
frame_qcmd = msm_dequeue(queue, list_frame);
processed_frame = frame_qcmd->command;
+ do_gettimeofday(&(processed_frame->out_time));
kfree(frame_qcmd);
event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
if (!event_qcmd) {
@@ -526,78 +877,55 @@
CPP_DBG("fid %d\n", processed_frame->frame_id);
msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
+ if (!processed_frame->output_buffer_info.processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info.index;
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error putting buffer\n");
+ rc = -EINVAL;
+ }
+ }
v4l2_evt.id = processed_frame->inst_id;
v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
}
- return 0;
+ return rc;
}
-static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev)
+static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
+ struct msm_queue_cmd *frame_qcmd)
{
uint32_t i;
- struct msm_queue_cmd *frame_qcmd;
+ int32_t rc = -EINVAL;
struct msm_cpp_frame_info_t *process_frame;
- struct msm_device_queue *queue;
if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
- while (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
- if (cpp_dev->realtime_q.len != 0) {
- queue = &cpp_dev->realtime_q;
- } else if (cpp_dev->offline_q.len != 0) {
- queue = &cpp_dev->offline_q;
- } else {
- pr_debug("All frames queued\n");
- break;
- }
- frame_qcmd = msm_dequeue(queue, list_frame);
- process_frame = frame_qcmd->command;
- msm_enqueue(&cpp_dev->processing_q,
- &frame_qcmd->list_frame);
- msm_cpp_write(0x6, cpp_dev->base);
- for (i = 0; i < process_frame->msg_len; i++)
- msm_cpp_write(process_frame->cpp_cmd_msg[i],
- cpp_dev->base);
- }
+ process_frame = frame_qcmd->command;
+ msm_enqueue(&cpp_dev->processing_q,
+ &frame_qcmd->list_frame);
+ msm_cpp_write(0x6, cpp_dev->base);
+ for (i = 0; i < process_frame->msg_len; i++)
+ msm_cpp_write(process_frame->cpp_cmd_msg[i],
+ cpp_dev->base);
+ do_gettimeofday(&(process_frame->in_time));
+ rc = 0;
}
- return 0;
+ return rc;
}
static int msm_cpp_flush_frames(struct cpp_device *cpp_dev)
{
- struct v4l2_event v4l2_evt;
- struct msm_queue_cmd *frame_qcmd;
- struct msm_cpp_frame_info_t *process_frame;
- struct msm_device_queue *queue;
- struct msm_queue_cmd *event_qcmd;
-
- do {
- if (cpp_dev->realtime_q.len != 0) {
- queue = &cpp_dev->realtime_q;
- } else if (cpp_dev->offline_q.len != 0) {
- queue = &cpp_dev->offline_q;
- } else {
- pr_debug("All frames flushed\n");
- break;
- }
- frame_qcmd = msm_dequeue(queue, list_frame);
- process_frame = frame_qcmd->command;
- kfree(frame_qcmd);
- event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
- if (!event_qcmd) {
- pr_err("Insufficient memory. return");
- return -ENOMEM;
- }
- atomic_set(&event_qcmd->on_heap, 1);
- event_qcmd->command = process_frame;
- CPP_DBG("fid %d\n", process_frame->frame_id);
- msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
-
- v4l2_evt.id = process_frame->inst_id;
- v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
- v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
- } while ((cpp_dev->realtime_q.len != 0) ||
- (cpp_dev->offline_q.len != 0));
return 0;
}
@@ -609,9 +937,9 @@
struct msm_cpp_frame_info_t *new_frame =
kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
uint32_t *cpp_frame_msg;
- unsigned long len;
unsigned long in_phyaddr, out_phyaddr;
uint16_t num_stripes = 0;
+ struct msm_buf_mngr_info buff_mgr_info;
int i = 0;
if (!new_frame) {
@@ -646,44 +974,40 @@
new_frame->cpp_cmd_msg = cpp_frame_msg;
- CPP_DBG("CPP in_fd: %d out_fd: %d\n", new_frame->src_fd,
- new_frame->dst_fd);
-
- new_frame->src_ion_handle = ion_import_dma_buf(cpp_dev->client,
- new_frame->src_fd);
- if (IS_ERR_OR_NULL(new_frame->src_ion_handle)) {
- pr_err("ION import failed\n");
- rc = PTR_ERR(new_frame->src_ion_handle);
+ in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
+ &new_frame->input_buffer_info,
+ ((new_frame->identity >> 16) & 0xFFFF),
+ (new_frame->identity & 0xFFFF));
+ if (!in_phyaddr) {
+ pr_err("error gettting input physical address\n");
+ rc = -EINVAL;
goto ERROR2;
}
- rc = ion_map_iommu(cpp_dev->client, new_frame->src_ion_handle,
- cpp_dev->domain_num, 0, SZ_4K, 0,
- (unsigned long *)&in_phyaddr, &len, 0, 0);
+ memset(&new_frame->output_buffer_info, 0,
+ sizeof(struct msm_cpp_buffer_info_t));
+ memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF);
+ rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+ &buff_mgr_info);
if (rc < 0) {
- pr_err("ION import failed\n");
- rc = PTR_ERR(new_frame->src_ion_handle);
+ pr_err("error getting buffer\n");
+ rc = -EINVAL;
+ goto ERROR2;
+ }
+
+ new_frame->output_buffer_info.index = buff_mgr_info.index;
+ out_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
+ &new_frame->output_buffer_info,
+ ((new_frame->identity >> 16) & 0xFFFF),
+ (new_frame->identity & 0xFFFF));
+ if (!out_phyaddr) {
+ pr_err("error gettting output physical address\n");
+ rc = -EINVAL;
goto ERROR3;
}
- CPP_DBG("in phy addr: 0x%x len: %ld\n", (uint32_t) in_phyaddr, len);
- new_frame->dest_ion_handle = ion_import_dma_buf(cpp_dev->client,
- new_frame->dst_fd);
- if (IS_ERR_OR_NULL(new_frame->dest_ion_handle)) {
- pr_err("ION import failed\n");
- rc = PTR_ERR(new_frame->dest_ion_handle);
- goto ERROR4;
- }
-
- rc = ion_map_iommu(cpp_dev->client, new_frame->dest_ion_handle,
- cpp_dev->domain_num, 0, SZ_4K, 0,
- (unsigned long *)&out_phyaddr, &len, 0, 0);
- if (rc < 0) {
- rc = PTR_ERR(new_frame->dest_ion_handle);
- goto ERROR5;
- }
-
- CPP_DBG("out phy addr: 0x%x len: %ld\n", (uint32_t)out_phyaddr, len);
num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) +
((cpp_frame_msg[12] >> 10) & 0x3FF) +
(cpp_frame_msg[12] & 0x3FF);
@@ -700,44 +1024,29 @@
if (!frame_qcmd) {
pr_err("Insufficient memory. return\n");
rc = -ENOMEM;
- goto ERROR6;
+ goto ERROR3;
}
atomic_set(&frame_qcmd->on_heap, 1);
frame_qcmd->command = new_frame;
- if (new_frame->frame_type == MSM_CPP_REALTIME_FRAME) {
- msm_enqueue(&cpp_dev->realtime_q,
- &frame_qcmd->list_frame);
- } else if (new_frame->frame_type == MSM_CPP_OFFLINE_FRAME) {
- msm_enqueue(&cpp_dev->offline_q,
- &frame_qcmd->list_frame);
- } else {
- pr_err("Invalid frame type\n");
+ rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd);
+ if (rc < 0) {
+ pr_err("error cannot send frame to hardware\n");
rc = -EINVAL;
- goto ERROR7;
+ goto ERROR4;
}
- msm_cpp_send_frame_to_hardware(cpp_dev);
+
return rc;
-ERROR7:
- kfree(frame_qcmd);
-ERROR6:
- ion_unmap_iommu(cpp_dev->client, new_frame->dest_ion_handle,
- cpp_dev->domain_num, 0);
-ERROR5:
- ion_free(cpp_dev->client, new_frame->dest_ion_handle);
- new_frame->dest_ion_handle = NULL;
ERROR4:
- ion_unmap_iommu(cpp_dev->client, new_frame->src_ion_handle,
- cpp_dev->domain_num, 0);
+ kfree(frame_qcmd);
ERROR3:
- ion_free(cpp_dev->client, new_frame->src_ion_handle);
- new_frame->src_ion_handle = NULL;
+ msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+ &buff_mgr_info);
ERROR2:
kfree(cpp_frame_msg);
ERROR1:
kfree(new_frame);
return rc;
-
}
long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
@@ -795,6 +1104,97 @@
case VIDIOC_MSM_CPP_FLUSH_QUEUE:
rc = msm_cpp_flush_frames(cpp_dev);
break;
+ case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: {
+ struct msm_cpp_stream_buff_info_t *u_stream_buff_info;
+ struct msm_cpp_stream_buff_info_t k_stream_buff_info;
+ if (sizeof(struct msm_cpp_stream_buff_info_t) !=
+ ioctl_ptr->len) {
+ pr_err("%s:%d: invalid length\n", __func__, __LINE__);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!u_stream_buff_info) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = (copy_from_user(u_stream_buff_info,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len) ? -EFAULT : 0);
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ kfree(u_stream_buff_info);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
+ k_stream_buff_info.identity = u_stream_buff_info->identity;
+ k_stream_buff_info.buffer_info =
+ kzalloc(k_stream_buff_info.num_buffs *
+ sizeof(struct msm_cpp_buffer_info_t), GFP_KERNEL);
+ if (!k_stream_buff_info.buffer_info) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = (copy_from_user(k_stream_buff_info.buffer_info,
+ (void __user *)u_stream_buff_info->buffer_info,
+ k_stream_buff_info.num_buffs *
+ sizeof(struct msm_cpp_buffer_info_t)) ?
+ -EFAULT : 0);
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ kfree(k_stream_buff_info.buffer_info);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = msm_cpp_add_buff_queue_entry(cpp_dev,
+ ((k_stream_buff_info.identity >> 16) & 0xFFFF),
+ (k_stream_buff_info.identity & 0xFFFF));
+ if (!rc)
+ rc = msm_cpp_enqueue_buff_info_list(cpp_dev,
+ &k_stream_buff_info);
+
+ kfree(k_stream_buff_info.buffer_info);
+ kfree(u_stream_buff_info);
+ break;
+ }
+ case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: {
+ uint32_t identity;
+ struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+ rc = (copy_from_user(&identity,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len) ? -EFAULT : 0);
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev,
+ ((identity >> 16) & 0xFFFF), (identity & 0xFFFF));
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for identity:%d\n",
+ identity);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ msm_cpp_dequeue_buff_info_list(cpp_dev, buff_queue_info);
+ rc = msm_cpp_free_buff_queue_entry(cpp_dev,
+ buff_queue_info->session_id,
+ buff_queue_info->stream_id);
+ break;
+ }
case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
struct msm_device_queue *queue = &cpp_dev->eventData_q;
struct msm_queue_cmd *event_qcmd;
@@ -808,23 +1208,6 @@
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
- if (process_frame->dest_ion_handle) {
- ion_unmap_iommu(cpp_dev->client,
- process_frame->dest_ion_handle,
- cpp_dev->domain_num, 0);
- ion_free(cpp_dev->client,
- process_frame->dest_ion_handle);
- process_frame->dest_ion_handle = NULL;
- }
-
- if (process_frame->src_ion_handle) {
- ion_unmap_iommu(cpp_dev->client,
- process_frame->src_ion_handle,
- cpp_dev->domain_num, 0);
- ion_free(cpp_dev->client,
- process_frame->src_ion_handle);
- process_frame->src_ion_handle = NULL;
- }
kfree(process_frame->cpp_cmd_msg);
kfree(process_frame);
@@ -834,7 +1217,7 @@
}
mutex_unlock(&cpp_dev->mutex);
CPP_DBG("X\n");
- return 0;
+ return rc;
}
int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -861,8 +1244,6 @@
.core = &msm_cpp_subdev_core_ops,
};
-static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev);
-
static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops;
static long msm_cpp_subdev_do_ioctl(
@@ -960,6 +1341,7 @@
v4l2_set_subdevdata(&cpp_dev->msm_sd.sd, cpp_dev);
platform_set_drvdata(pdev, &cpp_dev->msm_sd.sd);
mutex_init(&cpp_dev->mutex);
+ spin_lock_init(&cpp_dev->tasklet_lock);
if (pdev->dev.of_node)
of_property_read_u32((&pdev->dev)->of_node,
@@ -1054,14 +1436,13 @@
cpp_release_hardware(cpp_dev);
cpp_dev->state = CPP_STATE_OFF;
- msm_cpp_enable_debugfs(cpp_dev);
msm_queue_init(&cpp_dev->eventData_q, "eventdata");
- msm_queue_init(&cpp_dev->offline_q, "frame");
- msm_queue_init(&cpp_dev->realtime_q, "frame");
msm_queue_init(&cpp_dev->processing_q, "frame");
+ INIT_LIST_HEAD(&cpp_dev->tasklet_q);
+ tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet,
+ (unsigned long)cpp_dev);
cpp_dev->cpp_open_cnt = 0;
cpp_dev->is_firmware_loaded = 0;
-
return rc;
ERROR3:
@@ -1126,65 +1507,6 @@
platform_driver_unregister(&cpp_driver);
}
-static int msm_cpp_debugfs_stream_s(void *data, u64 val)
-{
- struct cpp_device *cpp_dev = data;
- CPP_DBG("CPP processing frame E\n");
- while (1) {
- mutex_lock(&cpp_dev->mutex);
- msm_cpp_notify_frame_done(cpp_dev);
- msm_cpp_send_frame_to_hardware(cpp_dev);
- mutex_unlock(&cpp_dev->mutex);
- msleep(20);
- }
- CPP_DBG("CPP processing frame X\n");
- return 0;
-}
-
-static int msm_cpp_debugfs_load_fw(void *data, u64 val)
-{
- const struct firmware *fw = NULL;
- struct cpp_device *cpp_dev = data;
- int rc = 0;
- CPP_DBG("%s\n", __func__);
- rc = request_firmware(&fw, "FIRMWARE.bin", &cpp_dev->pdev->dev);
- if (rc) {
- pr_err("request_fw failed\n");
- } else {
- CPP_DBG("request ok\n");
- release_firmware(fw);
- }
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_stream, NULL,
- msm_cpp_debugfs_stream_s, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_fw, NULL,
- msm_cpp_debugfs_load_fw, "%llu\n");
-
-static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
-{
- struct dentry *debugfs_base, *debugfs_test;
- debugfs_base = debugfs_create_dir("msm_camera", NULL);
- if (!debugfs_base)
- return -ENOMEM;
-
- debugfs_test = debugfs_create_file("test", S_IRUGO | S_IWUSR,
- debugfs_base, (void *)cpp_dev, &cpp_debugfs_stream);
- if (!debugfs_test) {
- debugfs_remove(debugfs_base);
- return -ENOMEM;
- }
-
- if (!debugfs_create_file("fw", S_IRUGO | S_IWUSR, debugfs_base,
- (void *)cpp_dev, &cpp_debugfs_fw)) {
- debugfs_remove(debugfs_test);
- debugfs_remove(debugfs_base);
- return -ENOMEM;
- }
- return 0;
-}
-
module_init(msm_cpp_init_module);
module_exit(msm_cpp_exit_module);
MODULE_DESCRIPTION("MSM CPP driver");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 0c586ca..36a5fa5 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/platform_device.h>
+#include <linux/interrupt.h>
#include <media/v4l2-subdev.h>
#include "msm_sd.h"
@@ -70,6 +71,8 @@
#define MSM_CPP_END_ADDRESS 0x3F00
#define MSM_CPP_POLL_RETRIES 20
+#define MSM_CPP_TASKLETQ_SIZE 16
+#define MSM_CPP_TX_FIFO_LEVEL 16
struct cpp_subscribe_info {
struct v4l2_fh *vfh;
@@ -116,6 +119,34 @@
const char *name;
};
+struct msm_cpp_tasklet_queue_cmd {
+ struct list_head list;
+ uint32_t irq_status;
+ uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
+ uint32_t tx_level;
+ uint8_t cmd_used;
+};
+
+struct msm_cpp_buffer_map_info_t {
+ unsigned long len;
+ unsigned long phy_addr;
+ struct ion_handle *ion_handle;
+ struct msm_cpp_buffer_info_t buff_info;
+};
+
+struct msm_cpp_buffer_map_list_t {
+ struct msm_cpp_buffer_map_info_t map_info;
+ struct list_head entry;
+};
+
+struct msm_cpp_buff_queue_info_t {
+ uint32_t used;
+ uint16_t session_id;
+ uint16_t stream_id;
+ struct list_head vb2_buff_head;
+ struct list_head native_buff_head;
+};
+
struct cpp_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
@@ -141,19 +172,28 @@
struct ion_client *client;
struct kref refcount;
+ /* Reusing proven tasklet from msm isp */
+ atomic_t irq_cnt;
+ uint8_t taskletq_idx;
+ spinlock_t tasklet_lock;
+ struct list_head tasklet_q;
+ struct tasklet_struct cpp_tasklet;
+ struct msm_cpp_tasklet_queue_cmd
+ tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE];
+
struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
uint32_t cpp_open_cnt;
struct cpp_hw_info hw_info;
struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
- /* Offline Frame Queue process when realtime queue is empty */
- struct msm_device_queue offline_q;
- /* Realtime Frame Queue process with highest priority */
- struct msm_device_queue realtime_q;
/* Processing Queue
* store frame info for frames sent to microcontroller
*/
struct msm_device_queue processing_q;
+
+ struct msm_cpp_buff_queue_info_t *buff_queue;
+ uint32_t num_buffq;
+ struct v4l2_subdev *buf_mgr_subdev;
};
#endif /* __MSM_CPP_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 0df0488..fbd4a2e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -24,7 +24,7 @@
#define CSID_VERSION_V3 0x30000000
#define MSM_CSID_DRV_NAME "msm_csid"
-#define DBG_CSID 1
+#define DBG_CSID 0
#define TRUE 1
#define FALSE 0
@@ -36,8 +36,6 @@
#define CDBG(fmt, args...) do { } while (0)
#endif
-static uint32_t irq_count;
-
static int msm_csid_cid_lut(
struct msm_camera_csid_lut_params *csid_lut_params,
void __iomem *csidbase)
@@ -84,8 +82,8 @@
{
uint32_t val = 0;
val = ((1 << csid_params->lane_cnt) - 1) << 20;
- msm_camera_io_w(0x7f010801 | val, csidbase + CSID_IRQ_MASK_ADDR);
- msm_camera_io_w(0x7f010801 | val, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
+ msm_camera_io_w(0x7f010800 | val, csidbase + CSID_IRQ_MASK_ADDR);
+ msm_camera_io_w(0x7f010800 | val, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
}
#else
static void msm_csid_set_debug_reg(void __iomem *csidbase,
@@ -94,11 +92,8 @@
static void msm_csid_reset(struct csid_device *csid_dev)
{
- CDBG("%s:%d called\n", __func__, __LINE__);
msm_camera_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
- CDBG("%s:%d called\n", __func__, __LINE__);
wait_for_completion_interruptible(&csid_dev->reset_complete);
- CDBG("%s:%d called\n", __func__, __LINE__);
return;
}
@@ -159,11 +154,6 @@
__func__, csid_dev->pdev->id, irq);
if (irq & (0x1 << CSID_RST_DONE_IRQ_BITSHIFT))
complete(&csid_dev->reset_complete);
- if (irq & 0x1) {
- pr_debug("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
- __func__, csid_dev->pdev->id, irq);
- irq_count++;
- }
msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
return IRQ_HANDLED;
}
@@ -253,13 +243,11 @@
int rc = 0;
uint8_t core_id = 0;
- CDBG("%s:%d called\n", __func__, __LINE__);
if (!csid_version) {
pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
rc = -EINVAL;
return rc;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
if (csid_dev->csid_state == CSID_POWER_UP) {
pr_err("%s: csid invalid state %d\n", __func__,
@@ -267,7 +255,6 @@
rc = -EINVAL;
return rc;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
csid_dev->base = ioremap(csid_dev->mem->start,
resource_size(csid_dev->mem));
@@ -276,10 +263,8 @@
rc = -ENOMEM;
return rc;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
if (CSID_VERSION <= CSID_VERSION_V2) {
- CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 1);
@@ -287,7 +272,6 @@
pr_err("%s: regulator on failed\n", __func__);
goto vreg_config_failed;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
@@ -296,7 +280,6 @@
pr_err("%s: regulator enable failed\n", __func__);
goto vreg_enable_failed;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
csid_8960_clk_info, csid_dev->csid_clk,
@@ -305,9 +288,7 @@
pr_err("%s: clock enable failed\n", __func__);
goto clk_enable_failed;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
} else if (CSID_VERSION >= CSID_VERSION_V3) {
- CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 1);
@@ -315,7 +296,6 @@
pr_err("%s: regulator on failed\n", __func__);
goto vreg_config_failed;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
@@ -324,7 +304,6 @@
pr_err("%s: regulator enable failed\n", __func__);
goto vreg_enable_failed;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
@@ -333,10 +312,8 @@
pr_err("%s: clock enable failed\n", __func__);
goto csid0_clk_enable_failed;
}
- CDBG("%s:%d called\n", __func__, __LINE__);
core_id = csid_dev->pdev->id;
if (core_id) {
- CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
csid_8974_clk_info[core_id].clk_info,
csid_dev->csid_clk,
@@ -348,7 +325,6 @@
}
}
}
- CDBG("%s:%d called\n", __func__, __LINE__);
csid_dev->hw_version =
msm_camera_io_r(csid_dev->base + CSID_HW_VERSION_ADDR);
@@ -356,17 +332,12 @@
csid_dev->hw_version);
*csid_version = csid_dev->hw_version;
- CDBG("%s:%d called\n", __func__, __LINE__);
init_completion(&csid_dev->reset_complete);
- CDBG("%s:%d called\n", __func__, __LINE__);
enable_irq(csid_dev->irq->start);
- CDBG("%s:%d called\n", __func__, __LINE__);
msm_csid_reset(csid_dev);
- CDBG("%s:%d called\n", __func__, __LINE__);
csid_dev->csid_state = CSID_POWER_UP;
- irq_count = 0;
return rc;
clk_enable_failed:
@@ -578,7 +549,6 @@
struct csid_device *new_csid_dev;
uint32_t csi_vdd_voltage = 0;
int rc = 0;
- CDBG("%s:%d called\n", __func__, __LINE__);
new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
if (!new_csid_dev) {
pr_err("%s: no enough memory\n", __func__);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 83b9bb3..b6bc0d7 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -640,109 +640,109 @@
debugfs_create_u32(
"hw_notification_interval",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->hw_notification_interval);
debugfs_create_u32(
"hw_notification_min_interval",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->hw_notification_min_interval);
debugfs_create_u32(
"hw_notification_count",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->hw_notification_count);
debugfs_create_u32(
"hw_notification_size",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->hw_notification_size);
debugfs_create_u32(
"hw_notification_min_size",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->hw_notification_min_size);
debugfs_create_u32(
"decoder_drop_count",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->decoder_drop_count);
debugfs_create_u32(
"decoder_out_count",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->decoder_out_count);
debugfs_create_u32(
"decoder_out_interval_sum",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->decoder_out_interval_sum);
debugfs_create_u32(
"decoder_out_interval_average",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->decoder_out_interval_average);
debugfs_create_u32(
"decoder_out_interval_max",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->decoder_out_interval_max);
debugfs_create_u32(
"decoder_ts_errors",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->decoder_ts_errors);
debugfs_create_u32(
"sdmx_process_count",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->sdmx_process_count);
debugfs_create_u32(
"sdmx_process_time_sum",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->sdmx_process_time_sum);
debugfs_create_u32(
"sdmx_process_time_average",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->sdmx_process_time_average);
debugfs_create_u32(
"sdmx_process_time_max",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->sdmx_process_time_max);
debugfs_create_u32(
"sdmx_process_packets_sum",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->sdmx_process_packets_sum);
debugfs_create_u32(
"sdmx_process_packets_average",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->sdmx_process_packets_average);
debugfs_create_u32(
"sdmx_process_packets_min",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
&mpq_demux->sdmx_process_packets_min);
}
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index d782227..50adb13 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -1245,6 +1245,15 @@
"Failed to load buffer usage table: %d\n", rc);
goto err_load_buffer_usage_table;
}
+
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
+ &res->max_load);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to determine max load supported: %d\n", rc);
+ goto err_load_buffer_usage_table;
+ }
+
return rc;
err_load_buffer_usage_table:
@@ -1295,6 +1304,8 @@
res->load_freq_tbl[c].load = pdata->load_table[c][0];
res->load_freq_tbl[c].freq = pdata->load_table[c][1];
}
+
+ res->max_load = pdata->max_load;
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 8f8e723..2ca5008 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -241,7 +241,7 @@
static u32 get_frame_size_compressed(int plane,
u32 height, u32 width)
{
- return (MAX_SUPPORTED_WIDTH * MAX_SUPPORTED_HEIGHT * 3/2)/2;
+ return (width * height * 3/2)/2;
}
struct msm_vidc_format vdec_formats[] = {
@@ -302,6 +302,14 @@
.type = OUTPUT_PORT,
},
{
+ .name = "HEVC",
+ .description = "HEVC compressed format",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
@@ -630,8 +638,8 @@
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
fmt->get_frame_size(i,
- f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
+ inst->capability.height.max,
+ inst->capability.width.max);
inst->bufq[OUTPUT_PORT].
vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
@@ -767,8 +775,8 @@
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
fmt->get_frame_size(i,
- f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
+ inst->capability.height.max,
+ inst->capability.width.max);
}
} else {
buff_req_buffer =
@@ -827,8 +835,8 @@
frame_sz.height = inst->prop.height;
msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
f->fmt.pix_mp.plane_fmt[0].sizeimage =
- fmt->get_frame_size(0, f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
+ fmt->get_frame_size(0, inst->capability.height.max,
+ inst->capability.width.max);
f->fmt.pix_mp.num_planes = fmt->num_planes;
for (i = 0; i < fmt->num_planes; ++i) {
inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
@@ -921,7 +929,8 @@
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
for (i = 0; i < *num_planes; i++) {
sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
- i, inst->prop.height, inst->prop.width);
+ i, inst->capability.height.max,
+ inst->capability.width.max);
}
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 4346a4e..8eecb98 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -22,7 +22,7 @@
#include "msm_smem.h"
#include "msm_vidc_debug.h"
-#define HW_RESPONSE_TIMEOUT msecs_to_jiffies(200)
+#define HW_RESPONSE_TIMEOUT 200
#define IS_ALREADY_IN_STATE(__p, __d) ({\
int __rc = (__p >= __d);\
@@ -49,11 +49,6 @@
#define TIME_DIFF_THRESHOLD 200
-/*Load is in Macroblocks (MBs) per sec. This value is calculated
- * based on one 4k video instance @ 24 fps plus one 1080p video
- * instance @ 30fps. 1 MB = 16 X 16 pixels*/
-#define MAX_LOAD 1074240
-
static int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type)
{
@@ -142,9 +137,10 @@
}
mutex_lock(&vidc_driver->lock);
list_for_each_entry(core, &vidc_driver->cores, list) {
- if (core && core->id == core_id)
+ if (core && core->id == core_id) {
found = 1;
break;
+ }
}
mutex_unlock(&vidc_driver->lock);
if (found)
@@ -366,22 +362,27 @@
}
}
+static void queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
+{
+ struct v4l2_event event = {.id = 0, .type = event_type};
+ v4l2_event_queue_fh(&inst->event_handler, &event);
+ wake_up(&inst->kernel_event_queue);
+}
+
static void handle_event_change(enum command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct v4l2_event dqevent;
struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
+ int event = 0;
int rc = 0;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- dqevent.id = 0;
event_notify = (struct msm_vidc_cb_event *) response->data;
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
control.id =
V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
@@ -389,24 +390,24 @@
dprintk(VIDC_WARN,
"Failed to get Smooth streamng flag\n");
if (!rc && control.value == true)
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
break;
default:
break;
}
+
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
+
rc = msm_vidc_check_session_supported(inst);
if (!rc) {
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst, event);
}
+
return;
} else {
dprintk(VIDC_ERR,
@@ -496,13 +497,9 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct v4l2_event dqevent;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
} else {
dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
}
@@ -512,7 +509,6 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst = NULL;
- struct v4l2_event dqevent;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
if (inst) {
@@ -521,10 +517,7 @@
mutex_lock(&inst->sync_lock);
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->sync_lock);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
} else {
dprintk(VIDC_ERR,
@@ -536,7 +529,6 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst = NULL ;
struct msm_vidc_core *core = NULL;
- struct v4l2_event dqevent;
if (response) {
core = get_vidc_core(response->device_id);
dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
@@ -544,18 +536,14 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
list_for_each_entry(inst, &core->instances,
list) {
- v4l2_event_queue_fh(&inst->event_handler,
- &dqevent);
-
mutex_lock(&inst->lock);
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->lock);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
} else {
dprintk(VIDC_ERR,
@@ -572,7 +560,6 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
struct msm_vidc_core *core = NULL;
- struct v4l2_event dqevent;
dprintk(VIDC_ERR, "Venus Subsystem crashed\n");
core = get_vidc_core(response->device_id);
if (!core) {
@@ -583,11 +570,9 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
list_for_each_entry(inst, &core->instances, list) {
if (inst) {
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
mutex_lock(&inst->lock);
inst->state = MSM_VIDC_CORE_INVALID;
inst->session = NULL;
@@ -600,15 +585,11 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct v4l2_event dqevent;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
- dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
inst->session = NULL;
- wake_up(&inst->kernel_event_queue);
show_stats(inst);
} else {
dprintk(VIDC_ERR,
@@ -1212,6 +1193,10 @@
HAL_VIDEO_CODEC_SPARK
HAL_VIDEO_CODEC_VP6
HAL_VIDEO_CODEC_VP7*/
+ case V4L2_PIX_FMT_HEVC:
+ codec = HAL_VIDEO_CODEC_HEVC;
+ break;
+
default:
dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
codec = HAL_UNUSED_CODEC;
@@ -1275,13 +1260,32 @@
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
}
+
num_mbs_per_sec = msm_comm_get_load(inst->core, MSM_VIDC_DECODER);
num_mbs_per_sec += msm_comm_get_load(inst->core, MSM_VIDC_ENCODER);
- if (num_mbs_per_sec > MAX_LOAD) {
- dprintk(VIDC_ERR, "HW is overloaded, needed:%d max: %d\n",
- num_mbs_per_sec, MAX_LOAD);
+ if (num_mbs_per_sec > inst->core->resources.max_load) {
+ struct msm_vidc_inst *temp;
+
+ dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
+ num_mbs_per_sec, inst->core->resources.max_load);
+ dprintk(VIDC_ERR, "Running instances:\n");
+ dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s\n", "type", "w", "h", "fps");
+ list_for_each_entry(temp, &inst->core->instances, list) {
+ mutex_lock(&temp->lock);
+ if (temp->state >= MSM_VIDC_OPEN_DONE &&
+ temp->state < MSM_VIDC_STOP_DONE) {
+ dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d\n",
+ temp->session_type,
+ temp->prop.width,
+ temp->prop.height,
+ temp->prop.fps);
+ }
+ mutex_unlock(&temp->lock);
+ }
+
return -ENOMEM;
}
+
hdev = inst->core->device;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
@@ -2144,7 +2148,6 @@
static void msm_comm_flush_in_invalid_state(struct msm_vidc_inst *inst)
{
- struct v4l2_event dqevent = {0};
struct list_head *ptr, *next;
struct vb2_buffer *vb;
if (!list_empty(&inst->bufq[CAPTURE_PORT].
@@ -2181,9 +2184,7 @@
}
}
}
- dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
return;
}
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 5948c7c..3208df9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -210,8 +210,7 @@
"Output" : "Capture");
for (j = 0; j < inst->fmts[i]->num_planes; j++)
write_str(&dbg_buf, "size for plane %d: %u\n", j,
- inst->fmts[i]->get_frame_size(j,
- inst->prop.height, inst->prop.width));
+ inst->bufq[i].vb2_bufq.plane_sizes[j]);
}
write_str(&dbg_buf, "-------------------------------\n");
for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 1bfbaa6..e5696be 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -37,7 +37,7 @@
#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
#define MAX_DEBUGFS_NAME 50
#define DEFAULT_TIMEOUT 3
-#define DEFAULT_HEIGHT 1080
+#define DEFAULT_HEIGHT 1088
#define DEFAULT_WIDTH 1920
#define MIN_SUPPORTED_WIDTH 32
#define MIN_SUPPORTED_HEIGHT 32
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 86b824b..693c1a5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -74,6 +74,7 @@
struct iommu_set iommu_group_set;
struct buffer_usage_set buffer_usage_set;
bool has_ocmem;
+ uint32_t max_load;
struct platform_device *pdev;
};
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index afe1431..123b654 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -12,6 +12,8 @@
*/
#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
#include <mach/qdsp6v2/apr.h>
#include <mach/subsystem_restart.h>
#include "hfi_packetization.h"
@@ -19,6 +21,7 @@
#include "q6_hfi.h"
#include "vidc_hfi_api.h"
+static struct hal_device_data hal_ctxt;
static int write_queue(void *info, u8 *packet)
{
@@ -190,17 +193,86 @@
static int q6_hfi_register_iommu_domains(struct q6_hfi_device *device)
{
- (void)device;
+ struct iommu_domain *domain;
+ int rc = 0, i = 0;
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
- dprintk(VIDC_ERR, "Not implemented: %s", __func__);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return -EINVAL;
+ }
- return 0;
+ iommu_group_set = &device->res->iommu_group_set;
+
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ iommu_map->group = iommu_group_find(iommu_map->name);
+ if (!iommu_map->group) {
+ dprintk(VIDC_ERR, "Failed to find group :%s\n",
+ iommu_map->name);
+ goto fail_group;
+ }
+ domain = iommu_group_get_iommudata(iommu_map->group);
+ if (IS_ERR_OR_NULL(domain)) {
+ dprintk(VIDC_ERR,
+ "Failed to get domain data for group %p",
+ iommu_map->group);
+ goto fail_group;
+ }
+ iommu_map->domain = msm_find_domain_no(domain);
+ if (iommu_map->domain < 0) {
+ dprintk(VIDC_ERR,
+ "Failed to get domain index for domain %p",
+ domain);
+ goto fail_group;
+ }
+ }
+ return rc;
+
+fail_group:
+ for (--i; i >= 0; i--) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if (iommu_map->group)
+ iommu_group_put(iommu_map->group);
+ iommu_map->group = NULL;
+ iommu_map->domain = -1;
+ }
+ return -EINVAL;
}
-static int q6_hfi_init_resources(struct q6_hfi_device *device)
+static void q6_hfi_deregister_iommu_domains(struct q6_hfi_device *device)
+{
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
+ int i = 0;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return;
+ }
+
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if (iommu_map->group)
+ iommu_group_put(iommu_map->group);
+ iommu_map->group = NULL;
+ iommu_map->domain = -1;
+ }
+}
+
+static int q6_hfi_init_resources(struct q6_hfi_device *device,
+ struct msm_vidc_platform_resources *res)
{
int rc = 0;
+ if (!device || !res) {
+ dprintk(VIDC_ERR, "Invalid device or resources");
+ return -EINVAL;
+ }
+
+ device->res = res;
rc = q6_hfi_register_iommu_domains(device);
if (rc)
dprintk(VIDC_ERR, "Failed to register iommu domains: %d\n", rc);
@@ -208,12 +280,17 @@
return rc;
}
+static void q6_hfi_deinit_resources(struct q6_hfi_device *device)
+{
+ q6_hfi_deregister_iommu_domains(device);
+}
+
static void *q6_hfi_add_device(u32 device_id,
hfi_cmd_response_callback callback)
{
struct q6_hfi_device *hdevice = NULL;
- if (device_id || !callback) {
+ if (!callback) {
dprintk(VIDC_ERR, "Invalid Paramters");
return NULL;
}
@@ -225,19 +302,23 @@
goto err_alloc;
}
- INIT_LIST_HEAD(&hal_ctxt.dev_head);
- INIT_LIST_HEAD(&hdevice->list);
hdevice->device_id = device_id;
hdevice->callback = callback;
+ dprintk(VIDC_DBG, "q6_hfi_add_device device_id %d\n", device_id);
+
INIT_WORK(&hdevice->vidc_worker, q6_hfi_core_work_handler);
hdevice->vidc_workq = create_singlethread_workqueue(
- "msm_vidc_workerq");
+ "msm_vidc_workerq_q6");
if (!hdevice->vidc_workq) {
dprintk(VIDC_ERR, ": create workq failed\n");
goto error_createq;
}
+ if (hal_ctxt.dev_count == 0)
+ INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+ INIT_LIST_HEAD(&hdevice->list);
list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
hal_ctxt.dev_count++;
@@ -249,6 +330,7 @@
}
static void *q6_hfi_get_device(u32 device_id,
+ struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
{
struct q6_hfi_device *device;
@@ -266,7 +348,7 @@
return NULL;
}
- rc = q6_hfi_init_resources(device);
+ rc = q6_hfi_init_resources(device, res);
if (rc) {
dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
goto err_fail_init_res;
@@ -283,12 +365,15 @@
struct q6_hfi_device *close, *dev;
if (device) {
+ q6_hfi_deinit_resources(device);
dev = (struct q6_hfi_device *) device;
list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+ if (close->device_id == dev->device_id) {
hal_ctxt.dev_count--;
list_del(&close->list);
destroy_workqueue(close->vidc_workq);
kfree(close);
+ }
}
}
@@ -394,7 +479,7 @@
q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
- rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_ARCH_OX_OFFSET);
+ rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
if (rc) {
dprintk(VIDC_ERR, "Failed to create sys init pkt");
goto err_core_init;
@@ -1115,13 +1200,74 @@
return -ENOTSUPP;
}
-static int q6_hfi_iommu_attach(void *dev)
+static int q6_hfi_iommu_attach(struct q6_hfi_device *device)
{
- (void)dev;
+ int rc = 0;
+ struct iommu_domain *domain;
+ int i;
+ struct iommu_set *iommu_group_set;
+ struct iommu_group *group;
+ struct iommu_info *iommu_map;
- dprintk(VIDC_ERR, "Not implemented: %s", __func__);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return -EINVAL;
+ }
- return 0;
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (IS_ERR_OR_NULL(domain)) {
+ dprintk(VIDC_ERR, "Failed to get domain: %s",
+ iommu_map->name);
+ rc = IS_ERR(domain) ? PTR_ERR(domain) : -EINVAL;
+ break;
+ }
+ dprintk(VIDC_DBG, "Attaching domain(id:%d) %p to group %p",
+ iommu_map->domain, domain, group);
+ rc = iommu_attach_group(domain, group);
+ if (rc) {
+ dprintk(VIDC_ERR, "IOMMU attach failed: %s",
+ iommu_map->name);
+ break;
+ }
+ }
+ if (i < iommu_group_set->count) {
+ i--;
+ for (; i >= 0; i--) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (group && domain)
+ iommu_detach_group(domain, group);
+ }
+ }
+ return rc;
+}
+
+static void q6_hfi_iommu_detach(struct q6_hfi_device *device)
+{
+ struct iommu_group *group;
+ struct iommu_domain *domain;
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
+ int i;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return;
+ }
+
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (group && domain)
+ iommu_detach_group(domain, group);
+ }
}
static int q6_hfi_load_fw(void *dev)
@@ -1181,6 +1327,7 @@
return;
if (device->resources.fw.cookie) {
+ q6_hfi_iommu_detach(device);
subsystem_put(device->resources.fw.cookie);
device->resources.fw.cookie = NULL;
}
@@ -1246,16 +1393,18 @@
int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
{
int rc = 0;
- if (!hdev || !callback) {
- dprintk(VIDC_ERR, "Invalid params: %p %p\n", hdev, callback);
+ if (!hdev || !res || !callback) {
+ dprintk(VIDC_ERR, "Invalid params: %p %p %p",
+ hdev, res, callback);
rc = -EINVAL;
goto err_hfi_init;
}
- hdev->hfi_device_data = q6_hfi_get_device(device_id, callback);
+ hdev->hfi_device_data = q6_hfi_get_device(device_id, res, callback);
q6_init_hfi_callbacks(hdev);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
index 551eb04..3dc4607 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.h
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -13,9 +13,10 @@
#ifndef __Q6_HFI_H__
#define __Q6_HFI_H__
+#include <mach/qdsp6v2/apr.h>
#include "vidc_hfi.h"
#include "vidc_hfi_helper.h"
-#include <mach/qdsp6v2/apr.h>
+#include "msm_vidc_resources.h"
#define Q6_IFACEQ_QUEUE_SIZE (8 * 1024)
@@ -40,6 +41,7 @@
u32 device_id;
msm_vidc_callback callback;
struct q6_resources resources;
+ struct msm_vidc_platform_resources *res;
void *apr;
};
@@ -109,6 +111,7 @@
};
int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback);
void q6_hfi_delete_device(void *device);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 995c655..8031c74 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -37,6 +37,8 @@
#define SHARED_QSIZE 0x1000000
+static struct hal_device_data hal_ctxt;
+
static const u32 venus_qdss_entries[][2] = {
{0xFC307000, 0x1000},
{0xFC322000, 0x1000},
@@ -384,11 +386,22 @@
msm_smem_free(clnt, mem);
}
-static void venus_hfi_write_register(u8 *base_addr, u32 reg,
+static void venus_hfi_write_register(struct venus_hfi_device *device, u32 reg,
u32 value, u8 *vaddr)
{
u32 hwiosymaddr = reg;
+ u8 *base_addr;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return;
+ }
+ base_addr = device->hal_data->register_base_addr;
+ if (!device->clocks_enabled) {
+ dprintk(VIDC_WARN,
+ "HFI Write register failed : Clocks are OFF\n");
+ return;
+ }
reg &= REG_ADDR_OFFSET_BITMASK;
if (reg == (u32)VIDC_CPU_CS_SCIACMDARG2) {
/* workaround to offset of FW bias */
@@ -414,14 +427,26 @@
wmb();
}
-static int venus_hfi_read_register(u8 *base_addr, u32 reg)
+static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg)
{
- int rc = readl_relaxed((u32)base_addr + reg);
+ int rc ;
+ u8 *base_addr;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+
+ base_addr = device->hal_data->register_base_addr;
+ if (!device->clocks_enabled) {
+ dprintk(VIDC_WARN,
+ "HFI Read register failed : Clocks are OFF\n");
+ return -EINVAL;
+ }
+ rc = readl_relaxed((u32)base_addr + reg);
rmb();
return rc;
}
-static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device,
- enum vidc_clocks clk_level)
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
{
int i;
struct venus_core_clock *cl;
@@ -429,19 +454,18 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return;
}
- if (device->clocks_enabled == 0) {
- dprintk(VIDC_DBG, "VCODEC clocks are already disabled");
+ if (!device->clocks_enabled) {
+ dprintk(VIDC_DBG, "Clocks are already disabled");
goto already_disabled;
}
- for (i = 0; i < clk_level; i++) {
+ for (i = 0; i <= device->clk_gating_level; i++) {
cl = &device->resources.clock[i];
- clk_disable_unprepare(cl->clk);
+ clk_disable(cl->clk);
}
already_disabled:
device->clocks_enabled = 0;
}
-static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device,
- enum vidc_clocks clk_level)
+static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
{
int i;
struct venus_core_clock *cl;
@@ -450,13 +474,13 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return -EINVAL;
}
- if (device->clocks_enabled == 1) {
- dprintk(VIDC_DBG, "VCODEC clocks are already enabled");
+ if (device->clocks_enabled) {
+ dprintk(VIDC_DBG, "Clocks are already enabled");
goto already_enabled;
}
- for (i = 0; i < clk_level; i++) {
+ for (i = 0; i <= device->clk_gating_level; i++) {
cl = &device->resources.clock[i];
- rc = clk_prepare_enable(cl->clk);
+ rc = clk_enable(cl->clk);
if (rc) {
dprintk(VIDC_ERR, "Failed to enable clocks\n");
goto fail_clk_enable;
@@ -470,7 +494,7 @@
fail_clk_enable:
for (; i >= 0; i--) {
cl = &device->resources.clock[i];
- clk_disable_unprepare(cl->clk);
+ clk_disable(cl->clk);
}
return rc;
}
@@ -480,7 +504,7 @@
{
int num_rows = clock->count;
struct load_freq_table *table = clock->load_freq_tbl;
- unsigned long ret = table[num_rows-1].freq;
+ unsigned long ret = table[0].freq;
int i;
for (i = 0; i < num_rows; i++) {
if (num_mbs_per_sec > table[i].load)
@@ -495,11 +519,11 @@
{
int rc = 0;
struct venus_hfi_device *device = dev;
- device->load = load;
if (!device) {
dprintk(VIDC_ERR, "Invalid args: %p\n", device);
return -EINVAL;
}
+ device->load = load;
rc = clk_set_rate(device->resources.clock[VCODEC_CLK].clk,
venus_hfi_get_clock_rate(&device->resources.clock[VCODEC_CLK],
load));
@@ -525,20 +549,22 @@
dprintk(VIDC_ERR, "cannot write to shared Q's");
goto err_q_write;
}
- result = venus_hfi_clk_gating_off(device, VCODEC_CLK);
+ mutex_lock(&device->clock_lock);
+ result = venus_hfi_clk_gating_off(device);
if (result) {
- dprintk(VIDC_ERR, "VCODEC clock enable failed\n");
+ dprintk(VIDC_ERR, "%s : Clock enable failed\n",
+ __func__);
goto err_q_write;
}
result = venus_hfi_scale_clocks(device, device->load);
if (result) {
- dprintk(VIDC_ERR, "VCODEC clock scaling failed\n");
+ dprintk(VIDC_ERR, "Clock scaling failed\n");
goto err_q_write;
}
if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
if (rx_req_is_set)
venus_hfi_write_register(
- device->hal_data->register_base_addr,
+ device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
result = 0;
@@ -547,6 +573,7 @@
}
err_q_write:
mutex_unlock(&device->write_lock);
+ mutex_unlock(&device->clock_lock);
return result;
}
@@ -568,11 +595,17 @@
goto read_error;
}
q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
-
+ mutex_lock(&device->clock_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ goto read_error;
+ }
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
if (tx_req_is_set)
venus_hfi_write_register(
- device->hal_data->register_base_addr,
+ device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
@@ -582,6 +615,7 @@
}
read_error:
mutex_unlock(&device->read_lock);
+ mutex_unlock(&device->clock_lock);
return rc;
}
@@ -602,11 +636,18 @@
rc = -ENODATA;
goto dbg_error;
}
+ mutex_lock(&device->clock_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ goto dbg_error;
+ }
q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
if (tx_req_is_set)
venus_hfi_write_register(
- device->hal_data->register_base_addr,
+ device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
@@ -616,6 +657,7 @@
}
dbg_error:
mutex_unlock(&device->read_lock);
+ mutex_unlock(&device->clock_lock);
return rc;
}
@@ -820,16 +862,16 @@
iface_q->q_array.align_device_addr;
q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ venus_hfi_write_register(dev,
VIDC_UC_REGION_ADDR,
(u32) dev->iface_q_table.align_device_addr, 0);
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ venus_hfi_write_register(dev,
VIDC_UC_REGION_SIZE, SHARED_QSIZE, 0);
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ venus_hfi_write_register(dev,
VIDC_CPU_CS_SCIACMDARG2,
(u32) dev->iface_q_table.align_device_addr,
dev->iface_q_table.align_virtual_addr);
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ venus_hfi_write_register(dev,
VIDC_CPU_CS_SCIACMDARG1, 0x01,
dev->iface_q_table.align_virtual_addr);
@@ -849,14 +891,14 @@
dev->qdss.mem_data = NULL;
}
if (!IS_ERR_OR_NULL(dev->qdss.align_device_addr))
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ venus_hfi_write_register(dev,
VIDC_MMAP_ADDR,
(u32) dev->qdss.align_device_addr, 0);
vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
vsfr->bufSize = SFR_SIZE;
if (!IS_ERR_OR_NULL(dev->sfr.align_device_addr))
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ venus_hfi_write_register(dev,
VIDC_SFR_ADDR, (u32)dev->sfr.align_device_addr , 0);
return 0;
fail_alloc_queue:
@@ -867,14 +909,14 @@
{
u32 ctrl_status = 0, count = 0, rc = 0;
int max_tries = 100;
- venus_hfi_write_register(device->hal_data->register_base_addr,
+ venus_hfi_write_register(device,
VIDC_WRAPPER_INTR_MASK, 0x8, 0);
- venus_hfi_write_register(device->hal_data->register_base_addr,
+ venus_hfi_write_register(device,
VIDC_CPU_CS_SCIACMDARG3, 1, 0);
while (!ctrl_status && count < max_tries) {
ctrl_status = venus_hfi_read_register(
- device->hal_data->register_base_addr,
+ device,
VIDC_CPU_CS_SCIACMDARG0);
if ((ctrl_status & 0xFE) == 0x4) {
dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
@@ -901,7 +943,7 @@
reg_set = &device->res->reg_set;
for (i = 0; i < reg_set->count; i++) {
- venus_hfi_write_register(device->hal_data->register_base_addr,
+ venus_hfi_write_register(device,
reg_set->reg_tbl[i].reg,
reg_set->reg_tbl[i].value, 0);
}
@@ -979,7 +1021,7 @@
goto err_core_init;
}
enable_irq(dev->hal_data->irq);
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ venus_hfi_write_register(dev,
VIDC_CTRL_INIT, 0x1, 0);
rc = venus_hfi_core_start_cpu(dev);
if (rc) {
@@ -988,7 +1030,7 @@
goto err_core_init;
}
- rc = create_pkt_cmd_sys_init(&pkt, HFI_ARCH_OX_OFFSET);
+ rc = create_pkt_cmd_sys_init(&pkt, HFI_VIDEO_ARCH_OX);
if (rc) {
dprintk(VIDC_ERR, "Failed to create sys init pkt");
goto err_core_init;
@@ -1006,6 +1048,7 @@
static int venus_hfi_core_release(void *device)
{
struct venus_hfi_device *dev;
+ int rc = 0;
if (device) {
dev = device;
} else {
@@ -1013,13 +1056,22 @@
return -ENODEV;
}
if (dev->hal_client) {
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ mutex_lock(&dev->clock_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&dev->clock_lock);
+ return -EIO;
+ }
+ venus_hfi_write_register(dev,
VIDC_CPU_CS_SCIACMDARG3, 0, 0);
if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
disable_irq_nosync(dev->hal_data->irq);
dev->intr_status = 0;
venus_hfi_interface_queues_release(dev);
}
+ mutex_unlock(&dev->clock_lock);
dprintk(VIDC_INFO, "HAL exited\n");
return 0;
}
@@ -1053,16 +1105,26 @@
static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
{
u32 intr_status = 0;
+ int rc = 0;
if (!device->callback)
return;
-
+ mutex_lock(&device->clock_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&device->clock_lock);
+ return;
+ }
intr_status = venus_hfi_read_register(
- device->hal_data->register_base_addr,
+ device,
VIDC_WRAPPER_INTR_STATUS);
if ((intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK) ||
- (intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) {
+ (intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK) ||
+ (intr_status &
+ VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)) {
device->intr_status |= intr_status;
dprintk(VIDC_DBG, "INTERRUPT for device: 0x%x: "
"times: %d interrupt_status: %d",
@@ -1072,10 +1134,11 @@
"times: %d interrupt_status: %d",
(u32) device, ++device->spur_count, intr_status);
}
- venus_hfi_write_register(device->hal_data->register_base_addr,
+ venus_hfi_write_register(device,
VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
- venus_hfi_write_register(device->hal_data->register_base_addr,
+ venus_hfi_write_register(device,
VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
+ mutex_unlock(&device->clock_lock);
dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
}
@@ -1796,14 +1859,16 @@
return -ENODEV;
}
mutex_lock(&device->write_lock);
+ mutex_lock(&device->clock_lock);
rc = venus_hfi_is_cmd_pending(device);
ctrl_status = venus_hfi_read_register(
- device->hal_data->register_base_addr,
+ device,
VIDC_CPU_CS_SCIACMDARG0);
if (((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
!= 0) && !rc)
- venus_hfi_clk_gating_on(device, VCODEC_CLK);
+ venus_hfi_clk_gating_on(device);
mutex_unlock(&device->write_lock);
+ mutex_unlock(&device->clock_lock);
return rc;
}
@@ -1824,15 +1889,14 @@
rc = hfi_process_msg_packet(device->callback,
device->device_id,
(struct vidc_hal_msg_pkt_hdr *) packet);
- if (rc == HFI_MSG_SYS_IDLE)
- rc = venus_hfi_try_clk_gating(device);
-
}
while (!venus_hfi_iface_dbgq_read(device, packet)) {
struct hfi_msg_sys_debug_packet *pkt =
(struct hfi_msg_sys_debug_packet *) packet;
dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
}
+ if (rc == HFI_MSG_SYS_IDLE)
+ rc = venus_hfi_try_clk_gating(device);
} else {
dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
}
@@ -2013,12 +2077,23 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return;
}
-
+ if (device->clocks_enabled) {
+ for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+ cl = &device->resources.clock[i];
+ clk_disable(cl->clk);
+ }
+ } else {
+ for (i = device->clk_gating_level + 1;
+ i < VCODEC_MAX_CLKS; i++) {
+ cl = &device->resources.clock[i];
+ clk_disable(cl->clk);
+ }
+ }
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
continue;
cl = &device->resources.clock[i];
- clk_disable_unprepare(cl->clk);
+ clk_unprepare(cl->clk);
}
device->clocks_enabled = 0;
}
@@ -2309,6 +2384,7 @@
struct vidc_resource_hdr rhdr;
struct venus_hfi_device *device = dev;
int rc = 0;
+
if (!device) {
dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
__func__, device);
@@ -2321,7 +2397,6 @@
rc = -EINVAL;
goto ocmem_unset_failed;
}
-
rhdr.resource_id = VIDC_RESOURCE_OCMEM;
rhdr.resource_handle = (u32) &device->resources.ocmem;
rc = venus_hfi_core_release_resource(device, &rhdr);
@@ -2623,7 +2698,8 @@
__func__, device);
return -EINVAL;
}
-
+ mutex_init(&device->clock_lock);
+ device->clk_gating_level = VCODEC_CLK;
rc = venus_hfi_iommu_attach(device);
if (rc) {
dprintk(VIDC_ERR, "Failed to attach iommu");
@@ -2746,25 +2822,25 @@
if (rc)
goto err_init_regs;
- INIT_LIST_HEAD(&hal_ctxt.dev_head);
- INIT_LIST_HEAD(&hdevice->list);
- list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
- hal_ctxt.dev_count++;
hdevice->device_id = device_id;
-
hdevice->callback = callback;
hdevice->vidc_workq = create_singlethread_workqueue(
- "msm_vidc_workerq");
+ "msm_vidc_workerq_venus");
if (!hdevice->vidc_workq) {
dprintk(VIDC_ERR, ": create workq failed\n");
goto error_createq;
}
+ if (hal_ctxt.dev_count == 0)
+ INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+ INIT_LIST_HEAD(&hdevice->list);
+ list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
+ hal_ctxt.dev_count++;
+
return (void *) hdevice;
error_createq:
- hal_ctxt.dev_count--;
- list_del(&hal_ctxt.dev_head);
err_init_regs:
kfree(hdevice);
err_alloc:
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 7a96ff4..197c754 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -176,8 +176,10 @@
u32 device_id;
u32 load;
u32 clocks_enabled;
+ enum vidc_clocks clk_gating_level;
struct mutex read_lock;
struct mutex write_lock;
+ struct mutex clock_lock;
msm_vidc_callback callback;
struct vidc_mem_addr iface_q_table;
struct vidc_mem_addr qdss;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.c b/drivers/media/platform/msm/vidc/vidc_hfi.c
index e8131dd..46293a6 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.c
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.c
@@ -16,8 +16,6 @@
#include "venus_hfi.h"
#include "q6_hfi.h"
-struct hal_device_data hal_ctxt;
-
void *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, u32 device_id,
struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
@@ -37,7 +35,7 @@
break;
case VIDC_HFI_Q6:
- rc = q6_hfi_initialize(hdev, device_id, callback);
+ rc = q6_hfi_initialize(hdev, device_id, res, callback);
break;
default:
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 8b3e7cb..075b391 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -830,8 +830,6 @@
void *cookie;
};
-extern struct hal_device_data hal_ctxt;
-
u32 hfi_process_msg_packet(msm_vidc_callback callback,
u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr);
#endif
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 95e644b..e20348d 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -190,6 +190,7 @@
HAL_VIDEO_CODEC_VP6 = 0x00000400,
HAL_VIDEO_CODEC_VP7 = 0x00000800,
HAL_VIDEO_CODEC_VP8 = 0x00001000,
+ HAL_VIDEO_CODEC_HEVC = 0x00010000,
HAL_UNUSED_CODEC = 0x10000000,
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 01c5e0b..baf7bc4 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -76,9 +76,10 @@
#define HFI_VIDEO_CODEC_MPEG4 0x00000020
#define HFI_VIDEO_CODEC_DIVX_311 0x00000040
#define HFI_VIDEO_CODEC_DIVX 0x00000080
-#define HFI_VIDEO_CODEC_VC1 0x00000100
+#define HFI_VIDEO_CODEC_VC1 0x00000100
#define HFI_VIDEO_CODEC_SPARK 0x00000200
-#define HFI_VIDEO_CODEC_VP8 0x00001000
+#define HFI_VIDEO_CODEC_VP8 0x00001000
+#define HFI_VIDEO_CODEC_HEVC 0x00010000
#define HFI_H264_PROFILE_BASELINE 0x00000001
#define HFI_H264_PROFILE_MAIN 0x00000002
diff --git a/drivers/media/platform/msm/wfd/enc-subdev.h b/drivers/media/platform/msm/wfd/enc-subdev.h
index 8bfb884..a1469cd 100644
--- a/drivers/media/platform/msm/wfd/enc-subdev.h
+++ b/drivers/media/platform/msm/wfd/enc-subdev.h
@@ -25,6 +25,10 @@
VENC_MODE_VFR,
};
+enum venc_event {
+ VENC_EVENT_HARDWARE_ERROR,
+};
+
struct mem_region {
struct list_head list;
u8 *kvaddr;
@@ -64,6 +68,7 @@
struct vb2_buffer *buf);
void (*ip_buffer_done)(void *cookie, u32 status,
struct mem_region *mregion);
+ void (*on_event)(void *cookie, enum venc_event e);
};
static inline bool mem_region_equals(struct mem_region *a,
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 40362f0..9ebf763 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -48,6 +48,12 @@
bool secure;
};
+static const int subscribed_events[] = {
+ V4L2_EVENT_MSM_VIDC_CLOSE_DONE,
+ V4L2_EVENT_MSM_VIDC_FLUSH_DONE,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR,
+};
+
int venc_load_fw(struct v4l2_subdev *sd)
{
/*No need to explicitly load the fw */
@@ -134,13 +140,21 @@
bool bail_out = false;
msm_vidc_dqevent(inst->vidc_context, &event);
- if (event.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
+
+ switch (event.type) {
+ case V4L2_EVENT_MSM_VIDC_CLOSE_DONE:
WFD_MSG_DBG("enc callback thread shutting " \
"down normally\n");
bail_out = true;
- } else {
- WFD_MSG_ERR("Got unknown event %d, ignoring\n",
- event.id);
+ break;
+ case V4L2_EVENT_MSM_VIDC_SYS_ERROR:
+ inst->vmops.on_event(inst->vmops.cbdata,
+ VENC_EVENT_HARDWARE_ERROR);
+ bail_out = true;
+ break;
+ default:
+ WFD_MSG_INFO("Got unknown event %d, ignoring\n",
+ event.type);
}
complete_all(&inst->cmd_complete);
@@ -251,11 +265,43 @@
return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
}
+static int subscribe_events(struct venc_inst *inst)
+{
+ struct v4l2_event_subscription event = {0};
+ int c = 0, rc = 0;
+
+ for (c = 0; c < ARRAY_SIZE(subscribed_events); c++) {
+ event.type = subscribed_events[c];
+ rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ WFD_MSG_ERR("Failed to subscribe to event 0x%x\n",
+ subscribed_events[c]);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void unsubscribe_events(struct venc_inst *inst)
+{
+ struct v4l2_event_subscription event = {0};
+ int c = 0, rc = 0;
+ for (c = 0; c < ARRAY_SIZE(subscribed_events); c++) {
+ event.type = subscribed_events[c];
+ rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ /* Just log and ignore failiures */
+ WFD_MSG_WARN("Failed to unsubscribe to event 0x%x\n",
+ subscribed_events[c]);
+ }
+ }
+}
+
static long venc_open(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
struct venc_msg_ops *vmops = arg;
- struct v4l2_event_subscription event = {0};
int rc = 0;
if (!vmops) {
@@ -289,17 +335,9 @@
goto vidc_open_fail;
}
- event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ rc = subscribe_events(inst);
if (rc) {
- WFD_MSG_ERR("Failed to subscribe to CLOSE_DONE event\n");
- goto vidc_subscribe_fail;
- }
-
- event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
- if (rc) {
- WFD_MSG_ERR("Failed to subscribe to FLUSH_DONE event\n");
+ WFD_MSG_ERR("Failed to subscribe to events\n");
goto vidc_subscribe_fail;
}
@@ -317,11 +355,7 @@
vmops->cookie = inst;
return 0;
vidc_kthread_create_fail:
- event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- msm_vidc_unsubscribe_event(inst->vidc_context, &event);
-
- event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ unsubscribe_events(inst);
vidc_subscribe_fail:
msm_vidc_close(inst->vidc_context);
vidc_open_fail:
@@ -333,7 +367,6 @@
static long venc_close(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
- struct v4l2_event_subscription event = {0};
struct v4l2_encoder_cmd enc_cmd = {0};
int rc = 0;
@@ -352,15 +385,7 @@
if (inst->callback_thread && inst->callback_thread_running)
kthread_stop(inst->callback_thread);
- event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
- if (rc)
- WFD_MSG_WARN("Failed to unsubscribe close event\n");
-
- event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
- if (rc)
- WFD_MSG_WARN("Failed to unsubscribe flush event\n");
+ unsubscribe_events(inst);
rc = msm_vidc_close(inst->vidc_context);
if (rc)
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 102b9b9..cd54449 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -25,8 +25,9 @@
#include <mach/board.h>
#include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-msm-mem.h>
@@ -42,6 +43,7 @@
#define DEFAULT_WFD_WIDTH 1280
#define DEFAULT_WFD_HEIGHT 720
#define VENC_INPUT_BUFFERS 4
+#define MAX_EVENTS 16
struct wfd_device {
struct mutex dev_lock;
@@ -92,12 +94,18 @@
struct list_head input_mem_list;
struct wfd_stats stats;
struct completion stop_mdp_thread;
+ struct v4l2_fh event_handler;
};
struct wfd_vid_buffer {
struct vb2_buffer vidbuf;
};
+static inline struct wfd_inst *file_to_inst(struct file *filp)
+{
+ return container_of(filp->private_data, struct wfd_inst, event_handler);
+}
+
static int wfd_vidbuf_queue_setup(struct vb2_queue *q,
const struct v4l2_format *fmt,
unsigned int *num_buffers,
@@ -105,7 +113,7 @@
unsigned int sizes[], void *alloc_ctxs[])
{
struct file *priv_data = (struct file *)(q->drv_priv);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
unsigned long flags;
int i;
@@ -124,10 +132,11 @@
return 0;
}
-void wfd_vidbuf_wait_prepare(struct vb2_queue *q)
+static void wfd_vidbuf_wait_prepare(struct vb2_queue *q)
{
}
-void wfd_vidbuf_wait_finish(struct vb2_queue *q)
+
+static void wfd_vidbuf_wait_finish(struct vb2_queue *q)
{
}
@@ -236,7 +245,8 @@
ION_IOC_INV_CACHES);
}
-int wfd_allocate_input_buffers(struct wfd_device *wfd_dev,
+
+static int wfd_allocate_input_buffers(struct wfd_device *wfd_dev,
struct wfd_inst *inst)
{
int i;
@@ -389,7 +399,8 @@
recon_alloc_fail:
return rc;
}
-void wfd_free_input_buffers(struct wfd_device *wfd_dev,
+
+static void wfd_free_input_buffers(struct wfd_device *wfd_dev,
struct wfd_inst *inst)
{
struct list_head *ptr, *next;
@@ -450,7 +461,7 @@
WFD_MSG_ERR("Failed to free recon buffers\n");
}
-struct mem_info *wfd_get_mem_info(struct wfd_inst *inst,
+static struct mem_info *wfd_get_mem_info(struct wfd_inst *inst,
unsigned long userptr)
{
struct mem_info_entry *temp;
@@ -468,7 +479,8 @@
spin_unlock_irqrestore(&inst->inst_lock, flags);
return ret;
}
-void wfd_put_mem_info(struct wfd_inst *inst,
+
+static void wfd_put_mem_info(struct wfd_inst *inst,
struct mem_info *minfo)
{
struct list_head *ptr, *next;
@@ -497,12 +509,13 @@
}
wfd_put_mem_info(inst, minfo);
}
-int wfd_vidbuf_buf_init(struct vb2_buffer *vb)
+
+static int wfd_vidbuf_buf_init(struct vb2_buffer *vb)
{
int rc = 0;
struct vb2_queue *q = vb->vb2_queue;
struct file *priv_data = (struct file *)(q->drv_priv);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
struct mem_info *minfo = vb2_plane_cookie(vb, 0);
@@ -532,24 +545,24 @@
return rc;
}
-int wfd_vidbuf_buf_prepare(struct vb2_buffer *vb)
+static int wfd_vidbuf_buf_prepare(struct vb2_buffer *vb)
{
return 0;
}
-int wfd_vidbuf_buf_finish(struct vb2_buffer *vb)
+static int wfd_vidbuf_buf_finish(struct vb2_buffer *vb)
{
return 0;
}
-void wfd_vidbuf_buf_cleanup(struct vb2_buffer *vb)
+static void wfd_vidbuf_buf_cleanup(struct vb2_buffer *vb)
{
int rc = 0;
struct vb2_queue *q = vb->vb2_queue;
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
struct mem_info *minfo = vb2_plane_cookie(vb, 0);
struct mem_region mregion;
@@ -574,7 +587,7 @@
{
int rc = 0, no_sig_wait = 0;
struct file *filp = (struct file *)data;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
struct mdp_buf_info obuf_mdp = {inst->mdp_inst, 0, 0, 0};
@@ -633,12 +646,12 @@
return rc;
}
-int wfd_vidbuf_start_streaming(struct vb2_queue *q, unsigned int count)
+static int wfd_vidbuf_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
int rc = 0;
WFD_MSG_ERR("Stream on called\n");
@@ -657,6 +670,7 @@
WFD_MSG_ERR("Failed to start vsg\n");
goto subdev_start_fail;
}
+
init_completion(&inst->stop_mdp_thread);
inst->mdp_task = kthread_run(mdp_output_thread, priv_data,
"mdp_output_thread");
@@ -673,12 +687,12 @@
return rc;
}
-int wfd_vidbuf_stop_streaming(struct vb2_queue *q)
+static int wfd_vidbuf_stop_streaming(struct vb2_queue *q)
{
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
int rc = 0;
WFD_MSG_DBG("mdp stop\n");
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
@@ -707,14 +721,14 @@
return rc;
}
-void wfd_vidbuf_buf_queue(struct vb2_buffer *vb)
+static void wfd_vidbuf_buf_queue(struct vb2_buffer *vb)
{
int rc = 0;
struct vb2_queue *q = vb->vb2_queue;
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
struct mem_region mregion;
struct mem_info *minfo = vb2_plane_cookie(vb, 0);
mregion.fd = minfo->fd;
@@ -787,7 +801,7 @@
static int wfdioc_g_fmt(struct file *filp, void *fh,
struct v4l2_format *fmt)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
unsigned long flags;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
@@ -811,7 +825,7 @@
struct v4l2_format *fmt)
{
int rc = 0;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
struct mdp_prop prop;
unsigned long flags;
@@ -862,7 +876,7 @@
static int wfdioc_reqbufs(struct file *filp, void *fh,
struct v4l2_requestbuffers *b)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
unsigned long flags;
int rc = 0;
@@ -918,7 +932,7 @@
struct v4l2_buffer *b)
{
int rc = 0;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
if (!inst || !b ||
(b->index < 0 || b->index >= inst->buf_count)) {
WFD_MSG_ERR("Invalid input parameters to QBUF IOCTL\n");
@@ -943,7 +957,7 @@
enum v4l2_buf_type i)
{
int rc = 0;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream on for buffer type = %d is not "
@@ -969,7 +983,7 @@
static int wfdioc_streamoff(struct file *filp, void *fh,
enum v4l2_buf_type i)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -993,7 +1007,7 @@
static int wfdioc_dqbuf(struct file *filp, void *fh,
struct v4l2_buffer *b)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
int rc;
WFD_MSG_DBG("Waiting to dequeue buffer\n");
@@ -1022,7 +1036,7 @@
{
int rc = 0;
struct wfd_device *wfd_dev = video_drvdata(filp);
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
switch (a->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
@@ -1057,7 +1071,7 @@
{
int rc = 0;
struct wfd_device *wfd_dev = video_drvdata(filp);
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
int64_t frame_interval = 0,
max_frame_interval = 0; /* both in nsecs*/
struct v4l2_qcom_frameskip frameskip, *usr_frameskip;
@@ -1112,7 +1126,7 @@
{
int rc = 0;
struct wfd_device *wfd_dev = video_drvdata(filp);
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct v4l2_qcom_frameskip frameskip;
int64_t frame_interval, max_frame_interval;
void *extendedmode = NULL;
@@ -1200,6 +1214,22 @@
return rc;
}
+static int wfdioc_subscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ struct wfd_inst *inst = container_of(fh, struct wfd_inst,
+ event_handler);
+ return v4l2_event_subscribe(&inst->event_handler, sub, MAX_EVENTS);
+}
+
+static int wfdioc_unsubscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ struct wfd_inst *inst = container_of(fh, struct wfd_inst,
+ event_handler);
+ return v4l2_event_unsubscribe(&inst->event_handler, sub);
+}
+
static const struct v4l2_ioctl_ops g_wfd_ioctl_ops = {
.vidioc_querycap = wfdioc_querycap,
.vidioc_s_fmt_vid_cap = wfdioc_s_fmt,
@@ -1213,13 +1243,16 @@
.vidioc_s_ctrl = wfdioc_s_ctrl,
.vidioc_g_parm = wfdioc_g_parm,
.vidioc_s_parm = wfdioc_s_parm,
+ .vidioc_subscribe_event = wfdioc_subscribe_event,
+ .vidioc_unsubscribe_event = wfdioc_unsubscribe_event,
+
};
static int wfd_set_default_properties(struct file *filp)
{
unsigned long flags;
struct v4l2_format fmt;
struct v4l2_control ctrl;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
if (!inst) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
@@ -1249,7 +1282,7 @@
struct mem_region *mregion)
{
struct file *filp = cookie;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct vsg_buf_info buf;
struct mdp_buf_info mdp_buf = {0};
struct wfd_device *wfd_dev =
@@ -1273,10 +1306,33 @@
}
+static void venc_on_event(void *cookie, enum venc_event e)
+{
+ struct file *filp = cookie;
+ struct wfd_inst *inst = file_to_inst(filp);
+ struct v4l2_event event;
+ int type = 0;
+
+ switch (e) {
+ case VENC_EVENT_HARDWARE_ERROR:
+ type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+ break;
+ default:
+ /* Whatever~~ */
+ break;
+ }
+
+ if (type) {
+ event.id = 0;
+ event.type = type;
+ v4l2_event_queue_fh(&inst->event_handler, &event);
+ }
+}
+
static int vsg_release_input_frame(void *cookie, struct vsg_buf_info *buf)
{
struct file *filp = cookie;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
int rc = 0;
@@ -1296,7 +1352,7 @@
static int vsg_encode_frame(void *cookie, struct vsg_buf_info *buf)
{
struct file *filp = cookie;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
struct venc_buf_info venc_buf;
@@ -1389,11 +1445,15 @@
rc = -ENOMEM;
goto err_mdp_open;
}
- filp->private_data = inst;
+ filp->private_data = &inst->event_handler;
spin_lock_init(&inst->inst_lock);
INIT_LIST_HEAD(&inst->input_mem_list);
INIT_LIST_HEAD(&inst->minfo_list);
+ /* Set up userspace event handlers */
+ v4l2_fh_init(&inst->event_handler, wfd_dev->pvdev);
+ v4l2_fh_add(&inst->event_handler);
+
wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
mdp_mops.secure = wfd_dev->secure;
@@ -1411,8 +1471,10 @@
WFD_MSG_ERR("Failed to load video encoder firmware: %d\n", rc);
goto err_venc;
}
+
enc_mops.op_buffer_done = venc_op_buffer_done;
enc_mops.ip_buffer_done = venc_ip_buffer_done;
+ enc_mops.on_event = venc_on_event;
enc_mops.cbdata = filp;
enc_mops.secure = wfd_dev->secure;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
@@ -1444,9 +1506,12 @@
v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_CLOSE, (void *)inst->mdp_inst);
err_mdp_open:
+ v4l2_fh_del(&inst->event_handler);
+
mutex_lock(&wfd_dev->dev_lock);
wfd_dev->in_use = false;
mutex_unlock(&wfd_dev->dev_lock);
+
kfree(inst);
err_dev_busy:
return rc;
@@ -1459,7 +1524,7 @@
int rc = 0;
wfd_dev = video_drvdata(filp);
WFD_MSG_DBG("wfd_close: E\n");
- inst = filp->private_data;
+ inst = file_to_inst(filp);
if (inst) {
wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
vb2_queue_release(&inst->vid_bufq);
@@ -1484,6 +1549,8 @@
kfree(inst);
}
+ v4l2_fh_del(&inst->event_handler);
+
mutex_lock(&wfd_dev->dev_lock);
wfd_dev->in_use = false;
mutex_unlock(&wfd_dev->dev_lock);
@@ -1491,12 +1558,28 @@
WFD_MSG_DBG("wfd_close: X\n");
return 0;
}
+
+unsigned int wfd_poll(struct file *filp, struct poll_table_struct *pt)
+{
+ struct wfd_inst *inst = file_to_inst(filp);
+ unsigned int flags = 0;
+
+ poll_wait(filp, &inst->event_handler.wait, pt);
+
+ if (v4l2_event_pending(&inst->event_handler))
+ flags |= POLLPRI;
+
+ return flags;
+}
+
static const struct v4l2_file_operations g_wfd_fops = {
.owner = THIS_MODULE,
.open = wfd_open,
.release = wfd_close,
- .ioctl = video_ioctl2
+ .ioctl = video_ioctl2,
+ .poll = wfd_poll,
};
+
void release_video_device(struct video_device *pvdev)
{
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index fce1547..09d942a 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -182,6 +182,41 @@
return rc;
}
+/**
+ * pm8xxx_read_register - Read a PMIC register
+ * @addr: PMIC register address
+ * @value: Output parameter which gets the value of the register read.
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_read_register(u16 addr, u8 *value)
+{
+ struct pm8xxx_misc_chip *chip;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
+
+ /* Loop over all attached PMICs and call specific functions for them. */
+ list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
+ switch (chip->version) {
+ case PM8XXX_VERSION_8921:
+ rc = pm8xxx_readb(chip->dev->parent, addr, value);
+ if (rc) {
+ pr_err("pm8xxx_readb(0x%03X) failed, rc=%d\n",
+ addr, rc);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_read_register);
+
/*
* Set an SMPS regulator to be disabled in its CTRL register, but enabled
* in the master enable register. Also set it's pull down enable bit.
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 9e22ffb..7d76b43 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -57,7 +57,6 @@
#define QSEOS_CHECK_VERSION_CMD 0x00001803
#define QSEE_CE_CLK_100MHZ 100000000
-#define QSEE_CE_CLK_50MHZ 50000000
#define QSEECOM_MAX_SG_ENTRY 512
@@ -78,10 +77,6 @@
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
-static int qsee_bw_count;
-static int qsee_sfpb_bw_count;
-static uint32_t qsee_perf_client;
-
struct qseecom_registered_listener_list {
struct list_head list;
struct qseecom_register_listener_req svc;
@@ -106,6 +101,13 @@
struct qseecom_handle *handle;
};
+struct qseecom_clk {
+ struct clk *ce_core_clk;
+ struct clk *ce_clk;
+ struct clk *ce_core_src_clk;
+ struct clk *ce_bus_clk;
+};
+
struct qseecom_control {
struct ion_client *ion_clnt; /* Ion client */
struct list_head registered_listener_list_head;
@@ -124,6 +126,12 @@
uint32_t qsee_version;
struct device *pdev;
bool commonlib_loaded;
+
+ int qsee_bw_count;
+ int qsee_sfpb_bw_count;
+
+ uint32_t qsee_perf_client;
+ struct qseecom_clk qsee;
};
struct qseecom_client_handle {
@@ -155,11 +163,6 @@
atomic_t ioctl_count;
};
-struct clk *ce_core_clk;
-struct clk *ce_clk;
-struct clk *ce_core_src_clk;
-struct clk *ce_bus_clk;
-
struct qseecom_sg_entry {
uint32_t phys_addr;
uint32_t len;
@@ -355,12 +358,14 @@
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
+ ret, data->listener.id);
return ret;
}
if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("SB deregistartion: result=%d\n", resp.result);
+ pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
+ resp.result, data->listener.id);
return -EPERM;
}
} else {
@@ -538,12 +543,13 @@
sizeof(send_data_rsp), resp,
sizeof(*resp));
if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ pr_err("scm_call() failed with err: %d (app_id = %d)\n",
+ ret, data->client.app_id);
return ret;
}
if (resp->result == QSEOS_RESULT_FAILURE) {
- pr_err("Response result %d not supported\n",
- resp->result);
+ pr_err("Response result %d FAIL (app_id = %d)\n",
+ resp->result, data->client.app_id);
return -EINVAL;
}
}
@@ -980,7 +986,8 @@
sizeof(send_data_req),
&resp, sizeof(resp));
if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ pr_err("scm_call() failed with err: %d (app_id = %d)\n",
+ ret, data->client.app_id);
return ret;
}
@@ -1161,13 +1168,15 @@
if (wait_event_freezable(this_lstnr->rcv_req_wq,
__qseecom_listener_has_rcvd_req(data,
this_lstnr))) {
- pr_warning("Interrupted: exiting wait_rcv_req loop\n");
+ pr_warning("Interrupted: exiting Listener Service = %d\n",
+ (uint32_t)data->listener.id);
/* woken up for different reason */
return -ERESTARTSYS;
}
if (data->abort) {
- pr_err("Aborting driver!\n");
+ pr_err("Aborting Listener Service = %d\n",
+ (uint32_t)data->listener.id);
return -ENODEV;
}
this_lstnr->rcv_req_flag = 0;
@@ -1387,6 +1396,14 @@
}
/* Populate the remaining parameters */
load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
+ /* Vote for the SFPB clock */
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret) {
+ pr_err("Unable to vote for SFPB clock: ret = %d", ret);
+ kzfree(img_data);
+ return -EIO;
+ }
+
/* SCM_CALL to load the image */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
sizeof(struct qseecom_load_lib_image_ireq),
@@ -1417,6 +1434,7 @@
}
}
kzfree(img_data);
+ qsee_disable_clock_vote(data, CLK_SFPB);
return ret;
}
@@ -1517,7 +1535,7 @@
}
if (ret) {
- pr_err("Failed to loadd commonlib image\n");
+ pr_err("Failed to load commonlib image\n");
kfree(data);
kfree(*handle);
*handle = NULL;
@@ -1746,64 +1764,123 @@
return 0;
}
+static int __qseecom_enable_clk(void)
+{
+ int rc = 0;
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
+ /* Enable CE core clk */
+ rc = clk_prepare_enable(qclk->ce_core_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE core clk\n");
+ goto err;
+ }
+ /* Enable CE clk */
+ rc = clk_prepare_enable(qclk->ce_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ goto ce_clk_err;
+ }
+ /* Enable AXI clk */
+ rc = clk_prepare_enable(qclk->ce_bus_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE bus clk\n");
+ goto ce_bus_clk_err;
+ }
+ return 0;
+
+ce_bus_clk_err:
+ clk_disable_unprepare(qclk->ce_clk);
+ce_clk_err:
+ clk_disable_unprepare(qclk->ce_core_clk);
+err:
+ return -EIO;
+}
+
+static void __qseecom_disable_clk(void)
+{
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
+ if (qclk->ce_clk != NULL)
+ clk_disable_unprepare(qclk->ce_clk);
+ if (qclk->ce_core_clk != NULL)
+ clk_disable_unprepare(qclk->ce_core_clk);
+ if (qclk->ce_bus_clk != NULL)
+ clk_disable_unprepare(qclk->ce_bus_clk);
+}
+
static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
int32_t clk_type)
{
int ret = 0;
+ struct qseecom_clk *qclk;
- if (!qsee_perf_client)
+ qclk = &qseecom.qsee;
+ if (!qseecom.qsee_perf_client)
return ret;
switch (clk_type) {
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
- if (!qsee_bw_count) {
- if (qsee_sfpb_bw_count > 0)
+ if (!qseecom.qsee_bw_count) {
+ if (qseecom.qsee_sfpb_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 3);
+ qseecom.qsee_perf_client, 3);
else {
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_100MHZ);
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 1);
+ if (qclk->ce_core_src_clk != NULL)
+ ret = __qseecom_enable_clk();
+ if (!ret) {
+ ret =
+ msm_bus_scale_client_update_request(
+ qseecom.qsee_perf_client, 1);
+ if ((ret) &&
+ (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
+ }
}
if (ret)
pr_err("DFAB Bandwidth req failed (%d)\n",
ret);
else {
- qsee_bw_count++;
+ qseecom.qsee_bw_count++;
data->client.perf_enabled = true;
}
} else {
- qsee_bw_count++;
+ qseecom.qsee_bw_count++;
data->client.perf_enabled = true;
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
mutex_lock(&qsee_bw_mutex);
- if (!qsee_sfpb_bw_count) {
- if (qsee_bw_count > 0)
+ if (!qseecom.qsee_sfpb_bw_count) {
+ if (qseecom.qsee_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 3);
+ qseecom.qsee_perf_client, 3);
else {
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_100MHZ);
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 2);
+ if (qclk->ce_core_src_clk != NULL)
+ ret = __qseecom_enable_clk();
+ if (!ret) {
+ ret =
+ msm_bus_scale_client_update_request(
+ qseecom.qsee_perf_client, 2);
+ if ((ret) &&
+ (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
+ }
}
if (ret)
pr_err("SFPB Bandwidth req failed (%d)\n",
ret);
else {
- qsee_sfpb_bw_count++;
+ qseecom.qsee_sfpb_bw_count++;
data->client.fast_load_enabled = true;
}
} else {
- qsee_sfpb_bw_count++;
+ qseecom.qsee_sfpb_bw_count++;
data->client.fast_load_enabled = true;
}
mutex_unlock(&qsee_bw_mutex);
@@ -1819,70 +1896,70 @@
int32_t clk_type)
{
int32_t ret = 0;
+ struct qseecom_clk *qclk;
- if (!qsee_perf_client)
+ qclk = &qseecom.qsee;
+ if (!qseecom.qsee_perf_client)
return;
switch (clk_type) {
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
- if (qsee_bw_count == 0) {
+ if (qseecom.qsee_bw_count == 0) {
pr_err("Client error.Extra call to disable DFAB clk\n");
mutex_unlock(&qsee_bw_mutex);
return;
}
- if (qsee_bw_count == 1) {
- if (qsee_sfpb_bw_count > 0)
+ if (qseecom.qsee_bw_count == 1) {
+ if (qseecom.qsee_sfpb_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 2);
+ qseecom.qsee_perf_client, 2);
else {
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 0);
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_50MHZ);
+ qseecom.qsee_perf_client, 0);
+ if ((!ret) && (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
}
if (ret)
pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
else {
- qsee_bw_count--;
+ qseecom.qsee_bw_count--;
data->client.perf_enabled = false;
}
} else {
- qsee_bw_count--;
+ qseecom.qsee_bw_count--;
data->client.perf_enabled = false;
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
mutex_lock(&qsee_bw_mutex);
- if (qsee_sfpb_bw_count == 0) {
+ if (qseecom.qsee_sfpb_bw_count == 0) {
pr_err("Client error.Extra call to disable SFPB clk\n");
mutex_unlock(&qsee_bw_mutex);
return;
}
- if (qsee_sfpb_bw_count == 1) {
- if (qsee_bw_count > 0)
+ if (qseecom.qsee_sfpb_bw_count == 1) {
+ if (qseecom.qsee_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 1);
+ qseecom.qsee_perf_client, 1);
else {
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 0);
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_50MHZ);
+ qseecom.qsee_perf_client, 0);
+ if ((!ret) && (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
}
if (ret)
pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
else {
- qsee_sfpb_bw_count--;
+ qseecom.qsee_sfpb_bw_count--;
data->client.fast_load_enabled = false;
}
} else {
- qsee_sfpb_bw_count--;
+ qseecom.qsee_sfpb_bw_count--;
data->client.fast_load_enabled = false;
}
mutex_unlock(&qsee_bw_mutex);
@@ -1941,6 +2018,13 @@
ret = -EFAULT;
goto qseecom_load_external_elf_set_cpu_err;
}
+ /* Vote for the SFPB clock */
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret) {
+ pr_err("Unable to vote for SFPB clock: ret = %d", ret);
+ ret = -EIO;
+ goto qseecom_load_external_elf_set_cpu_err;
+ }
/* SCM_CALL to load the external elf */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
@@ -1980,7 +2064,7 @@
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
-
+ qsee_disable_clock_vote(data, CLK_SFPB);
return ret;
}
@@ -2350,97 +2434,61 @@
.release = qseecom_release
};
-static int __qseecom_enable_clk(void)
-{
- int rc = 0;
-
- /* Enable CE core clk */
- rc = clk_prepare_enable(ce_core_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE core clk\n");
- return -EIO;
- } else {
- /* Enable CE clk */
- rc = clk_prepare_enable(ce_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- clk_disable_unprepare(ce_core_clk);
- return -EIO;
- } else {
- /* Enable AXI clk */
- rc = clk_prepare_enable(ce_bus_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- clk_disable_unprepare(ce_core_clk);
- clk_disable_unprepare(ce_clk);
- return -EIO;
- }
- }
- }
- return rc;
-}
-
-static void __qseecom_disable_clk(void)
-{
- if (ce_clk != NULL)
- clk_disable_unprepare(ce_clk);
- if (ce_core_clk != NULL)
- clk_disable_unprepare(ce_core_clk);
- if (ce_bus_clk != NULL)
- clk_disable_unprepare(ce_bus_clk);
-}
-
static int __qseecom_init_clk(void)
{
int rc = 0;
struct device *pdev;
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
pdev = qseecom.pdev;
/* Get CE3 src core clk. */
- ce_core_src_clk = clk_get(pdev, "core_clk_src");
- if (!IS_ERR(ce_core_src_clk)) {
- /* Set the core src clk @50Mhz */
- rc = clk_set_rate(ce_core_src_clk, QSEE_CE_CLK_50MHZ);
+
+ qclk->ce_core_src_clk = clk_get(pdev, "core_clk_src");
+ if (!IS_ERR(qclk->ce_core_src_clk)) {
+ /* Set the core src clk @100Mhz */
+ rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
if (rc) {
- clk_put(ce_core_src_clk);
+ clk_put(qclk->ce_core_src_clk);
pr_err("Unable to set the core src clk @100Mhz.\n");
return -EIO;
}
} else {
pr_warn("Unable to get CE core src clk, set to NULL\n");
- ce_core_src_clk = NULL;
+ qclk->ce_core_src_clk = NULL;
}
/* Get CE core clk */
- ce_core_clk = clk_get(pdev, "core_clk");
- if (IS_ERR(ce_core_clk)) {
- rc = PTR_ERR(ce_core_clk);
+ qclk->ce_core_clk = clk_get(pdev, "core_clk");
+ if (IS_ERR(qclk->ce_core_clk)) {
+ rc = PTR_ERR(qclk->ce_core_clk);
pr_err("Unable to get CE core clk\n");
- if (ce_core_src_clk != NULL)
- clk_put(ce_core_src_clk);
+ if (qclk->ce_core_src_clk != NULL)
+ clk_put(qclk->ce_core_src_clk);
return -EIO;
}
/* Get CE Interface clk */
- ce_clk = clk_get(pdev, "iface_clk");
- if (IS_ERR(ce_clk)) {
- rc = PTR_ERR(ce_clk);
+ qclk->ce_clk = clk_get(pdev, "iface_clk");
+ if (IS_ERR(qclk->ce_clk)) {
+ rc = PTR_ERR(qclk->ce_clk);
pr_err("Unable to get CE interface clk\n");
- if (ce_core_src_clk != NULL)
- clk_put(ce_core_src_clk);
- clk_put(ce_core_clk);
+ if (qclk->ce_core_src_clk != NULL)
+ clk_put(qclk->ce_core_src_clk);
+ clk_put(qclk->ce_core_clk);
return -EIO;
}
/* Get CE AXI clk */
- ce_bus_clk = clk_get(pdev, "bus_clk");
- if (IS_ERR(ce_bus_clk)) {
- rc = PTR_ERR(ce_bus_clk);
+ qclk->ce_bus_clk = clk_get(pdev, "bus_clk");
+ if (IS_ERR(qclk->ce_bus_clk)) {
+ rc = PTR_ERR(qclk->ce_bus_clk);
pr_err("Unable to get CE BUS interface clk\n");
- if (ce_core_src_clk != NULL)
- clk_put(ce_core_src_clk);
- clk_put(ce_core_clk);
- clk_put(ce_clk);
+ if (qclk->ce_core_src_clk != NULL)
+ clk_put(qclk->ce_core_src_clk);
+ clk_put(qclk->ce_core_clk);
+ clk_put(qclk->ce_clk);
return -EIO;
}
return rc;
@@ -2448,21 +2496,25 @@
static void __qseecom_deinit_clk(void)
{
- if (ce_clk != NULL) {
- clk_put(ce_clk);
- ce_clk = NULL;
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
+
+ if (qclk->ce_clk != NULL) {
+ clk_put(qclk->ce_clk);
+ qclk->ce_clk = NULL;
}
- if (ce_core_clk != NULL) {
- clk_put(ce_core_clk);
- ce_clk = NULL;
+ if (qclk->ce_core_clk != NULL) {
+ clk_put(qclk->ce_core_clk);
+ qclk->ce_clk = NULL;
}
- if (ce_bus_clk != NULL) {
- clk_put(ce_bus_clk);
- ce_clk = NULL;
+ if (qclk->ce_bus_clk != NULL) {
+ clk_put(qclk->ce_bus_clk);
+ qclk->ce_clk = NULL;
}
- if (ce_core_src_clk != NULL) {
- clk_put(ce_core_src_clk);
- ce_core_src_clk = NULL;
+ if (qclk->ce_core_src_clk != NULL) {
+ clk_put(qclk->ce_core_src_clk);
+ qclk->ce_core_src_clk = NULL;
}
}
@@ -2475,14 +2527,14 @@
struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
- qsee_bw_count = 0;
- qsee_perf_client = 0;
- qsee_sfpb_bw_count = 0;
+ qseecom.qsee_bw_count = 0;
+ qseecom.qsee_perf_client = 0;
+ qseecom.qsee_sfpb_bw_count = 0;
- ce_core_clk = NULL;
- ce_clk = NULL;
- ce_core_src_clk = NULL;
- ce_bus_clk = NULL;
+ qseecom.qsee.ce_core_clk = NULL;
+ qseecom.qsee.ce_clk = NULL;
+ qseecom.qsee.ce_core_src_clk = NULL;
+ qseecom.qsee.ce_bus_clk = NULL;
rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
if (rc < 0) {
@@ -2561,11 +2613,7 @@
ret = __qseecom_init_clk();
if (ret)
goto err;
- ret = __qseecom_enable_clk();
- if (ret) {
- __qseecom_deinit_clk();
- goto err;
- }
+
qseecom_platform_support = (struct msm_bus_scale_pdata *)
msm_bus_cl_get_pdata(pdev);
if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
@@ -2599,10 +2647,10 @@
pdev->dev.platform_data;
}
- qsee_perf_client = msm_bus_scale_register_client(
+ qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
- if (!qsee_perf_client)
+ if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
return 0;
err:
@@ -2621,7 +2669,7 @@
int ret = 0;
if (pdev->dev.platform_data != NULL)
- msm_bus_scale_unregister_client(qsee_perf_client);
+ msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
@@ -2672,13 +2720,13 @@
if (qseecom.qseos_version > QSEEE_VERSION_00)
qseecom_unload_commonlib_image();
- if (qsee_perf_client)
- msm_bus_scale_client_update_request(qsee_perf_client, 0);
+ if (qseecom.qsee_perf_client)
+ msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
+ 0);
/* register client for bus scaling */
- if (pdev->dev.of_node) {
- __qseecom_disable_clk();
+ if (pdev->dev.of_node)
__qseecom_deinit_clk();
- }
+
return ret;
};
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 9598d45..9ef86a7 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -2582,28 +2582,27 @@
debugfs_create_u32(
"stat_rx_chunks",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
tsif_device->dent_tsif,
&tsif_device->stat_rx);
debugfs_create_u32(
"stat_overflow",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
tsif_device->dent_tsif,
&tsif_device->stat_overflow);
debugfs_create_u32(
"stat_lost_sync",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
tsif_device->dent_tsif,
&tsif_device->stat_lost_sync);
debugfs_create_u32(
"stat_timeout",
- S_IRUGO|S_IWUGO,
+ S_IRUGO | S_IWUSR | S_IWGRP,
tsif_device->dent_tsif,
&tsif_device->stat_timeout);
-
}
}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index dc129f7..60e0640 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1166,6 +1166,7 @@
if (!retries) {
printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n",
__func__, mmc_hostname(host), err);
+ err = _mmc_detect_card_removed(host);
}
#else
err = _mmc_detect_card_removed(host);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index f3973ef..4a063fd 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1160,9 +1160,16 @@
data_cnt = SPS_MAX_DESC_SIZE;
} else {
data_cnt = len;
- if (i == data->sg_len - 1)
+ if ((i == data->sg_len - 1) &&
+ (sps_pipe_handle ==
+ host->sps.cons.pipe_handle)) {
+ /*
+ * set EOT only for consumer pipe, for
+ * producer pipe h/w will set it.
+ */
flags = SPS_IOVEC_FLAG_INT |
SPS_IOVEC_FLAG_EOT;
+ }
}
rc = sps_transfer_one(sps_pipe_handle, addr,
data_cnt, host, flags);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2769709..5090eea 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2253,7 +2253,6 @@
MMC_CAP2_DETECT_ON_ERR);
msm_host->mmc->caps2 |= MMC_CAP2_SANITIZE;
msm_host->mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
- msm_host->mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
msm_host->mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 41dd6e7..ed67df4 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -22,7 +22,7 @@
#include <mach/ecm_ipa.h>
#define DRIVER_NAME "ecm_ipa"
-#define DRIVER_VERSION "12-Mar-2013"
+#define DRIVER_VERSION "20-Mar-2013"
#define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
#define ECM_IPA_IPV6_HDR_NAME "ecm_eth_ipv6"
#define IPA_TO_USB_CLIENT IPA_CLIENT_USB_CONS
@@ -30,13 +30,6 @@
#define ECM_IPA_ERROR(fmt, args...) \
pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
fmt, __func__, __LINE__, current->comm, ## args)
-#ifdef ECM_IPA_DEBUG_ON
-#define ECM_IPA_DEBUG(fmt, args...) \
- pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
- fmt, __func__, __LINE__, current->comm, ## args)
-#else /* ECM_IPA_DEBUG_ON */
-#define ECM_IPA_DEBUG(fmt, args...)
-#endif /* ECM_IPA_DEBUG_ON */
#define NULL_CHECK(ptr) \
do { \
@@ -47,8 +40,8 @@
} \
while (0)
-#define ECM_IPA_LOG_ENTRY() ECM_IPA_DEBUG("begin\n")
-#define ECM_IPA_LOG_EXIT() ECM_IPA_DEBUG("end\n")
+#define ECM_IPA_LOG_ENTRY() pr_debug("begin\n")
+#define ECM_IPA_LOG_EXIT() pr_debug("end\n")
/**
* struct ecm_ipa_dev - main driver context parameters
@@ -192,7 +185,7 @@
struct net_device *net;
struct ecm_ipa_dev *dev;
ECM_IPA_LOG_ENTRY();
- ECM_IPA_DEBUG("%s version %s\n", DRIVER_NAME, DRIVER_VERSION);
+ pr_debug("%s version %s\n", DRIVER_NAME, DRIVER_VERSION);
NULL_CHECK(ecm_ipa_rx_dp_notify);
NULL_CHECK(ecm_ipa_tx_dp_notify);
NULL_CHECK(priv);
@@ -202,7 +195,7 @@
ECM_IPA_ERROR("fail to allocate etherdev\n");
goto fail_alloc_etherdev;
}
- ECM_IPA_DEBUG("etherdev was successfully allocated\n");
+ pr_debug("etherdev was successfully allocated\n");
dev = netdev_priv(net);
memset(dev, 0, sizeof(*dev));
dev->tx_enable = true;
@@ -213,11 +206,11 @@
*priv = (void *)dev;
snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
net->netdev_ops = &ecm_ipa_netdev_ops;
- ECM_IPA_DEBUG("internal data structures were intialized\n");
+ pr_debug("internal data structures were intialized\n");
ret = ecm_ipa_debugfs_init(dev);
if (ret)
goto fail_debugfs;
- ECM_IPA_DEBUG("debugfs entries were created\n");
+ pr_debug("debugfs entries were created\n");
*ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
*ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
ECM_IPA_LOG_EXIT();
@@ -382,7 +375,7 @@
ECM_IPA_LOG_ENTRY();
result = ipa_deregister_intf("ecm0");
if (result)
- ECM_IPA_DEBUG("Fail on Tx prop deregister\n");
+ pr_debug("Fail on Tx prop deregister\n");
ECM_IPA_LOG_EXIT();
return;
}
@@ -415,14 +408,14 @@
NULL_CHECK(dev);
net = dev->net;
NULL_CHECK(net);
- ECM_IPA_DEBUG("host_ethaddr=%pM device_ethaddr=%pM\n",
+ pr_debug("host_ethaddr=%pM device_ethaddr=%pM\n",
host_ethaddr, device_ethaddr);
result = ecm_ipa_create_rm_resource(dev);
if (result) {
ECM_IPA_ERROR("fail on RM create\n");
return -EINVAL;
}
- ECM_IPA_DEBUG("RM resource was created\n");
+ pr_debug("RM resource was created\n");
netif_carrier_off(dev->net);
result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
device_ethaddr);
@@ -435,19 +428,19 @@
ECM_IPA_ERROR("fail on ipa rules set\n");
goto fail_set_device_ethernet;
}
- ECM_IPA_DEBUG("Ethernet header insertion was set\n");
+ pr_debug("Ethernet header insertion was set\n");
result = ecm_ipa_register_properties();
if (result) {
ECM_IPA_ERROR("fail on properties set\n");
goto fail_register_tx;
}
- ECM_IPA_DEBUG("ECM 2 Tx and 2 Rx properties were registered\n");
+ pr_debug("ECM 2 Tx and 2 Rx properties were registered\n");
result = register_netdev(net);
if (result) {
ECM_IPA_ERROR("register_netdev failed: %d\n", result);
goto fail_register_netdev;
}
- ECM_IPA_DEBUG("register_netdev succeeded\n");
+ pr_debug("register_netdev succeeded\n");
ECM_IPA_LOG_EXIT();
return 0;
fail_register_netdev:
@@ -467,7 +460,7 @@
struct ecm_ipa_dev *dev = priv;
ECM_IPA_LOG_ENTRY();
NULL_CHECK(priv);
- ECM_IPA_DEBUG("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
+ pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
usb_to_ipa_hdl, ipa_to_usb_hdl);
if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
@@ -511,10 +504,10 @@
ECM_IPA_LOG_ENTRY();
if (event == IPA_RM_RESOURCE_GRANTED &&
netif_queue_stopped(dev->net)) {
- ECM_IPA_DEBUG("Resource Granted - waking queue\n");
+ pr_debug("Resource Granted - waking queue\n");
netif_wake_queue(dev->net);
} else {
- ECM_IPA_DEBUG("Resource released\n");
+ pr_debug("Resource released\n");
}
ECM_IPA_LOG_EXIT();
}
@@ -532,7 +525,7 @@
ECM_IPA_ERROR("Fail on ipa_rm_create_resource\n");
goto fail_rm_create;
}
- ECM_IPA_DEBUG("rm client was created");
+ pr_debug("rm client was created");
result = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_STD_ECM_PROD,
INACTIVITY_MSEC_DELAY);
@@ -540,14 +533,14 @@
ECM_IPA_ERROR("Fail on ipa_rm_inactivity_timer_init\n");
goto fail_it;
}
- ECM_IPA_DEBUG("rm_it client was created");
+ pr_debug("rm_it client was created");
result = ipa_rm_add_dependency(IPA_RM_RESOURCE_STD_ECM_PROD,
IPA_RM_RESOURCE_USB_CONS);
if (result)
ECM_IPA_ERROR("unable to add dependency (%d)\n", result);
- ECM_IPA_DEBUG("rm dependency was set\n");
+ pr_debug("rm dependency was set\n");
ECM_IPA_LOG_EXIT();
return 0;
@@ -596,7 +589,7 @@
static int ecm_ipa_stop(struct net_device *net)
{
ECM_IPA_LOG_ENTRY();
- ECM_IPA_DEBUG("stopping net device\n");
+ pr_debug("stopping net device\n");
netif_stop_queue(net);
ECM_IPA_LOG_EXIT();
return 0;
@@ -624,7 +617,7 @@
unregister_netdev(dev->net);
free_netdev(dev->net);
}
- ECM_IPA_DEBUG("cleanup done\n");
+ pr_debug("cleanup done\n");
ecm_ipa_ctx = NULL;
ECM_IPA_LOG_EXIT();
return ;
@@ -678,20 +671,20 @@
if (unlikely(tx_filter(skb))) {
dev_kfree_skb_any(skb);
- ECM_IPA_DEBUG("packet got filtered out on Tx path\n");
+ pr_debug("packet got filtered out on Tx path\n");
status = NETDEV_TX_OK;
goto out;
}
ret = resource_request(dev);
if (ret) {
- ECM_IPA_DEBUG("Waiting to resource\n");
+ pr_debug("Waiting to resource\n");
netif_stop_queue(net);
goto resource_busy;
}
spin_lock_irqsave(&dev->ack_spinlock, flags);
if (dev->last_out_skb) {
- ECM_IPA_DEBUG("No Tx-ack received for previous packet\n");
+ pr_debug("No Tx-ack received for previous packet\n");
spin_unlock_irqrestore(&dev->ack_spinlock, flags);
netif_stop_queue(net);
status = -NETDEV_TX_BUSY;
@@ -743,7 +736,7 @@
skb->dev = dev->net;
skb->protocol = eth_type_trans(skb, dev->net);
if (rx_filter(skb)) {
- ECM_IPA_DEBUG("packet got filtered out on Rx path\n");
+ pr_debug("packet got filtered out on Rx path\n");
dev_kfree_skb_any(skb);
return;
}
@@ -789,7 +782,7 @@
dev->last_out_skb = NULL;
spin_unlock_irqrestore(&dev->ack_spinlock, flags);
if (netif_queue_stopped(dev->net)) {
- ECM_IPA_DEBUG("waking up queue\n");
+ pr_debug("waking up queue\n");
netif_wake_queue(dev->net);
}
dev_kfree_skb_any(skb);
@@ -866,9 +859,9 @@
missing = copy_from_user(&input, buf, 1);
if (missing)
return -EFAULT;
- ECM_IPA_DEBUG("input received %c\n", input);
+ pr_debug("input received %c\n", input);
*enable = input - '0';
- ECM_IPA_DEBUG("value was set to %d\n", *enable);
+ pr_debug("value was set to %d\n", *enable);
return count;
}
@@ -1001,7 +994,7 @@
ECM_IPA_ERROR("failed to configure IPA to USB end-point\n");
goto out;
}
- ECM_IPA_DEBUG("end-point registers successfully configured\n");
+ pr_debug("end-point registers successfully configured\n");
out:
ECM_IPA_LOG_EXIT();
return result;
@@ -1040,7 +1033,7 @@
ECM_IPA_ERROR("failed to configure USB to IPA\n");
goto out;
}
- ECM_IPA_DEBUG("end-point registers successfully configured\n");
+ pr_debug("end-point registers successfully configured\n");
out:
ECM_IPA_LOG_EXIT();
return result;
@@ -1057,7 +1050,7 @@
if (!is_valid_ether_addr(device_ethaddr))
return -EINVAL;
memcpy(dev_ethaddr, device_ethaddr, ETH_ALEN);
- ECM_IPA_DEBUG("device ethernet address: %pM\n", dev_ethaddr);
+ pr_debug("device ethernet address: %pM\n", dev_ethaddr);
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index cfbedfb..a4b7e22 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,6 +13,8 @@
#include <linux/delay.h>
#include "ipa_i.h"
+#define IPA_HOLB_TMR_VAL 0xff
+
static void ipa_enable_data_path(u32 clnt_hdl)
{
struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
@@ -248,6 +250,20 @@
memcpy(&sps->desc, &ep->connect.desc, sizeof(struct sps_mem_buffer));
memcpy(&sps->data, &ep->connect.data, sizeof(struct sps_mem_buffer));
+ if (in->client == IPA_CLIENT_HSIC1_CONS ||
+ in->client == IPA_CLIENT_HSIC2_CONS ||
+ in->client == IPA_CLIENT_HSIC3_CONS ||
+ in->client == IPA_CLIENT_HSIC4_CONS) {
+ IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
+ IPA_HOLB_TMR_VAL);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx),
+ 0x1);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx),
+ IPA_HOLB_TMR_VAL);
+ }
+
IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx);
return 0;
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 0f81285..47108c6 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -17,6 +17,7 @@
#include <linux/io.h> /* ioread32() */
#include <linux/bitops.h> /* find_first_bit() */
#include <linux/errno.h> /* ENODEV */
+#include <linux/memory.h>
#include "bam.h"
#include "sps_bam.h"
@@ -849,7 +850,7 @@
print_bam_test_bus_reg(base, 0);
- print_bam_reg(base);
+ print_bam_selected_reg(base, BAM_MAX_EES);
num_pipes = bam_read_reg_field(base, NUM_PIPES,
BAM_NUM_PIPES);
@@ -857,8 +858,7 @@
(u32) base, num_pipes);
for (i = 0; i < num_pipes; i++)
- print_bam_pipe_reg(base, i);
-
+ print_bam_pipe_selected_reg(base, i);
}
/**
@@ -1174,7 +1174,7 @@
pipes = bam[0xfbc / 4];
#endif
- SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+ SPS_INFO("\nsps:<bam-begin> --- Content of BAM-level registers---\n");
SPS_INFO("BAM_CTRL: 0x%x.\n", ctrl);
SPS_INFO("BAM_REVISION: 0x%x.\n", ver);
@@ -1198,7 +1198,7 @@
bam[i / 4], bam[(i / 4) + 1],
bam[(i / 4) + 2], bam[(i / 4) + 3]);
- SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+ SPS_INFO("\nsps:<bam-begin> --- Content of BAM-level registers ---\n");
}
/* output the content of BAM pipe registers */
@@ -1211,7 +1211,7 @@
if (bam == NULL)
return;
- SPS_INFO("\nsps:----- Content of Pipe %d registers <begin> -----\n",
+ SPS_INFO("\nsps:<pipe-begin> --- Content of Pipe %d registers ---\n",
pipe);
SPS_INFO("-- Pipe Management Registers --\n");
@@ -1240,47 +1240,110 @@
bam[i / 4], bam[(i / 4) + 1],
bam[(i / 4) + 2], bam[(i / 4) + 3]);
- SPS_INFO("\nsps:----- Content of Pipe %d registers <end> -----\n",
+ SPS_INFO("\nsps:<pipe-end> --- Content of Pipe %d registers ---\n",
pipe);
}
/* output the content of selected BAM-level registers */
-void print_bam_selected_reg(void *virt_addr)
+void print_bam_selected_reg(void *virt_addr, u32 ee)
{
void *base = virt_addr;
+ u32 bam_ctrl;
+ u32 bam_revision;
+ u32 bam_rev_num;
+ u32 bam_rev_ee_num;
+
+ u32 bam_num_pipes;
+ u32 bam_pipe_num;
+
+ u32 bam_desc_cnt_trshld;
+ u32 bam_desc_cnt_trd_val;
+
+ u32 bam_irq_en;
+ u32 bam_irq_stts;
+
+ u32 bam_irq_src_ee = 0;
+ u32 bam_irq_msk_ee = 0;
+ u32 bam_irq_unmsk_ee = 0;
+
+ u32 bam_ahb_err_ctrl;
+ u32 bam_ahb_err_addr;
+ u32 bam_ahb_err_data;
+ u32 bam_cnfg_bits;
+
+ u32 bam_sw_rev = 0;
+ u32 bam_timer = 0;
+ u32 bam_timer_ctrl = 0;
+
if (base == NULL)
return;
- SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+ bam_ctrl = bam_read_reg(base, CTRL);
+ bam_revision = bam_read_reg(base, REVISION);
+ bam_rev_num = bam_read_reg_field(base, REVISION, BAM_REVISION);
+ bam_rev_ee_num = bam_read_reg_field(base, REVISION, BAM_NUM_EES);
- SPS_INFO("BAM_CTRL: 0x%x\n"
- "BAM_REVISION: 0x%x\n"
- "BAM_NUM_EES: %d\n"
-#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
- "BAM_CMD_DESC_EN: 0x%x\n"
-#endif
- "BAM_NUM_PIPES: %d\n"
- "BAM_DESC_CNT_TRSHLD: 0x%x (%d)\n"
- "BAM_IRQ_SRCS: 0x%x\n"
- "BAM_IRQ_SRCS_MSK: 0x%x\n"
- "BAM_EE: %d\n"
- "BAM_CNFG_BITS: 0x%x\n",
- bam_read_reg(base, CTRL),
- bam_read_reg_field(base, REVISION, BAM_REVISION),
- bam_read_reg_field(base, REVISION, BAM_NUM_EES),
-#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
- bam_read_reg_field(base, REVISION, BAM_CMD_DESC_EN),
-#endif
- bam_read_reg_field(base, NUM_PIPES, BAM_NUM_PIPES),
- bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
- bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
- bam_read_reg(base, IRQ_SRCS),
- bam_read_reg(base, IRQ_SRCS_MSK),
- bam_read_reg_field(base, TRUST_REG, BAM_EE),
- bam_read_reg(base, CNFG_BITS));
+ bam_num_pipes = bam_read_reg(base, NUM_PIPES);
+ bam_pipe_num = bam_read_reg_field(base, NUM_PIPES, BAM_NUM_PIPES);
- SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+ bam_desc_cnt_trshld = bam_read_reg(base, DESC_CNT_TRSHLD);
+ bam_desc_cnt_trd_val = bam_read_reg_field(base, DESC_CNT_TRSHLD,
+ BAM_DESC_CNT_TRSHLD);
+
+ bam_irq_en = bam_read_reg(base, IRQ_EN);
+ bam_irq_stts = bam_read_reg(base, IRQ_STTS);
+
+ if (ee < BAM_MAX_EES) {
+ bam_irq_src_ee = bam_read_reg(base, IRQ_SRCS_EE(ee));
+ bam_irq_msk_ee = bam_read_reg(base, IRQ_SRCS_MSK_EE(ee));
+ bam_irq_unmsk_ee = bam_read_reg(base, IRQ_SRCS_UNMASKED_EE(ee));
+ }
+
+ bam_ahb_err_ctrl = bam_read_reg(base, AHB_MASTER_ERR_CTRLS);
+ bam_ahb_err_addr = bam_read_reg(base, AHB_MASTER_ERR_ADDR);
+ bam_ahb_err_data = bam_read_reg(base, AHB_MASTER_ERR_DATA);
+ bam_cnfg_bits = bam_read_reg(base, CNFG_BITS);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ bam_sw_rev = bam_read_reg(base, SW_REVISION);
+ bam_timer = bam_read_reg(base, TIMER);
+ bam_timer_ctrl = bam_read_reg(base, TIMER_CTRL);
+#endif
+
+
+ SPS_INFO("\nsps:<bam-begin> --- BAM-level registers ---\n\n");
+
+ SPS_INFO("BAM_CTRL: 0x%x\n", bam_ctrl);
+ SPS_INFO("BAM_REVISION: 0x%x\n", bam_revision);
+ SPS_INFO(" REVISION: 0x%x\n", bam_rev_num);
+ SPS_INFO(" NUM_EES: %d\n", bam_rev_ee_num);
+ SPS_INFO("BAM_SW_REVISION: 0x%x\n", bam_sw_rev);
+ SPS_INFO("BAM_NUM_PIPES: %d\n", bam_num_pipes);
+ SPS_INFO(" NUM_PIPES: %d\n", bam_pipe_num);
+ SPS_INFO("BAM_DESC_CNT_TRSHLD: 0x%x\n", bam_desc_cnt_trshld);
+ SPS_INFO(" DESC_CNT_TRSHLD: 0x%x (%d)\n", bam_desc_cnt_trd_val,
+ bam_desc_cnt_trd_val);
+
+ SPS_INFO("BAM_IRQ_EN: 0x%x\n", bam_irq_en);
+ SPS_INFO("BAM_IRQ_STTS: 0x%x\n", bam_irq_stts);
+
+ if (ee < BAM_MAX_EES) {
+ SPS_INFO("BAM_IRQ_SRCS_EE(%d): 0x%x\n", ee, bam_irq_src_ee);
+ SPS_INFO("BAM_IRQ_SRCS_MSK_EE(%d): 0x%x\n", ee, bam_irq_msk_ee);
+ SPS_INFO("BAM_IRQ_SRCS_UNMASKED_EE(%d): 0x%x\n", ee,
+ bam_irq_unmsk_ee);
+ }
+
+ SPS_INFO("BAM_AHB_MASTER_ERR_CTRLS: 0x%x\n", bam_ahb_err_ctrl);
+ SPS_INFO("BAM_AHB_MASTER_ERR_ADDR: 0x%x\n", bam_ahb_err_addr);
+ SPS_INFO("BAM_AHB_MASTER_ERR_DATA: 0x%x\n", bam_ahb_err_data);
+
+ SPS_INFO("BAM_CNFG_BITS: 0x%x\n", bam_cnfg_bits);
+ SPS_INFO("BAM_TIMER: 0x%x\n", bam_timer);
+ SPS_INFO("BAM_TIMER_CTRL: 0x%x\n", bam_timer_ctrl);
+
+ SPS_INFO("\nsps:<bam-end> --- BAM-level registers ---\n\n");
}
/* output the content of selected BAM pipe registers */
@@ -1289,68 +1352,205 @@
void *base = virt_addr;
u32 pipe = pipe_index;
+ u32 p_ctrl;
+ u32 p_sys_mode;
+ u32 p_direction;
+ u32 p_lock_group = 0;
+
+ u32 p_irq_en;
+ u32 p_irq_stts;
+ u32 p_irq_stts_eot;
+ u32 p_irq_stts_int;
+
+ u32 p_prd_sdbd;
+ u32 p_bytes_free;
+ u32 p_prd_ctrl;
+ u32 p_prd_toggle;
+ u32 p_prd_sb_updated;
+
+ u32 p_con_sdbd;
+ u32 p_bytes_avail;
+ u32 p_con_ctrl;
+ u32 p_con_toggle;
+ u32 p_con_ack_toggle;
+ u32 p_con_ack_toggle_r;
+ u32 p_con_wait_4_ack;
+ u32 p_con_sb_updated;
+
+ u32 p_sw_offset;
+ u32 p_read_pointer;
+ u32 p_evnt_reg;
+ u32 p_write_pointer;
+
+ u32 p_evnt_dest;
+ u32 p_desc_fifo_addr;
+ u32 p_desc_fifo_size;
+ u32 p_data_fifo_addr;
+ u32 p_data_fifo_size;
+ u32 p_fifo_sizes;
+
+ u32 p_evnt_trd;
+ u32 p_evnt_trd_val;
+
+ u32 p_retr_ct;
+ u32 p_retr_offset;
+ u32 p_si_ct;
+ u32 p_si_offset;
+ u32 p_df_ct = 0;
+ u32 p_df_offset = 0;
+ u32 p_au_ct1;
+ u32 p_psm_ct2;
+ u32 p_psm_ct3;
+ u32 p_psm_ct4;
+ u32 p_psm_ct5;
+
+ u32 p_timer;
+ u32 p_timer_ctrl;
+
if (base == NULL)
return;
- SPS_INFO("\nsps:----- Registers of Pipe %d -----\n", pipe);
+ p_ctrl = bam_read_reg(base, P_CTRL(pipe));
+ p_sys_mode = bam_read_reg_field(base, P_CTRL(pipe), P_SYS_MODE);
+ p_direction = bam_read_reg_field(base, P_CTRL(pipe), P_DIRECTION);
- SPS_INFO("BAM_P_CTRL: 0x%x\n"
- "BAM_P_SYS_MODE: %d\n"
- "BAM_P_DIRECTION: %d\n"
+ p_irq_en = bam_read_reg(base, P_IRQ_EN(pipe));
+ p_irq_stts = bam_read_reg(base, P_IRQ_STTS(pipe));
+ p_irq_stts_eot = bam_read_reg_field(base, P_IRQ_STTS(pipe),
+ P_IRQ_STTS_P_TRNSFR_END_IRQ);
+ p_irq_stts_int = bam_read_reg_field(base, P_IRQ_STTS(pipe),
+ P_IRQ_STTS_P_PRCSD_DESC_IRQ);
+
+ p_prd_sdbd = bam_read_reg(base, P_PRDCR_SDBND(pipe));
+ p_bytes_free = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+ P_PRDCR_SDBNDn_BAM_P_BYTES_FREE);
+ p_prd_ctrl = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+ P_PRDCR_SDBNDn_BAM_P_CTRL);
+ p_prd_toggle = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+ P_PRDCR_SDBNDn_BAM_P_TOGGLE);
+ p_prd_sb_updated = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+ P_PRDCR_SDBNDn_BAM_P_SB_UPDATED);
+ p_con_sdbd = bam_read_reg(base, P_CNSMR_SDBND(pipe));
+ p_bytes_avail = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL);
+ p_con_ctrl = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_CTRL);
+ p_con_toggle = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_TOGGLE);
+ p_con_ack_toggle = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_ACK_TOGGLE);
+ p_con_ack_toggle_r = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_ACK_TOGGLE_R);
+ p_con_wait_4_ack = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_WAIT_4_ACK);
+ p_con_sb_updated = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_SB_UPDATED);
+
+ p_sw_offset = bam_read_reg(base, P_SW_OFSTS(pipe));
+ p_read_pointer = bam_read_reg_field(base, P_SW_OFSTS(pipe),
+ SW_DESC_OFST);
+ p_evnt_reg = bam_read_reg(base, P_EVNT_REG(pipe));
+ p_write_pointer = bam_read_reg_field(base, P_EVNT_REG(pipe),
+ P_DESC_FIFO_PEER_OFST);
+
+ p_evnt_dest = bam_read_reg(base, P_EVNT_DEST_ADDR(pipe));
+ p_desc_fifo_addr = bam_read_reg(base, P_DESC_FIFO_ADDR(pipe));
+ p_desc_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES(pipe),
+ P_DESC_FIFO_SIZE);
+ p_data_fifo_addr = bam_read_reg(base, P_DATA_FIFO_ADDR(pipe));
+ p_data_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES(pipe),
+ P_DATA_FIFO_SIZE);
+ p_fifo_sizes = bam_read_reg(base, P_FIFO_SIZES(pipe));
+
+ p_evnt_trd = bam_read_reg(base, P_EVNT_GEN_TRSHLD(pipe));
+ p_evnt_trd_val = bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
+ P_EVNT_GEN_TRSHLD_P_TRSHLD);
+
+ p_retr_ct = bam_read_reg(base, P_RETR_CNTXT(pipe));
+ p_retr_offset = bam_read_reg_field(base, P_RETR_CNTXT(pipe),
+ P_RETR_CNTXT_RETR_DESC_OFST);
+ p_si_ct = bam_read_reg(base, P_SI_CNTXT(pipe));
+ p_si_offset = bam_read_reg_field(base, P_SI_CNTXT(pipe),
+ P_SI_CNTXT_SI_DESC_OFST);
+ p_au_ct1 = bam_read_reg(base, P_AU_PSM_CNTXT_1(pipe));
+ p_psm_ct2 = bam_read_reg(base, P_PSM_CNTXT_2(pipe));
+ p_psm_ct3 = bam_read_reg(base, P_PSM_CNTXT_3(pipe));
+ p_psm_ct4 = bam_read_reg(base, P_PSM_CNTXT_4(pipe));
+ p_psm_ct5 = bam_read_reg(base, P_PSM_CNTXT_5(pipe));
+
+ p_timer = bam_read_reg(base, P_TIMER(pipe));
+ p_timer_ctrl = bam_read_reg(base, P_TIMER_CTRL(pipe));
+
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
- "BAM_P_LOCK_GROUP: 0x%x (%d)\n"
+ p_lock_group = bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP);
+ p_df_ct = bam_read_reg(base, P_DF_CNTXT(pipe));
+ p_df_offset = bam_read_reg_field(base, P_DF_CNTXT(pipe),
+ P_DF_CNTXT_DF_DESC_OFST);
#endif
- "BAM_P_EE: %d\n"
- "BAM_P_IRQ_STTS: 0x%x\n"
- "BAM_P_IRQ_STTS_P_TRNSFR_END_IRQ: 0x%x\n"
- "BAM_P_IRQ_STTS_P_PRCSD_DESC_IRQ: 0x%x\n"
- "BAM_P_IRQ_EN: 0x%x\n"
- "BAM_P_PRDCR_SDBNDn_BAM_P_BYTES_FREE: 0x%x (%d)\n"
- "BAM_P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL: 0x%x (%d)\n"
- "BAM_P_SW_DESC_OFST: 0x%x\n"
- "BAM_P_DESC_FIFO_PEER_OFST: 0x%x\n"
- "BAM_P_EVNT_DEST_ADDR: 0x%x\n"
- "BAM_P_DESC_FIFO_ADDR: 0x%x\n"
- "BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n"
- "BAM_P_DATA_FIFO_ADDR: 0x%x\n"
- "BAM_P_DATA_FIFO_SIZE: 0x%x (%d)\n"
- "BAM_P_EVNT_GEN_TRSHLD: 0x%x (%d)\n",
- bam_read_reg(base, P_CTRL(pipe)),
- bam_read_reg_field(base, P_CTRL(pipe), P_SYS_MODE),
- bam_read_reg_field(base, P_CTRL(pipe), P_DIRECTION),
-#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
- bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
- bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
-#endif
- bam_read_reg_field(base, P_TRUST_REG(pipe), BAM_P_EE),
- bam_read_reg(base, P_IRQ_STTS(pipe)),
- bam_read_reg_field(base, P_IRQ_STTS(pipe),
- P_IRQ_STTS_P_TRNSFR_END_IRQ),
- bam_read_reg_field(base, P_IRQ_STTS(pipe),
- P_IRQ_STTS_P_PRCSD_DESC_IRQ),
- bam_read_reg(base, P_IRQ_EN(pipe)),
- bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
- P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
- bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
- P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
- bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
- P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
- bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
- P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
- bam_read_reg_field(base, P_SW_OFSTS(pipe), SW_DESC_OFST),
- bam_read_reg_field(base, P_EVNT_REG(pipe),
- P_DESC_FIFO_PEER_OFST),
- bam_read_reg(base, P_EVNT_DEST_ADDR(pipe)),
- bam_read_reg(base, P_DESC_FIFO_ADDR(pipe)),
- bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
- bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
- bam_read_reg(base, P_DATA_FIFO_ADDR(pipe)),
- bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
- bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
- bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
- P_EVNT_GEN_TRSHLD_P_TRSHLD),
- bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
- P_EVNT_GEN_TRSHLD_P_TRSHLD));
+
+ SPS_INFO("\nsps:<pipe-begin> --- Registers of Pipe %d ---\n\n", pipe);
+
+ SPS_INFO("BAM_P_CTRL: 0x%x\n", p_ctrl);
+ SPS_INFO(" SYS_MODE: %d\n", p_sys_mode);
+ if (p_direction)
+ SPS_INFO(" DIRECTION:%d->Producer\n", p_direction);
+ else
+ SPS_INFO(" DIRECTION:%d->Consumer\n", p_direction);
+ SPS_INFO(" LOCK_GROUP: 0x%x (%d)\n", p_lock_group, p_lock_group);
+
+ SPS_INFO("BAM_P_IRQ_EN: 0x%x\n", p_irq_en);
+ SPS_INFO("BAM_P_IRQ_STTS: 0x%x\n", p_irq_stts);
+ SPS_INFO(" TRNSFR_END_IRQ(EOT): 0x%x\n", p_irq_stts_eot);
+ SPS_INFO(" PRCSD_DESC_IRQ(INT): 0x%x\n", p_irq_stts_int);
+
+ SPS_INFO("BAM_P_PRDCR_SDBND: 0x%x\n", p_prd_sdbd);
+ SPS_INFO(" BYTES_FREE: 0x%x (%d)\n", p_bytes_free, p_bytes_free);
+ SPS_INFO(" CTRL: 0x%x\n", p_prd_ctrl);
+ SPS_INFO(" TOGGLE: %d\n", p_prd_toggle);
+ SPS_INFO(" SB_UPDATED: %d\n", p_prd_sb_updated);
+ SPS_INFO("BAM_P_CNSMR_SDBND: 0x%x\n", p_con_sdbd);
+ SPS_INFO(" WAIT_4_ACK: %d\n", p_con_wait_4_ack);
+ SPS_INFO(" BYTES_AVAIL: 0x%x (%d)\n", p_bytes_avail, p_bytes_avail);
+ SPS_INFO(" CTRL: 0x%x\n", p_con_ctrl);
+ SPS_INFO(" TOGGLE: %d\n", p_con_toggle);
+ SPS_INFO(" ACK_TOGGLE: %d\n", p_con_ack_toggle);
+ SPS_INFO(" ACK_TOGGLE_R: %d\n", p_con_ack_toggle_r);
+ SPS_INFO(" SB_UPDATED: %d\n", p_con_sb_updated);
+
+ SPS_INFO("BAM_P_SW_DESC_OFST: 0x%x\n", p_sw_offset);
+ SPS_INFO(" SW_DESC_OFST: 0x%x\n", p_read_pointer);
+ SPS_INFO("BAM_P_EVNT_REG: 0x%x\n", p_evnt_reg);
+ SPS_INFO(" DESC_FIFO_PEER_OFST: 0x%x\n", p_write_pointer);
+
+ SPS_INFO("BAM_P_RETR_CNTXT: 0x%x\n", p_retr_ct);
+ SPS_INFO(" RETR_OFFSET: 0x%x\n", p_retr_offset);
+ SPS_INFO("BAM_P_SI_CNTXT: 0x%x\n", p_si_ct);
+ SPS_INFO(" SI_OFFSET: 0x%x\n", p_si_offset);
+ SPS_INFO("BAM_P_DF_CNTXT: 0x%x\n", p_df_ct);
+ SPS_INFO(" DF_OFFSET: 0x%x\n", p_df_offset);
+
+ SPS_INFO("BAM_P_DESC_FIFO_ADDR: 0x%x\n", p_desc_fifo_addr);
+ SPS_INFO("BAM_P_DATA_FIFO_ADDR: 0x%x\n", p_data_fifo_addr);
+ SPS_INFO("BAM_P_FIFO_SIZES: 0x%x\n", p_fifo_sizes);
+ SPS_INFO(" DESC_FIFO_SIZE: 0x%x (%d)\n", p_desc_fifo_size,
+ p_desc_fifo_size);
+ SPS_INFO(" DATA_FIFO_SIZE: 0x%x (%d)\n", p_data_fifo_size,
+ p_data_fifo_size);
+
+ SPS_INFO("BAM_P_EVNT_DEST_ADDR: 0x%x\n", p_evnt_dest);
+ SPS_INFO("BAM_P_EVNT_GEN_TRSHLD: 0x%x\n", p_evnt_trd);
+ SPS_INFO(" EVNT_GEN_TRSHLD: 0x%x (%d)\n", p_evnt_trd_val,
+ p_evnt_trd_val);
+
+ SPS_INFO("BAM_P_AU_PSM_CNTXT_1: 0x%x\n", p_au_ct1);
+ SPS_INFO("BAM_P_PSM_CNTXT_2: 0x%x\n", p_psm_ct2);
+ SPS_INFO("BAM_P_PSM_CNTXT_3: 0x%x\n", p_psm_ct3);
+ SPS_INFO("BAM_P_PSM_CNTXT_4: 0x%x\n", p_psm_ct4);
+ SPS_INFO("BAM_P_PSM_CNTXT_5: 0x%x\n", p_psm_ct5);
+ SPS_INFO("BAM_P_TIMER: 0x%x\n", p_timer);
+ SPS_INFO("BAM_P_TIMER_CTRL: 0x%x\n", p_timer_ctrl);
+
+ SPS_INFO("\nsps:<pipe-end> --- Registers of Pipe %d ---\n\n", pipe);
}
/* output descriptor FIFO of a pipe */
@@ -1362,6 +1562,7 @@
u32 desc_fifo_size;
u32 *desc_fifo;
int i;
+ char desc_info[MAX_MSG_LEN];
if (base == NULL)
return;
@@ -1380,7 +1581,8 @@
return;
}
- SPS_INFO("\nsps:----- descriptor FIFO of Pipe %d -----\n", pipe);
+ SPS_INFO("\nsps:<desc-begin> --- descriptor FIFO of Pipe %d -----\n\n",
+ pipe);
SPS_INFO("BAM_P_DESC_FIFO_ADDR: 0x%x\n"
"BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n\n",
@@ -1428,17 +1630,49 @@
if (desc_fifo_size > current_desc + size / 2)
end = current_desc + size / 2;
- SPS_INFO("------------- begin of partial FIFO -------------\n");
+ SPS_INFO("------------ begin of partial FIFO ------------\n\n");
- for (i = begin; i < end; i += 0x10)
- SPS_INFO("addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x.\n",
+ SPS_INFO("desc addr; desc content; desc flags\n");
+ for (i = begin; i < end; i += 0x8) {
+ u32 offset;
+ u32 flags = desc_fifo[(i / 4) + 1] >> 16;
+
+ memset(desc_info, 0, sizeof(desc_info));
+ offset = scnprintf(desc_info, 40, "0x%x: 0x%x, 0x%x: ",
desc_fifo_addr + i,
- desc_fifo[i / 4], desc_fifo[(i / 4) + 1],
- desc_fifo[(i / 4) + 2], desc_fifo[(i / 4) + 3]);
+ desc_fifo[i / 4], desc_fifo[(i / 4) + 1]);
- SPS_INFO("------------- end of partial FIFO -------------\n");
+ if (flags & SPS_IOVEC_FLAG_INT)
+ offset += scnprintf(desc_info + offset, 5,
+ "INT ");
+ if (flags & SPS_IOVEC_FLAG_EOT)
+ offset += scnprintf(desc_info + offset, 5,
+ "EOT ");
+ if (flags & SPS_IOVEC_FLAG_EOB)
+ offset += scnprintf(desc_info + offset, 5,
+ "EOB ");
+ if (flags & SPS_IOVEC_FLAG_NWD)
+ offset += scnprintf(desc_info + offset, 5,
+ "NWD ");
+ if (flags & SPS_IOVEC_FLAG_CMD)
+ offset += scnprintf(desc_info + offset, 5,
+ "CMD ");
+ if (flags & SPS_IOVEC_FLAG_LOCK)
+ offset += scnprintf(desc_info + offset, 5,
+ "LCK ");
+ if (flags & SPS_IOVEC_FLAG_UNLOCK)
+ offset += scnprintf(desc_info + offset, 5,
+ "UNL ");
+ if (flags & SPS_IOVEC_FLAG_IMME)
+ offset += scnprintf(desc_info + offset, 5,
+ "IMM ");
+
+ SPS_INFO("%s\n", desc_info);
+ }
+
+ SPS_INFO("\n------------ end of partial FIFO ------------\n");
} else {
- SPS_INFO("----------------- begin of FIFO -----------------\n");
+ SPS_INFO("---------------- begin of FIFO ----------------\n\n");
for (i = 0; i < desc_fifo_size; i += 0x10)
SPS_INFO("addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x.\n",
@@ -1446,8 +1680,11 @@
desc_fifo[i / 4], desc_fifo[(i / 4) + 1],
desc_fifo[(i / 4) + 2], desc_fifo[(i / 4) + 3]);
- SPS_INFO("----------------- end of FIFO -----------------\n");
+ SPS_INFO("\n---------------- end of FIFO ----------------\n");
}
+
+ SPS_INFO("\nsps:<desc-end> --- descriptor FIFO of Pipe %d -----\n\n",
+ pipe);
}
/* output BAM_TEST_BUS_REG with specified TEST_BUS_SEL */
@@ -1476,14 +1713,18 @@
BAM_TESTBUS_SEL));
}
+ SPS_INFO("\nsps:<testbus-begin> --- BAM TEST_BUS dump -----\n\n");
+
/* output other selections */
for (i = 0; i < size; i++) {
bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL,
test_bus_selection[i]);
- SPS_INFO("sps:bam 0x%x(va);TEST_BUS_REG:0x%x;TEST_BUS_SEL:0x%x",
- (u32) base, bam_read_reg(base, TEST_BUS_REG),
+ SPS_INFO("sps:TEST_BUS_REG:0x%x\t TEST_BUS_SEL:0x%x\n",
+ bam_read_reg(base, TEST_BUS_REG),
bam_read_reg_field(base, TEST_BUS_SEL,
BAM_TESTBUS_SEL));
}
+
+ SPS_INFO("\nsps:<testbus-end> --- BAM TEST_BUS dump -----\n\n");
}
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index b34f9dc..6f2e2a4 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -325,7 +325,7 @@
print_bam_reg(vir_addr);
break;
case 3: /* output selected BAM-level registers */
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
break;
case 4: /* output selected registers of all pipes */
for (i = 0; i < num_pipes; i++)
@@ -401,21 +401,14 @@
case 91: /* output testbus register, BAM global regisers
and registers of all pipes */
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
print_bam_pipe_selected_reg(vir_addr, i);
break;
case 92: /* output testbus register, BAM global regisers
and registers of selected pipes */
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (bam_pipe_sel & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (bam_pipe_sel & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -425,11 +418,7 @@
if (desc_option == 0)
desc_option = 1;
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (bam_pipe_sel & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (bam_pipe_sel & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -443,11 +432,9 @@
if (desc_option == 0)
desc_option = 1;
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (bam_pipe_sel & (1UL << i)) {
- print_bam_pipe_reg(vir_addr, i);
print_bam_pipe_selected_reg(vir_addr, i);
print_bam_pipe_desc_fifo(vir_addr, i,
desc_option);
@@ -456,11 +443,7 @@
case 95: /* output registers and desc FIFOs
of selected pipes: format 1 */
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (bam_pipe_sel & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (bam_pipe_sel & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -471,11 +454,9 @@
case 96: /* output registers and desc FIFOs
of selected pipes: format 2 */
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (bam_pipe_sel & (1UL << i)) {
- print_bam_pipe_reg(vir_addr, i);
print_bam_pipe_selected_reg(vir_addr, i);
print_bam_pipe_desc_fifo(vir_addr, i, 0);
}
@@ -483,11 +464,7 @@
case 97: /* output registers, desc FIFOs and partial data blocks
of selected pipes: format 1 */
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (bam_pipe_sel & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (bam_pipe_sel & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -501,11 +478,9 @@
case 98: /* output registers, desc FIFOs and partial data blocks
of selected pipes: format 2 */
print_bam_test_bus_reg(vir_addr, testbus_sel);
- print_bam_reg(vir_addr);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (bam_pipe_sel & (1UL << i)) {
- print_bam_pipe_reg(vir_addr, i);
print_bam_pipe_selected_reg(vir_addr, i);
print_bam_pipe_desc_fifo(vir_addr, i, 0);
print_bam_pipe_desc_fifo(vir_addr, i, 100);
@@ -516,7 +491,7 @@
print_bam_reg(vir_addr);
for (i = 0; i < num_pipes; i++)
print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
print_bam_pipe_selected_reg(vir_addr, i);
for (i = 0; i < num_pipes; i++)
@@ -674,7 +649,7 @@
/* Get the debug info of BAM registers and descriptor FIFOs */
int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
- u32 tb_sel, u8 desc_sel)
+ u32 tb_sel, u32 desc_sel)
{
int res = 0;
struct sps_bam *bam;
@@ -700,6 +675,8 @@
vir_addr = bam->base;
num_pipes = bam->props.num_pipes;
+ SPS_INFO("sps:<bam-addr> dump BAM:0x%x.\n", bam->props.phys_addr);
+
switch (option) {
case 1: /* output all registers of this BAM */
print_bam_reg(vir_addr);
@@ -710,7 +687,7 @@
print_bam_reg(vir_addr);
break;
case 3: /* output selected BAM-level registers */
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
break;
case 4: /* output selected registers of all pipes */
for (i = 0; i < num_pipes; i++)
@@ -784,21 +761,14 @@
case 91: /* output testbus register, BAM global regisers
and registers of all pipes */
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
print_bam_pipe_selected_reg(vir_addr, i);
break;
case 92: /* output testbus register, BAM global regisers
and registers of selected pipes */
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (para & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (para & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -808,11 +778,7 @@
if (desc_sel == 0)
desc_sel = 1;
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (para & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (para & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -826,11 +792,9 @@
if (desc_sel == 0)
desc_sel = 1;
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (para & (1UL << i)) {
- print_bam_pipe_reg(vir_addr, i);
print_bam_pipe_selected_reg(vir_addr, i);
print_bam_pipe_desc_fifo(vir_addr, i,
desc_sel);
@@ -839,11 +803,7 @@
case 95: /* output registers and desc FIFOs
of selected pipes: format 1 */
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (para & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (para & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -854,11 +814,9 @@
case 96: /* output registers and desc FIFOs
of selected pipes: format 2 */
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (para & (1UL << i)) {
- print_bam_pipe_reg(vir_addr, i);
print_bam_pipe_selected_reg(vir_addr, i);
print_bam_pipe_desc_fifo(vir_addr, i, 0);
}
@@ -866,11 +824,7 @@
case 97: /* output registers, desc FIFOs and partial data blocks
of selected pipes: format 1 */
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- for (i = 0; i < num_pipes; i++)
- if (para & (1UL << i))
- print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (para & (1UL << i))
print_bam_pipe_selected_reg(vir_addr, i);
@@ -884,11 +838,9 @@
case 98: /* output registers, desc FIFOs and partial data blocks
of selected pipes: format 2 */
print_bam_test_bus_reg(vir_addr, tb_sel);
- print_bam_reg(vir_addr);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
if (para & (1UL << i)) {
- print_bam_pipe_reg(vir_addr, i);
print_bam_pipe_selected_reg(vir_addr, i);
print_bam_pipe_desc_fifo(vir_addr, i, 0);
print_bam_pipe_desc_fifo(vir_addr, i, 100);
@@ -899,7 +851,7 @@
print_bam_reg(vir_addr);
for (i = 0; i < num_pipes; i++)
print_bam_pipe_reg(vir_addr, i);
- print_bam_selected_reg(vir_addr);
+ print_bam_selected_reg(vir_addr, bam->props.ee);
for (i = 0; i < num_pipes; i++)
print_bam_pipe_selected_reg(vir_addr, i);
for (i = 0; i < num_pipes; i++)
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 5ad281d..31d1a78 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -403,8 +403,9 @@
}
dev->state |= BAM_STATE_ENABLED;
- SPS_INFO("sps:BAM 0x%x enabled: ver:0x%x, number of pipes:%d",
- BAM_ID(dev), dev->version, dev->props.num_pipes);
+ SPS_INFO("sps:BAM 0x%x (va:0x%x) enabled: ver:0x%x, number of pipes:%d",
+ BAM_ID(dev), (u32) dev->base, dev->version,
+ dev->props.num_pipes);
return 0;
}
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 5b70fb0..8da3b40 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -40,6 +40,8 @@
/* "Clear" value for the connection parameter struct */
#define SPSRM_CLEAR 0xcccccccc
+#define MAX_MSG_LEN 80
+
extern u32 d_type;
#ifdef CONFIG_DEBUG_FS
@@ -48,25 +50,28 @@
extern u8 debug_level_option;
extern u8 print_limit_option;
-#define MAX_MSG_LEN 80
#define SPS_DEBUGFS(msg, args...) do { \
char buf[MAX_MSG_LEN]; \
snprintf(buf, MAX_MSG_LEN, msg"\n", ##args); \
sps_debugfs_record(buf); \
} while (0)
#define SPS_ERR(msg, args...) do { \
- if (unlikely(print_limit_option > 2)) \
- pr_err_ratelimited(msg, ##args); \
- else \
- pr_err(msg, ##args); \
+ if (logging_option != 1) { \
+ if (unlikely(print_limit_option > 2)) \
+ pr_err_ratelimited(msg, ##args); \
+ else \
+ pr_err(msg, ##args); \
+ } \
if (unlikely(debugfs_record_enabled)) \
SPS_DEBUGFS(msg, ##args); \
} while (0)
#define SPS_INFO(msg, args...) do { \
- if (unlikely(print_limit_option > 1)) \
- pr_info_ratelimited(msg, ##args); \
- else \
- pr_info(msg, ##args); \
+ if (logging_option != 1) { \
+ if (unlikely(print_limit_option > 1)) \
+ pr_info_ratelimited(msg, ##args); \
+ else \
+ pr_info(msg, ##args); \
+ } \
if (unlikely(debugfs_record_enabled)) \
SPS_DEBUGFS(msg, ##args); \
} while (0)
@@ -192,7 +197,7 @@
void print_bam_pipe_reg(void *, u32);
/* output the content of selected BAM-level registers */
-void print_bam_selected_reg(void *);
+void print_bam_selected_reg(void *, u32);
/* output the content of selected BAM pipe registers */
void print_bam_pipe_selected_reg(void *, u32);
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 16c47ba..a5fac9e 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -52,6 +52,28 @@
struct sps_connect *sps_connections;
};
+/**
+* struct usb_bam_ctx_type - represents the usb bam driver entity
+* @usb_bam_sps: holds the sps pipes the usb bam driver holds
+* against the sps driver.
+* @usb_bam_pdev: the platfrom device that represents the usb bam.
+* @usb_bam_wq: Worqueue used for managing states of reset against
+* a peer bam.
+* @qscratch_ram1_reg: The memory region mapped to the qscratch
+* registers.
+* @max_connections: The maximum number of pipes that are configured
+* in the platform data.
+* @mem_clk: Clock that controls the usb bam driver memory in
+* case the usb bam uses its private memory for the pipes.
+* @mem_iface_clk: Clock that controls the usb bam private memory in
+* case the usb bam uses its private memory for the pipes.
+* @qdss_core_name: Stores the name of the core ("ssusb", "hsusb" or "hsic")
+* that it used as a peer of the qdss in bam2bam mode.
+* @h_bam: This array stores for each BAM ("ssusb", "hsusb" or "hsic") the
+* handle/device of the sps driver.
+* @pipes_enabled_per_bam: This array stores for each BAM
+* ("ssusb", "hsusb" or "hsic") the number of pipes currently enabled.
+*/
struct usb_bam_ctx_type {
struct usb_bam_sps_type usb_bam_sps;
struct platform_device *usb_bam_pdev;
@@ -61,8 +83,8 @@
struct clk *mem_clk;
struct clk *mem_iface_clk;
char qdss_core_name[USB_BAM_MAX_STR_LEN];
- char bam_enabled_list[USB_BAM_MAX_STR_LEN];
u32 h_bam[MAX_BAMS];
+ u8 pipes_enabled_per_bam[MAX_BAMS];
};
static char *bam_enable_strings[3] = {
@@ -442,7 +464,6 @@
int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
int ret;
- enum usb_bam bam;
struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
struct msm_usb_bam_platform_data *pdata;
@@ -467,13 +488,11 @@
pr_err("idx is wrong %d", idx);
return -EINVAL;
}
- bam = pipe_connect->bam_type;
- if (bam < 0)
- return -EINVAL;
- /* Check if BAM requires RESET before connect */
- if (pdata->reset_on_connect[bam] == true)
- sps_device_reset(ctx.h_bam[bam]);
+ /* Check if BAM requires RESET before connect and reset of first pipe */
+ if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
+ (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
+ sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
ret = connect_pipe(idx, bam_pipe_idx);
if (ret) {
@@ -482,6 +501,7 @@
}
pipe_connect->enabled = 1;
+ ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
return 0;
}
@@ -548,6 +568,8 @@
u8 idx;
struct usb_bam_pipe_connect *pipe_connect;
int ret;
+ struct msm_usb_bam_platform_data *pdata =
+ ctx.usb_bam_pdev->dev.platform_data;
if (!ipa_params) {
pr_err("%s: Invalid ipa params\n",
@@ -573,6 +595,11 @@
return 0;
}
+ /* Check if BAM requires RESET before connect and reset of first pipe */
+ if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
+ (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
+ sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+
ret = connect_pipe_ipa(idx, ipa_params);
ipa_rm_request_resource(IPA_RM_RESOURCE_USB_PROD);
@@ -582,6 +609,7 @@
}
pipe_connect->enabled = 1;
+ ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
return 0;
}
@@ -799,6 +827,11 @@
}
pipe_connect->enabled = 0;
+ if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
+ pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
+ __func__, pipe_connect->bam_type);
+ else
+ ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
return 0;
}
@@ -993,6 +1026,7 @@
__func__);
goto err;
}
+ bam = usb_bam_connections[i].bam_type;
rc = of_property_read_u32(node, "qcom,peer-bam",
&usb_bam_connections[i].peer_bam);
@@ -1220,6 +1254,9 @@
usb_bam_work);
}
+ for (i = 0; i < MAX_BAMS; i++)
+ ctx.pipes_enabled_per_bam[i] = 0;
+
spin_lock_init(&usb_bam_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 08cf71e..cb5be3d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -486,7 +486,7 @@
static int calib_vadc(struct qpnp_bms_chip *chip)
{
- int rc;
+ int rc, raw_0625, raw_1250;
struct qpnp_vadc_result result;
rc = qpnp_vadc_read(REF_625MV, &result);
@@ -494,16 +494,19 @@
pr_debug("vadc read failed with rc = %d\n", rc);
return rc;
}
- chip->vadc_v0625 = result.physical;
+ raw_0625 = result.adc_code;
rc = qpnp_vadc_read(REF_125V, &result);
if (rc) {
pr_debug("vadc read failed with rc = %d\n", rc);
return rc;
}
- chip->vadc_v1250 = result.physical;
- pr_debug("vadc calib: 0625 = %d, 1250 = %d\n",
- chip->vadc_v0625, chip->vadc_v1250);
+ raw_1250 = result.adc_code;
+ chip->vadc_v0625 = vadc_reading_to_uv(raw_0625);
+ chip->vadc_v1250 = vadc_reading_to_uv(raw_1250);
+ pr_debug("vadc calib: 0625 = %d raw (%d uv), 1250 = %d raw (%d uv)\n",
+ raw_0625, chip->vadc_v0625,
+ raw_1250, chip->vadc_v1250);
return 0;
}
@@ -1608,10 +1611,9 @@
pr_debug("SOC before adjustment = %d\n", soc);
new_calculated_soc = adjust_soc(chip, ¶ms, soc, batt_temp);
- /* clamp soc due to BMS HW inaccuracies in pm8941v2.0 */
- if (chip->revision1 == 0 && chip->revision2 == 0)
- new_calculated_soc = clamp_soc_based_on_voltage(chip,
- new_calculated_soc);
+ /* always clamp soc due to BMS hw/sw immaturities */
+ new_calculated_soc = clamp_soc_based_on_voltage(chip,
+ new_calculated_soc);
done_calculating:
if (new_calculated_soc != chip->calculated_soc
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index f8b06bf..b479477 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -190,8 +190,8 @@
* @safe_current: battery safety current setting
* @maxinput_usb_ma: Maximum Input current USB
* @maxinput_dc_ma: Maximum Input current DC
- * @warm_bat_degc Warm battery temperature in degree Celsius
- * @cool_bat_degc Cool battery temperature in degree Celsius
+ * @warm_bat_decidegc Warm battery temperature in degree Celsius
+ * @cool_bat_decidegc Cool battery temperature in degree Celsius
* @revision: PMIC revision
* @thermal_levels amount of thermal mitigation levels
* @thermal_mitigation thermal mitigation level values
@@ -242,8 +242,8 @@
unsigned int term_current;
unsigned int maxinput_usb_ma;
unsigned int maxinput_dc_ma;
- unsigned int warm_bat_degc;
- unsigned int cool_bat_degc;
+ unsigned int warm_bat_decidegc;
+ unsigned int cool_bat_decidegc;
unsigned int safe_current;
unsigned int revision;
unsigned int thermal_levels;
@@ -546,6 +546,12 @@
if (chip->batt_present ^ batt_present) {
chip->batt_present = batt_present;
power_supply_changed(&chip->batt_psy);
+
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ && batt_present) {
+ if (qpnp_adc_tm_channel_measure(&chip->adc_param))
+ pr_err("request ADC error\n");
+ }
}
if (chip->bms_psy)
@@ -1019,13 +1025,15 @@
/* Only honour requests while USB is present */
if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+ chip->usb_psy->get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
if (ret.intval <= 2 && !chip->use_default_batt_values &&
get_prop_batt_present(chip)) {
- qpnp_chg_usb_suspend_enable(chip, 1);
qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
+ qpnp_chg_usb_suspend_enable(chip, 1);
} else {
- qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
qpnp_chg_usb_suspend_enable(chip, 0);
+ qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
}
}
@@ -1305,56 +1313,74 @@
}
}
-#define TEMP_HYSTERISIS_DEGC 2
+#define HYSTERISIS_DECIDEGC 20
static void
qpnp_chg_adc_notification(enum qpnp_tm_state state, void *ctx)
{
struct qpnp_chg_chip *chip = ctx;
bool bat_warm = 0, bat_cool = 0;
+ int temp;
if (state >= ADC_TM_STATE_NUM) {
pr_err("invalid notification %d\n", state);
return;
}
- pr_debug("state = %s\n", state == ADC_TM_HIGH_STATE ? "high" : "low");
+ temp = get_prop_batt_temp(chip);
- if (state == ADC_TM_HIGH_STATE) {
- if (!chip->bat_is_warm) {
+ pr_debug("temp = %d state = %s\n", temp,
+ state == ADC_TM_WARM_STATE ? "warm" : "cool");
+
+ if (state == ADC_TM_WARM_STATE) {
+ if (temp > chip->warm_bat_decidegc) {
bat_warm = true;
bat_cool = false;
chip->adc_param.low_temp =
- chip->warm_bat_degc - TEMP_HYSTERISIS_DEGC;
- } else if (chip->bat_is_cool) {
+ chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC;
+ chip->adc_param.state_request =
+ ADC_TM_COOL_THR_ENABLE;
+ } else if (temp >
+ chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC){
bat_warm = false;
bat_cool = false;
- chip->adc_param.high_temp = chip->warm_bat_degc;
+
+ chip->adc_param.low_temp = chip->cool_bat_decidegc;
+ chip->adc_param.high_temp = chip->warm_bat_decidegc;
+ chip->adc_param.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
}
} else {
- if (!chip->bat_is_cool) {
+ if (temp < chip->cool_bat_decidegc) {
+ bat_warm = false;
bat_cool = true;
- bat_warm = false;
chip->adc_param.high_temp =
- chip->cool_bat_degc + TEMP_HYSTERISIS_DEGC;
- } else if (chip->bat_is_warm) {
- bat_cool = false;
+ chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC;
+ chip->adc_param.state_request =
+ ADC_TM_WARM_THR_ENABLE;
+ } else if (temp >
+ chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC){
bat_warm = false;
- chip->adc_param.low_temp = chip->cool_bat_degc;
+ bat_cool = false;
+
+ chip->adc_param.low_temp = chip->cool_bat_decidegc;
+ chip->adc_param.high_temp = chip->warm_bat_decidegc;
+ chip->adc_param.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
}
}
if (chip->bat_is_cool ^ bat_cool || chip->bat_is_warm ^ bat_warm) {
+ chip->bat_is_cool = bat_cool;
+ chip->bat_is_warm = bat_warm;
+
/* set appropriate voltages and currents */
qpnp_chg_set_appropriate_vddmax(chip);
qpnp_chg_set_appropriate_battery_current(chip);
qpnp_chg_set_appropriate_vbatdet(chip);
-
- chip->bat_is_cool = bat_cool;
- chip->bat_is_warm = bat_warm;
}
- /* re-arm ADC interrupt */
- qpnp_adc_tm_channel_measure(&chip->adc_param);
+ if (qpnp_adc_tm_channel_measure(&chip->adc_param))
+ pr_err("request ADC error\n");
}
static int
@@ -1744,8 +1770,8 @@
/* Get the warm-bat-degc property */
rc = of_property_read_u32(spmi->dev.of_node,
- "qcom,chg-warm-bat-degc",
- &chip->warm_bat_degc);
+ "qcom,chg-warm-bat-decidegc",
+ &chip->warm_bat_decidegc);
if (rc && rc != -EINVAL) {
pr_err("Error reading warm-bat-degc property %d\n", rc);
goto fail_chg_enable;
@@ -1753,14 +1779,14 @@
/* Get the cool-bat-degc property */
rc = of_property_read_u32(spmi->dev.of_node,
- "qcom,chg-cool-bat-degc",
- &chip->cool_bat_degc);
+ "qcom,chg-cool-bat-decidegc",
+ &chip->cool_bat_decidegc);
if (rc && rc != -EINVAL) {
pr_err("Error reading cool-bat-degc property %d\n", rc);
goto fail_chg_enable;
}
- if (chip->cool_bat_degc && chip->warm_bat_degc) {
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
rc = qpnp_adc_tm_is_ready();
if (rc) {
pr_err("tm not ready %d\n", rc);
@@ -1998,19 +2024,22 @@
}
}
- if (chip->cool_bat_degc && chip->warm_bat_degc) {
- chip->adc_param.low_temp = chip->cool_bat_degc;
- chip->adc_param.high_temp = chip->warm_bat_degc;
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
+ chip->adc_param.low_temp = chip->cool_bat_decidegc;
+ chip->adc_param.high_temp = chip->warm_bat_decidegc;
chip->adc_param.timer_interval = ADC_MEAS2_INTERVAL_1S;
chip->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
chip->adc_param.btm_ctx = chip;
chip->adc_param.threshold_notification =
qpnp_chg_adc_notification;
chip->adc_param.channel = LR_MUX1_BATT_THERM;
- rc = qpnp_adc_tm_channel_measure(&chip->adc_param);
- if (rc) {
- pr_err("request ADC error %d\n", rc);
- goto fail_chg_enable;
+
+ if (get_prop_batt_present(chip)) {
+ rc = qpnp_adc_tm_channel_measure(&chip->adc_param);
+ if (rc) {
+ pr_err("request ADC error %d\n", rc);
+ goto fail_chg_enable;
+ }
}
}
@@ -2039,6 +2068,10 @@
qpnp_charger_remove(struct spmi_device *spmi)
{
struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ && chip->batt_present) {
+ qpnp_adc_tm_disable_chan_meas(&chip->adc_param);
+ }
dev_set_drvdata(&spmi->dev, NULL);
kfree(chip);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 71554ed..9b2f554 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -64,60 +64,6 @@
printk(x); \
} while (0)
-
-static int can_use_cma_pages(struct zone *zone, gfp_t gfp_mask)
-{
- int can_use = 0;
- int mtype = allocflags_to_migratetype(gfp_mask);
- int i = 0;
- int *mtype_fallbacks = get_migratetype_fallbacks(mtype);
-
- if (is_migrate_cma(mtype)) {
- can_use = 1;
- } else {
- for (i = 0;; i++) {
- int fallbacktype = mtype_fallbacks[i];
-
- if (is_migrate_cma(fallbacktype)) {
- can_use = 1;
- break;
- }
-
- if (fallbacktype == MIGRATE_RESERVE)
- break;
- }
- }
- return can_use;
-}
-
-
-static int nr_free_zone_pages(struct zone *zone, gfp_t gfp_mask)
-{
- int sum = zone_page_state(zone, NR_FREE_PAGES);
-
- if (!can_use_cma_pages(zone, gfp_mask))
- sum -= zone_page_state(zone, NR_FREE_CMA_PAGES);
-
- return sum;
-}
-
-
-static int nr_free_pages(gfp_t gfp_mask)
-{
- struct zoneref *z;
- struct zone *zone;
- int sum = 0;
-
- struct zonelist *zonelist = node_zonelist(numa_node_id(), gfp_mask);
-
- for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
- sum += nr_free_zone_pages(zone, gfp_mask);
- }
-
- return sum;
-}
-
-
static int test_task_flag(struct task_struct *p, int flag)
{
struct task_struct *t = p;
@@ -160,15 +106,6 @@
other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM);
- if (nr_to_scan > 0 && other_free > other_file) {
- /*
- * If the number of free pages is going to affect the decision
- * of which process is selected then ensure only free pages
- * which can satisfy the request are considered.
- */
- other_free = nr_free_pages(sc->gfp_mask);
- }
-
if (lowmem_adj_size < array_size)
array_size = lowmem_adj_size;
if (lowmem_minfree_size < array_size)
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 7d3664a..f7e5eee 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -74,6 +74,9 @@
#define TSENS_EEPROM_8X26_2(n) ((n) + 0x444)
#define TSENS_8X26_MAIN_CALIB_ADDR_RANGE 4
+#define TSENS_EEPROM_8X10_1(n) ((n) + 0x1a4)
+#define TSENS_EEPROM_8X10_1_OFFSET 8
+
/* TSENS calibration Mask data */
#define TSENS_BASE1_MASK 0xff
#define TSENS0_POINT1_MASK 0x3f00
@@ -191,6 +194,19 @@
#define TSENS5_8X26_POINT2_SHIFT 26
#define TSENS6_8X26_POINT2_SHIFT 17
+#define TSENS_8X10_CAL_SEL_SHIFT 28
+#define TSENS_8X10_BASE1_SHIFT 8
+#define TSENS0_8X10_POINT1_SHIFT 16
+#define TSENS0_8X10_POINT2_SHIFT 22
+#define TSENS1_8X10_POINT2_SHIFT 6
+#define TSENS_8X10_BASE0_MASK 0xf
+#define TSENS_8X10_BASE1_MASK 0xf0
+#define TSENS0_8X10_POINT1_MASK 0x3f0000
+#define TSENS0_8X10_POINT2_MASK 0xfc00000
+#define TSENS_8X10_TSENS_CAL_SEL 0x70000000
+#define TSENS1_8X10_POINT1_MASK 0x3f
+#define TSENS1_8X10_POINT2_MASK 0xfc0
+
#define TSENS_BIT_APPEND 0x3
#define TSENS_CAL_DEGC_POINT1 30
#define TSENS_CAL_DEGC_POINT2 120
@@ -599,6 +615,98 @@
TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
}
+static int tsens_calib_8x10_sensors(void)
+{
+ int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
+ int tsens0_point2 = 0, tsens1_point2 = 0;
+ int tsens_base1_data = 0, tsens_calibration_mode = 0;
+ uint32_t calib_data[2];
+ uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2];
+
+ if (tmdev->calibration_less_mode)
+ goto calibration_less_mode;
+
+ calib_data[0] = readl_relaxed(
+ TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr));
+ calib_data[1] = readl_relaxed(
+ (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
+ TSENS_EEPROM_8X10_1_OFFSET));
+
+ tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL)
+ >> TSENS_8X10_CAL_SEL_SHIFT;
+
+ if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
+ (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
+ tsens_base0_data = (calib_data[0] & TSENS_8X10_BASE0_MASK);
+ tsens0_point1 = (calib_data[0] & TSENS0_8X10_POINT1_MASK) >>
+ TSENS0_8X10_POINT1_SHIFT;
+ tsens1_point1 = calib_data[1] & TSENS1_8X10_POINT1_MASK;
+ } else
+ goto calibration_less_mode;
+
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ tsens_base1_data = (calib_data[0] & TSENS_8X10_BASE1_MASK) >>
+ TSENS_8X10_BASE1_SHIFT;
+ tsens0_point2 = (calib_data[0] & TSENS0_8X10_POINT2_MASK) >>
+ TSENS0_8X10_POINT2_SHIFT;
+ tsens1_point2 = (calib_data[1] & TSENS1_8X10_POINT2_MASK) >>
+ TSENS1_8X10_POINT2_SHIFT;
+ }
+
+ if (tsens_calibration_mode == 0) {
+calibration_less_mode:
+ pr_debug("TSENS is calibrationless mode\n");
+ for (i = 0; i < tmdev->tsens_num_sensor; i++)
+ calib_tsens_point2_data[i] = 780;
+ calib_tsens_point1_data[0] = 595;
+ calib_tsens_point1_data[1] = 629;
+ goto compute_intercept_slope;
+ }
+
+ if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
+ (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
+ calib_tsens_point1_data[0] =
+ ((((tsens_base0_data) + tsens0_point1) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point1_data[1] =
+ ((((tsens_base0_data) + tsens1_point1) << 2) |
+ TSENS_BIT_APPEND);
+ }
+
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ pr_debug("two point calibration calculation\n");
+ calib_tsens_point2_data[0] =
+ (((tsens_base1_data + tsens0_point2) << 2) |
+ TSENS_BIT_APPEND);
+ calib_tsens_point2_data[1] =
+ (((tsens_base1_data + tsens1_point2) << 2) |
+ TSENS_BIT_APPEND);
+ }
+
+compute_intercept_slope:
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ int32_t num = 0, den = 0;
+ tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
+ tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+ temp_120_degc - temp_30_degc (x2 - x1) */
+ num = tmdev->sensor[i].calib_data_point2 -
+ tmdev->sensor[i].calib_data_point1;
+ num *= tmdev->tsens_factor;
+ den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
+ tmdev->sensor[i].slope_mul_tsens_factor = num/den;
+ }
+ tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
+ tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
+ tmdev->sensor[i].slope_mul_tsens_factor);
+ INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
+ tmdev->prev_reading_avail = false;
+ }
+
+ return 0;
+}
+
static int tsens_calib_8x26_sensors(void)
{
int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
@@ -627,7 +735,6 @@
if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
(tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
- pr_debug("backup one point calibrationless mode\n");
tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
>> TSENS_8X26_BASE0_SHIFT;
tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
@@ -647,7 +754,6 @@
goto calibration_less_mode;
if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
- pr_debug("backup two point calibrationless mode\n");
tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
TSENS0_8X26_POINT2_SHIFT;
@@ -670,10 +776,10 @@
pr_debug("TSENS is calibrationless mode\n");
for (i = 0; i < tmdev->tsens_num_sensor; i++)
calib_tsens_point2_data[i] = 780;
- calib_tsens_point1_data[0] = 502;
- calib_tsens_point1_data[1] = 509;
- calib_tsens_point1_data[2] = 503;
- calib_tsens_point1_data[3] = 509;
+ calib_tsens_point1_data[0] = 595;
+ calib_tsens_point1_data[1] = 625;
+ calib_tsens_point1_data[2] = 553;
+ calib_tsens_point1_data[3] = 578;
calib_tsens_point1_data[4] = 505;
calib_tsens_point1_data[5] = 509;
calib_tsens_point1_data[6] = 507;
@@ -682,7 +788,6 @@
if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
- pr_debug("one and two point calibration calculation\n");
calib_tsens_point1_data[0] =
((((tsens_base0_data) + tsens0_point1) << 2) |
TSENS_BIT_APPEND);
@@ -800,7 +905,6 @@
TSENS_TWO_POINT_CALIB) ||
(tsens_calibration_mode ==
TSENS_ONE_POINT_CALIB_OPTION_2)) {
- pr_debug("backup one point calibrationless mode\n");
tsens_base1_data = (calib_data_backup[0] &
TSENS_BASE1_MASK);
tsens0_point1 = (calib_data_backup[0] &
@@ -833,7 +937,6 @@
goto calibration_less_mode;
if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
- pr_debug("backup two point calibrationless mode\n");
tsens_base2_data = (calib_data_backup[2] &
TSENS_BASE2_BACKUP_MASK) >>
TSENS_POINT2_BASE_BACKUP_SHIFT;
@@ -879,7 +982,6 @@
(tsens_calibration_mode ==
TSENS_ONE_POINT_CALIB_OPTION_2) ||
(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
- pr_debug("TSENS is one point calibrationless mode\n");
tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
TSENS0_POINT1_SHIFT;
@@ -905,7 +1007,6 @@
goto calibration_less_mode;
if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
- pr_debug("TSENS is two point calibrationless mode\n");
tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
TSENS_POINT2_BASE_SHIFT;
tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
@@ -951,7 +1052,6 @@
}
if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
- pr_debug("old one point calibration calculation\n");
calib_tsens_point1_data[0] =
(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+ tsens0_point1;
@@ -989,7 +1089,6 @@
if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
- pr_debug("one and two point calibration calculation\n");
calib_tsens_point1_data[0] =
((((tsens_base1_data) + tsens0_point1) << 2) |
TSENS_BIT_APPEND);
@@ -1097,6 +1196,8 @@
rc = tsens_calib_8974_sensors();
else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
rc = tsens_calib_8x26_sensors();
+ else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10)
+ rc = tsens_calib_8x10_sensors();
else
rc = -ENODEV;
@@ -1163,7 +1264,7 @@
"qcom,calibration-less-mode");
tmdev->calib_mode = calib_type;
tmdev->tsens_local_init = of_property_read_bool(of_node,
- "qcom,tsens_local_init");
+ "qcom,tsens-local-init");
tmdev->tsens_irq = platform_get_irq(pdev, 0);
if (tmdev->tsens_irq < 0) {
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index e84220f..e7d2e0f 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -35,7 +35,7 @@
#include <linux/platform_device.h>
/* QPNP VADC TM register definition */
-#define QPNP_REVISION3 0x3
+#define QPNP_REVISION3 0x2
#define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT 2
#define QPNP_STATUS1 0x8
#define QPNP_STATUS1_OP_MODE 4
@@ -182,6 +182,7 @@
bool thermal_node;
bool low_thr_notify;
bool high_thr_notify;
+ uint32_t scale_type;
};
struct qpnp_adc_tm_drv {
@@ -457,7 +458,7 @@
return rc;
}
-static int32_t qpnp_adc_tm_meas_int_update(uint16_t addr,
+static int32_t qpnp_adc_tm_reg_update(uint16_t addr,
u8 mask, bool state)
{
u8 reg_value = 0;
@@ -484,7 +485,7 @@
return rc;
}
-static int32_t qpnp_adc_tm_usbid_btm_thr_en(uint32_t btm_chan,
+static int32_t qpnp_adc_tm_thr_update(uint32_t btm_chan,
struct qpnp_vadc_chan_properties *chan_prop)
{
int rc = 0;
@@ -519,7 +520,7 @@
if (rc < 0)
pr_err("high threshold msb setting failed\n");
- pr_debug("client requested high:%d and low:%d\n",
+ pr_debug("client requested low:%d and high:%d\n",
chan_prop->low_thr, chan_prop->high_thr);
return rc;
@@ -543,7 +544,7 @@
i++;
}
- if ((i == adc_tm->max_channels_available) && (!chan_found)) {
+ if (!chan_found) {
pr_err("Channel not found\n");
return -EINVAL;
}
@@ -551,7 +552,7 @@
sensor_mask = 1 << chan_idx;
if (!adc_tm->sensor[chan_idx].thermal_node) {
/* Update low and high notification thresholds */
- rc = qpnp_adc_tm_usbid_btm_thr_en(btm_chan,
+ rc = qpnp_adc_tm_thr_update(btm_chan,
chan_prop);
if (rc < 0) {
pr_err("setting chan:%d threshold failed\n", btm_chan);
@@ -565,7 +566,7 @@
pr_debug("low sensor mask:%x with state:%d\n",
sensor_mask, chan_prop->state_request);
/* Enable low threshold's interrupt */
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
if (rc < 0) {
pr_err("low thr enable err:%d\n", btm_chan);
@@ -579,7 +580,7 @@
ADC_TM_HIGH_LOW_THR_ENABLE)) {
/* Enable high threshold's interrupt */
pr_debug("high sensor mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
if (rc < 0) {
pr_err("high thr enable err:%d\n", btm_chan);
@@ -589,7 +590,7 @@
}
/* Enable corresponding BTM channel measurement */
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
if (rc < 0) {
pr_err("multi measurement en failed\n");
@@ -677,7 +678,7 @@
/* Recurring interval measurement enable */
rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
op_cntrl, true);
if (rc < 0) {
pr_err("adc-tm meas interval op configure failed\n");
@@ -766,7 +767,7 @@
return rc;
}
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("multi measurement update failed\n");
@@ -955,6 +956,47 @@
return 0;
}
+static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
+{
+ /* Battery therm's warm temperature translates to low voltage */
+ if (adc_tm->low_thr_notify) {
+ /* HIGH_STATE = WARM_TEMP for battery client */
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->low_thr_notify = false;
+ }
+
+ /* Battery therm's cool temperature translates to high voltage */
+ if (adc_tm->high_thr_notify) {
+ /* LOW_STATE = COOL_TEMP for battery client */
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->high_thr_notify = false;
+ }
+
+ return;
+}
+
+static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
+{
+ /* For non batt therm clients */
+ if (adc_tm->low_thr_notify) {
+ pr_debug("notify kernel with low state\n");
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->low_thr_notify = false;
+ }
+
+ if (adc_tm->high_thr_notify) {
+ pr_debug("notify kernel with high state\n");
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->high_thr_notify = false;
+ }
+
+ return;
+}
+
static void notify_adc_tm_fn(struct work_struct *work)
{
struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
@@ -966,19 +1008,10 @@
pr_debug("notifying uspace client\n");
} else {
if (adc_tm->btm_param->threshold_notification != NULL) {
- if (adc_tm->low_thr_notify) {
- pr_debug("notify kernel with low state\n");
- adc_tm->btm_param->threshold_notification(
- ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
- adc_tm->low_thr_notify = false;
- }
-
- if (adc_tm->high_thr_notify) {
- pr_debug("notify kernel with high state\n");
- adc_tm->btm_param->threshold_notification(
- ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
- adc_tm->high_thr_notify = false;
- }
+ if (adc_tm->scale_type == SCALE_RBATT_THERM)
+ notify_battery_therm(adc_tm);
+ else
+ notify_clients(adc_tm);
}
}
@@ -1008,7 +1041,7 @@
/* low_thr (lower voltage) for higher temp */
thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
low_thr_int_chan_en;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, state);
if (rc)
pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
@@ -1017,7 +1050,7 @@
/* high_thr (higher voltage) for cooler temp */
thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
high_thr_int_chan_en;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, state);
if (rc)
pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
@@ -1090,7 +1123,7 @@
such as usb_id, vbatt, pmic_therm */
sensor_mask = 1 << sensor_num;
pr_debug("non thermal node - mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
@@ -1133,7 +1166,7 @@
such as usb_id, vbatt, pmic_therm */
pr_debug("non thermal node - mask:%x\n", sensor_mask);
sensor_mask = 1 << sensor_num;
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
@@ -1157,6 +1190,13 @@
}
}
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi meas disable for channel failed\n");
+ goto fail;
+ }
+
rc = qpnp_adc_tm_enable_if_channel_meas();
if (rc < 0) {
pr_err("re-enabling measurement failed\n");
@@ -1252,7 +1292,8 @@
{
struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
uint32_t channel, dt_index = 0, scale_type = 0;
- int rc = 0;
+ int rc = 0, i = 0;
+ bool chan_found = false;
if (!adc_tm || !adc_tm->adc_tm_initialized)
return -ENODEV;
@@ -1265,11 +1306,17 @@
mutex_lock(&adc_tm->adc->adc_lock);
channel = param->channel;
- while ((adc_tm->adc->adc_channels[dt_index].channel_num
- != channel) && (dt_index < adc_tm->max_channels_available))
- dt_index++;
+ while (i < adc_tm->max_channels_available) {
+ if (adc_tm->adc->adc_channels[i].channel_num ==
+ channel) {
+ dt_index = i;
+ chan_found = true;
+ i++;
+ } else
+ i++;
+ }
- if (dt_index >= adc_tm->max_channels_available) {
+ if (!chan_found) {
pr_err("not a valid ADC_TM channel\n");
rc = -EINVAL;
goto fail_unlock;
@@ -1290,11 +1337,11 @@
channel, scale_type, dt_index);
adc_tm->adc->amux_prop->amux_channel = channel;
adc_tm->adc->amux_prop->decimation =
- adc_tm->adc->adc_channels[channel].adc_decimation;
+ adc_tm->adc->adc_channels[dt_index].adc_decimation;
adc_tm->adc->amux_prop->hw_settle_time =
- adc_tm->adc->adc_channels[channel].hw_settle_time;
+ adc_tm->adc->adc_channels[dt_index].hw_settle_time;
adc_tm->adc->amux_prop->fast_avg_setup =
- adc_tm->adc->adc_channels[channel].fast_avg_setup;
+ adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
adc_tm->adc->amux_prop->mode_sel =
ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
@@ -1315,6 +1362,7 @@
}
adc_tm->sensor[dt_index].btm_param = param;
+ adc_tm->sensor[dt_index].scale_type = scale_type;
fail_unlock:
mutex_unlock(&adc_tm->adc->adc_lock);
@@ -1363,21 +1411,21 @@
btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("low threshold int write failed\n");
goto fail;
}
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("high threshold int enable failed\n");
goto fail;
}
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("multi measurement en failed\n");
@@ -1534,6 +1582,8 @@
adc_tm->sensor[sen_idx].vadc_channel_num =
adc_tm->adc->adc_channels[sen_idx].channel_num;
adc_tm->sensor[sen_idx].sensor_num = sen_idx;
+ pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
+ adc_tm->adc->adc_channels[sen_idx].channel_num);
if (thermal_node) {
/* Register with the thermal zone */
pr_debug("thermal node%x\n", btm_channel_num);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 64ef2db..9fad90c 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2086,16 +2086,25 @@
static void dwc3_id_work(struct work_struct *w)
{
struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, id_work);
+ int ret;
/* Give external client a chance to handle */
- if (!mdwc->ext_inuse) {
- if (usb_ext) {
- int ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
- dwc3_ext_notify_online);
- dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
- __func__, ret);
- mdwc->ext_inuse = (ret == 0);
+ if (!mdwc->ext_inuse && usb_ext) {
+ if (mdwc->pmic_id_irq)
+ disable_irq(mdwc->pmic_id_irq);
+
+ ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
+ dwc3_ext_notify_online);
+ dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
+ __func__, ret);
+
+ if (mdwc->pmic_id_irq) {
+ /* ID may have changed while IRQ disabled; update it */
+ mdwc->id_state = !!irq_read_line(mdwc->pmic_id_irq);
+ enable_irq(mdwc->pmic_id_irq);
}
+
+ mdwc->ext_inuse = (ret == 0);
}
if (!mdwc->ext_inuse) { /* notify OTG */
@@ -2107,10 +2116,14 @@
static irqreturn_t dwc3_pmic_id_irq(int irq, void *data)
{
struct dwc3_msm *mdwc = data;
+ enum dwc3_id_state id;
/* If we can't read ID line state for some reason, treat it as float */
- mdwc->id_state = !!irq_read_line(irq);
- queue_work(system_nrt_wq, &mdwc->id_work);
+ id = !!irq_read_line(irq);
+ if (mdwc->id_state != id) {
+ mdwc->id_state = id;
+ queue_work(system_nrt_wq, &mdwc->id_work);
+ }
return IRQ_HANDLED;
}
@@ -2370,7 +2383,7 @@
goto free_hs_ldo_init;
}
- msm->ext_xceiv.id = DWC3_ID_FLOAT;
+ msm->id_state = msm->ext_xceiv.id = DWC3_ID_FLOAT;
msm->ext_xceiv.otg_capability = of_property_read_bool(node,
"qcom,otg-capability");
msm->charger.charging_disabled = of_property_read_bool(node,
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index daf9a26..ca1f817 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -426,6 +426,9 @@
if (!init) {
init = true;
+ if (!work_busy(&dotg->sm_work))
+ schedule_work(&dotg->sm_work);
+
complete(&dotg->dwc3_xcvr_vbus_init);
dev_dbg(phy->dev, "XCVR: BSV init complete\n");
return;
@@ -610,8 +613,11 @@
* driver initialization. Wait for it.
*/
ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5);
- if (!ret)
+ if (!ret) {
dev_err(phy->dev, "%s: completion timeout\n", __func__);
+ /* We can safely assume no cable connected */
+ set_bit(ID, &dotg->inputs);
+ }
ext_xceiv = dotg->ext_xceiv;
dwc3_otg_reset(dotg);
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 52e3126..5a3d753 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -345,6 +345,7 @@
/* MBIM control descriptors */
(struct usb_descriptor_header *) &mbim_control_intf,
(struct usb_descriptor_header *) &mbim_header_desc,
+ (struct usb_descriptor_header *) &mbim_union_desc,
(struct usb_descriptor_header *) &mbb_desc,
(struct usb_descriptor_header *) &ext_mbb_desc,
(struct usb_descriptor_header *) &hs_mbim_notify_desc,
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 4b9dfbf..2dccca8 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -387,7 +387,7 @@
unsigned port_num;
enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
- u8 src_connection_idx, dst_connection_idx;
+ int src_connection_idx = 0, dst_connection_idx = 0;
struct usb_gadget *gadget = dev->cdev->gadget;
pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
@@ -439,7 +439,6 @@
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
- case USB_GADGET_XPORT_BAM:
case USB_GADGET_XPORT_BAM2BAM:
src_connection_idx = usb_bam_get_connection_idx(gadget->name,
A2_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
@@ -451,6 +450,7 @@
gsmd_ctrl_disconnect(&dev->port, port_num);
return ret;
}
+ case USB_GADGET_XPORT_BAM:
ret = gbam_connect(&dev->port, port_num,
dxport, src_connection_idx, dst_connection_idx);
if (ret) {
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index a710fef..7fafbc64 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,6 +1,7 @@
mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
mdss-mdp-objs += mdss_mdp_pp.o
mdss-mdp-objs += mdss_mdp_intf_video.o
+mdss-mdp-objs += mdss_mdp_intf_cmd.o
mdss-mdp-objs += mdss_mdp_intf_writeback.o
mdss-mdp-objs += mdss_mdp_rotator.o
mdss-mdp-objs += mdss_mdp_overlay.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index dd41638..c847ee6 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -90,6 +90,8 @@
u32 smp_mb_cnt;
u32 smp_mb_size;
+ u32 rot_block_size;
+
struct mdss_hw_settings *hw_settings;
struct mdss_mdp_pipe *vig_pipes;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index bfcd7ec..faf3e6f 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -25,6 +25,7 @@
#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_dsi.h"
+#include "mdss_debug.h"
static unsigned char *mdss_dsi_base;
@@ -250,32 +251,6 @@
return 0;
}
-static int mdss_dsi_ctrl_unprepare(struct mdss_panel_data *pdata)
-{
- struct mdss_panel_info *pinfo;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- int ret = 0;
-
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
- pinfo = &pdata->panel_info;
-
- mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
-
- ret = ctrl_pdata->off(pdata);
- if (ret) {
- pr_err("%s: Panel OFF failed\n", __func__);
- return ret;
- }
-
- return ret;
-}
-
static void mdss_dsi_put_dt_vreg_data(struct device *dev,
struct dss_module_power *module_power)
{
@@ -443,6 +418,10 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+ ctrl_pdata, ctrl_pdata->ndx);
+
mdss_dsi_clk_disable(pdata);
mdss_dsi_unprepare_clocks(ctrl_pdata);
@@ -514,6 +493,10 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n",
+ __func__, ctrl_pdata, ctrl_pdata->ndx);
+
pinfo = &pdata->panel_info;
ret = mdss_dsi_panel_power_on(pdata, 1);
@@ -597,6 +580,27 @@
wmb();
}
+ pr_debug("%s-:\n", __func__);
+ return 0;
+}
+
+static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ pr_debug("%s+:\n", __func__);
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+ mipi = &pdata->panel_info.mipi;
+
ret = ctrl_pdata->on(pdata);
if (ret) {
pr_err("%s: unable to initialize the panel\n", __func__);
@@ -605,6 +609,34 @@
mdss_dsi_op_mode_config(mipi->mode, pdata);
+ pr_debug("%s-:\n", __func__);
+
+ return ret;
+}
+
+static int mdss_dsi_blank(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ pr_debug("%s+:\n", __func__);
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+
+ ret = ctrl_pdata->off(pdata);
+ if (ret) {
+ pr_err("%s: Panel OFF failed\n", __func__);
+ return ret;
+ }
+
pr_debug("%s-:End\n", __func__);
return ret;
}
@@ -621,33 +653,27 @@
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ pr_debug("%s+:event=%d\n", __func__, event);
+
switch (event) {
case MDSS_EVENT_UNBLANK:
+ rc = mdss_dsi_on(pdata);
if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
- rc = mdss_dsi_on(pdata);
- } else {
- pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
- __func__, event,
- ctrl_pdata->on_cmds->ctrl_state);
- rc = -EINVAL;
+ rc = mdss_dsi_unblank(pdata);
}
break;
+ case MDSS_EVENT_PANEL_ON:
+ if (ctrl_pdata->on_cmds->ctrl_state == DSI_HS_MODE)
+ rc = mdss_dsi_unblank(pdata);
+ break;
case MDSS_EVENT_BLANK:
if (ctrl_pdata->off_cmds->ctrl_state == DSI_HS_MODE) {
- rc = mdss_dsi_ctrl_unprepare(pdata);
- } else {
- pr_debug("%s:event=%d,Unprepare not called.Ctrl_state: %d\n",
- __func__, event,
- ctrl_pdata->on_cmds->ctrl_state);
- rc = -EINVAL;
+ rc = mdss_dsi_blank(pdata);
}
break;
- case MDSS_EVENT_TIMEGEN_OFF:
+ case MDSS_EVENT_PANEL_OFF:
if (ctrl_pdata->off_cmds->ctrl_state == DSI_LP_MODE) {
- pr_debug("%s:event=%d, calling unprepare: ctrl_state: %d\n",
- __func__, event,
- ctrl_pdata->on_cmds->ctrl_state);
- rc = mdss_dsi_ctrl_unprepare(pdata);
+ rc = mdss_dsi_blank(pdata);
}
rc = mdss_dsi_off(pdata);
break;
@@ -665,6 +691,7 @@
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
}
+ pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc);
return rc;
}
@@ -674,8 +701,6 @@
u32 index;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- pr_debug("%s\n", __func__);
-
if (pdev->dev.of_node) {
struct resource *mdss_dsi_mres;
const char *ctrl_name;
@@ -789,7 +814,7 @@
struct device dsi_dev;
int mdss_dsi_retrieve_ctrl_resources(struct platform_device *pdev, int mode,
- unsigned char **ctrl_base)
+ struct mdss_dsi_ctrl_pdata *ctrl)
{
int rc = 0;
u32 index;
@@ -828,21 +853,25 @@
return -ENOMEM;
}
- *ctrl_base = ioremap(mdss_dsi_mres->start,
+ ctrl->ctrl_base = ioremap(mdss_dsi_mres->start,
resource_size(mdss_dsi_mres));
- if (!(*ctrl_base)) {
+ if (!(ctrl->ctrl_base)) {
pr_err("%s:%d unable to remap dsi resources",
__func__, __LINE__);
return -ENOMEM;
}
+ ctrl->reg_size = resource_size(mdss_dsi_mres);
+
+ pr_info("%s: dsi base=%x size=%x\n",
+ __func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+
return 0;
}
int dsi_panel_device_register(struct platform_device *pdev,
- struct mdss_panel_common_pdata *panel_data,
- char backlight_ctrl)
+ struct mdss_panel_common_pdata *panel_data)
{
struct mipi_panel_info *mipi;
int rc;
@@ -851,7 +880,6 @@
struct mdss_dsi_ctrl_pdata *ctrl_pdata;
struct device_node *dsi_ctrl_np = NULL;
struct platform_device *ctrl_pdev = NULL;
- unsigned char *ctrl_addr;
bool broadcast;
bool cont_splash_enabled = false;
@@ -891,8 +919,7 @@
else
bpp = 3; /* Default format set to RGB888 */
- if (panel_data->panel_info.type == MIPI_VIDEO_PANEL &&
- !panel_data->panel_info.clk_rate) {
+ if (!panel_data->panel_info.clk_rate) {
h_period += panel_data->panel_info.lcdc.xres_pad;
v_period += panel_data->panel_info.lcdc.yres_pad;
@@ -961,6 +988,45 @@
}
}
+ ctrl_pdata->disp_te_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,te-gpio", 0);
+ if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+ pr_err("%s:%d, Disp_te gpio not specified\n",
+ __func__, __LINE__);
+ } else {
+ rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
+ if (rc) {
+ pr_err("request TE gpio failed, rc=%d\n",
+ rc);
+ gpio_free(ctrl_pdata->disp_te_gpio);
+ return -ENODEV;
+ }
+ rc = gpio_tlmm_config(GPIO_CFG(
+ ctrl_pdata->disp_te_gpio, 1,
+ GPIO_CFG_INPUT,
+ GPIO_CFG_PULL_DOWN,
+ GPIO_CFG_2MA),
+ GPIO_CFG_ENABLE);
+
+ if (rc) {
+ pr_err("%s: unable to config tlmm = %d\n",
+ __func__, ctrl_pdata->disp_te_gpio);
+ gpio_free(ctrl_pdata->disp_te_gpio);
+ return -ENODEV;
+ }
+
+ rc = gpio_direction_input(ctrl_pdata->disp_te_gpio);
+ if (rc) {
+ pr_err("set_direction for disp_en gpio failed, rc=%d\n",
+ rc);
+ gpio_free(ctrl_pdata->disp_te_gpio);
+ return -ENODEV;
+ }
+ pr_debug("%s: te_gpio=%d\n", __func__,
+ ctrl_pdata->disp_te_gpio);
+ }
+
+
ctrl_pdata->rst_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,rst-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
@@ -985,12 +1051,11 @@
if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev,
panel_data->panel_info.pdest,
- &ctrl_addr)) {
+ ctrl_pdata)) {
pr_err("%s: unable to get Dsi controller res\n", __func__);
return -EPERM;
}
- pr_debug("%s: ctrl base address: 0x%x\n", __func__, (int)ctrl_addr);
ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
ctrl_pdata->on_cmds = panel_data->dsi_panel_on_cmds;
@@ -1001,9 +1066,16 @@
sizeof(struct mdss_panel_info));
mdss_dsi_irq_handler_config(ctrl_pdata);
- (ctrl_pdata->panel_data).set_backlight = panel_data->bl_fnc;
- (ctrl_pdata->ctrl_base) = ctrl_addr;
- (ctrl_pdata->bl_ctrl) = backlight_ctrl;
+ ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
+ ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
+ ctrl_pdata->pwm_gpio = panel_data->panel_info.pwm_gpio;
+ ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
+ ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
+ ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
+
+ if (ctrl_pdata->bklt_ctrl == BL_PWM)
+ mdss_dsi_panel_pwm_cfg(ctrl_pdata);
+
/*
* register in mdp driver
*/
@@ -1047,6 +1119,16 @@
pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+ if (panel_data->panel_info.pdest == DISPLAY_1) {
+ mdss_debug_register_base("dsi0",
+ ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
+ ctrl_pdata->ndx = 0;
+ } else {
+ mdss_debug_register_base("dsi1",
+ ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
+ ctrl_pdata->ndx = 1;
+ }
+
pr_debug("%s: Panal data initialized\n", __func__);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index b365f36..197ff7a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -273,17 +273,27 @@
};
struct mdss_dsi_ctrl_pdata {
+ int ndx;
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
struct mdss_panel_data panel_data;
+ struct mdss_hw *mdss_hw;
unsigned char *ctrl_base;
- char bl_ctrl;
+ int reg_size;
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
+ int irq_cnt;
int mdss_dsi_clk_on;
int rst_gpio;
int disp_en_gpio;
+ int disp_te_gpio;
+ int bklt_ctrl; /* backlight ctrl */
+ int pwm_period;
+ int pwm_gpio;
+ int pwm_lpg_chan;
+ int bklt_max;
+ struct pwm_device *pwm_bl;
struct dsi_panel_cmds_list *on_cmds;
struct dsi_panel_cmds_list *off_cmds;
struct dsi_drv_cm_data shared_pdata;
@@ -293,8 +303,7 @@
};
int dsi_panel_device_register(struct platform_device *pdev,
- struct mdss_panel_common_pdata *panel_data,
- char bl_ctrl);
+ struct mdss_panel_common_pdata *panel_data);
char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
char *mdss_dsi_buf_init(struct dsi_buf *dp);
@@ -343,5 +352,7 @@
void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on);
void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
+void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
+void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 6f7023c..ccec0fc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -26,7 +26,6 @@
#include "mdss_dsi.h"
static struct completion dsi_dma_comp;
-static int dsi_irq_enabled;
static spinlock_t dsi_irq_lock;
static spinlock_t dsi_mdp_lock;
static int dsi_mdp_busy;
@@ -51,90 +50,47 @@
spin_lock_init(&dsi_mdp_lock);
}
-void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
{
- if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1)
- mdss_dsi0_hw.ptr = (void *)(ctrl_pdata);
- else
- mdss_dsi1_hw.ptr = (void *)(ctrl_pdata);
+ if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
+ mdss_dsi0_hw.ptr = (void *)(ctrl);
+ ctrl->mdss_hw = &mdss_dsi0_hw;
+ } else {
+ mdss_dsi1_hw.ptr = (void *)(ctrl);
+ ctrl->mdss_hw = &mdss_dsi1_hw;
+ }
}
-void mdss_dsi_enable_irq(struct mdss_panel_data *pdata)
+void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr)
{
unsigned long flags;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
+ if (ctrl == NULL) {
+ pr_err("%s: Invalid ctrl\n", __func__);
return;
}
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
spin_lock_irqsave(&dsi_irq_lock, flags);
- if (dsi_irq_enabled) {
- pr_debug("%s: IRQ aleady enabled\n", __func__);
- spin_unlock_irqrestore(&dsi_irq_lock, flags);
- return;
+ if (enable) {
+ if (ctrl->irq_cnt == 0)
+ mdss_enable_irq(ctrl->mdss_hw);
+ ctrl->irq_cnt++;
+ } else {
+ if (ctrl->irq_cnt) {
+ ctrl->irq_cnt--;
+ if (ctrl->irq_cnt == 0) {
+ if (isr)
+ mdss_disable_irq_nosync(ctrl->mdss_hw);
+ else
+ mdss_disable_irq(ctrl->mdss_hw);
+ }
+ }
}
-
- if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
- mdss_enable_irq(&mdss_dsi0_hw);
- else
- mdss_enable_irq(&mdss_dsi1_hw);
-
- dsi_irq_enabled = 1;
- /* TO DO: Check whether MDSS IRQ is enabled */
+ pr_debug("%s: ctrl=%d enable=%d cnt=%d\n", __func__,
+ ctrl->ndx, enable, ctrl->irq_cnt);
spin_unlock_irqrestore(&dsi_irq_lock, flags);
}
-void mdss_dsi_disable_irq(struct mdss_panel_data *pdata)
-{
- unsigned long flags;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- spin_lock_irqsave(&dsi_irq_lock, flags);
- if (dsi_irq_enabled == 0) {
- pr_debug("%s: IRQ already disabled\n", __func__);
- spin_unlock_irqrestore(&dsi_irq_lock, flags);
- return;
- }
- if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1)
- mdss_disable_irq(&mdss_dsi0_hw);
- else
- mdss_disable_irq(&mdss_dsi1_hw);
-
- dsi_irq_enabled = 0;
- /* TO DO: Check whether MDSS IRQ is Disabled */
- spin_unlock_irqrestore(&dsi_irq_lock, flags);
-}
-
-/*
- * mdss_dsi_disale_irq_nosync() should be called
- * from interrupt context
- */
-void mdss_dsi_disable_irq_nosync(void)
-{
- spin_lock(&dsi_irq_lock);
- if (dsi_irq_enabled == 0) {
- pr_debug("%s: IRQ cannot be disabled\n", __func__);
- spin_unlock(&dsi_irq_lock);
- return;
- }
-
- dsi_irq_enabled = 0;
- spin_unlock(&dsi_irq_lock);
-}
-
/*
* mipi dsi buf mechanism
*/
@@ -689,6 +645,30 @@
return len;
}
+void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata)
+{
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ int i;
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x201);
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x016c, 0xff0000); /* red */
+ i = 0;
+ while (i++ < 50) {
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0184, 0x1);
+ /* Add sleep to get ~50 fps frame rate*/
+ msleep(20);
+ }
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x0);
+}
+
void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
struct mdss_panel_data *pdata)
{
@@ -745,7 +725,7 @@
if (pinfo->r_sel)
data |= BIT(4);
data |= (pinfo->dst_format & 0x0f); /* 4 bits */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x003c, data);
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0040, data);
/* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */
data = pinfo->wr_mem_continue & 0x0ff;
@@ -830,6 +810,7 @@
dsi_ctrl |= BIT(0); /* enable dsi */
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
+ mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0); /* enable dsi irq */
wmb();
}
@@ -977,8 +958,6 @@
DSI_INTR_CMD_MDP_DONE_MASK;
}
- pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl);
-
if (ctrl_pdata->shared_pdata.broadcast_enable)
if ((pdata->panel_info.pdest == DISPLAY_2)
&& (left_ctrl_pdata != NULL)) {
@@ -994,17 +973,6 @@
wmb();
}
-void mdss_dsi_cmd_mdp_start(struct mdss_panel_data *pdata)
-{
- unsigned long flag;
-
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- mdss_dsi_enable_irq(pdata);
- dsi_mdp_busy = true;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-}
-
-
void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata)
{
u32 status;
@@ -1116,7 +1084,7 @@
}
spin_lock_irqsave(&dsi_mdp_lock, flag);
- mdss_dsi_enable_irq(pdata);
+ mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
dsi_mdp_busy = true;
spin_unlock_irqrestore(&dsi_mdp_lock, flag);
@@ -1134,7 +1102,7 @@
spin_lock_irqsave(&dsi_mdp_lock, flag);
dsi_mdp_busy = false;
- mdss_dsi_disable_irq(pdata);
+ mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
spin_unlock_irqrestore(&dsi_mdp_lock, flag);
if (video_mode)
@@ -1206,7 +1174,7 @@
}
spin_lock_irqsave(&dsi_mdp_lock, flag);
- mdss_dsi_enable_irq(pdata);
+ mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
dsi_mdp_busy = true;
spin_unlock_irqrestore(&dsi_mdp_lock, flag);
@@ -1243,7 +1211,7 @@
spin_lock_irqsave(&dsi_mdp_lock, flag);
dsi_mdp_busy = false;
- mdss_dsi_disable_irq(pdata);
+ mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
spin_unlock_irqrestore(&dsi_mdp_lock, flag);
if (pdata->panel_info.mipi.no_max_pkt_size) {
@@ -1288,7 +1256,6 @@
struct mdss_panel_data *pdata)
{
int len;
- int i;
int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
char *bp;
unsigned long size, addr;
@@ -1303,12 +1270,6 @@
panel_data);
bp = tp->data;
- pr_debug("%s: ", __func__);
- for (i = 0; i < tp->len; i++)
- pr_debug("%x ", *bp++);
-
- pr_debug("\n");
-
len = ALIGN(tp->len, 4);
size = ALIGN(tp->len, SZ_4K);
@@ -1495,6 +1456,8 @@
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
}
+ pr_debug("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+
if (isr & DSI_INTR_ERROR)
mdss_dsi_error(dsi_base);
@@ -1510,7 +1473,6 @@
if (isr & DSI_INTR_CMD_MDP_DONE) {
spin_lock(&dsi_mdp_lock);
dsi_mdp_busy = false;
- mdss_dsi_disable_irq_nosync();
spin_unlock(&dsi_mdp_lock);
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 8d38737..d24ed16 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -13,11 +13,14 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of.h>
-#include <linux/qpnp/pin.h>
+#include <linux/of_gpio.h>
#include <linux/gpio.h>
+#include <linux/qpnp/pin.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/leds.h>
+#include <linux/pwm.h>
+#include <linux/err.h>
#include "mdss_dsi.h"
@@ -30,6 +33,64 @@
static struct mdss_dsi_phy_ctrl phy_params;
+void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int ret;
+
+ if (!gpio_is_valid(ctrl->pwm_gpio)) {
+ pr_err("%s: pwm_gpio=%d Invalid\n", __func__,
+ ctrl->pwm_gpio);
+ return;
+ }
+
+ ret = gpio_request(ctrl->pwm_gpio, "disp_pwm");
+ if (ret) {
+ pr_err("%s: pwm_gpio=%d request failed\n", __func__,
+ ctrl->pwm_gpio);
+ return;
+ }
+
+ ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt");
+ if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
+ pr_err("%s: lpg_chan=%d pwm request failed", __func__,
+ ctrl->pwm_lpg_chan);
+ gpio_free(ctrl->pwm_gpio);
+ ctrl->pwm_gpio = -1;
+ }
+}
+
+static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level)
+{
+ int ret;
+ u32 duty;
+
+ if (ctrl->pwm_bl == NULL) {
+ pr_err("%s: no PWM\n", __func__);
+ return;
+ }
+
+ duty = level * ctrl->pwm_period;
+ duty /= ctrl->bklt_max;
+
+ pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n",
+ __func__, ctrl->bklt_ctrl, ctrl->pwm_period,
+ ctrl->pwm_gpio, ctrl->pwm_lpg_chan);
+
+ pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__,
+ ctrl->ndx, level, duty);
+
+ ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
+ if (ret) {
+ pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+ return;
+ }
+
+ ret = pwm_enable(ctrl->pwm_bl);
+ if (ret)
+ pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
+}
+
+
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@@ -84,46 +145,51 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
- if (ctrl_pdata->bl_ctrl) {
- switch (ctrl_pdata->bl_ctrl) {
- case BL_WLED:
- led_trigger_event(bl_led_trigger, bl_level);
- break;
-
- default:
- pr_err("%s: Unknown bl_ctrl configuration\n",
- __func__);
- break;
- }
- } else
- pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__);
+ switch (ctrl_pdata->bklt_ctrl) {
+ case BL_WLED:
+ led_trigger_event(bl_led_trigger, bl_level);
+ break;
+ case BL_PWM:
+ mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);
+ break;
+ default:
+ pr_err("%s: Unknown bl_ctrl configuration\n",
+ __func__);
+ break;
+ }
}
+static char set_tear_on[2] = {0x35, 0x00};
+static struct dsi_cmd_desc dsi_tear_on_cmd = {
+ DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on};
+
+static char set_tear_off[2] = {0x34, 0x00};
+static struct dsi_cmd_desc dsi_tear_off_cmd = {
+ DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off};
+
static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
{
struct mipi_panel_info *mipi;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
mipi = &pdata->panel_info.mipi;
- pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
- mipi->mode);
+ pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
- if (mipi->mode == DSI_VIDEO_MODE) {
+ if (ctrl->on_cmds->size)
mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- ctrl_pdata->on_cmds->buf,
- ctrl_pdata->on_cmds->size);
- } else {
- pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__);
- return -EINVAL;
- }
+ ctrl->on_cmds->buf,
+ ctrl->on_cmds->size);
+
+ mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
+ &dsi_tear_on_cmd, 1);
return 0;
}
@@ -131,34 +197,33 @@
static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
{
struct mipi_panel_info *mipi;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+
+ pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
+
mipi = &pdata->panel_info.mipi;
- pr_debug("%s:%d, debug info\n", __func__, __LINE__);
+ mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
+ &dsi_tear_off_cmd, 1);
- if (mipi->mode == DSI_VIDEO_MODE) {
+ if (ctrl->off_cmds->size)
mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- ctrl_pdata->off_cmds->buf,
- ctrl_pdata->off_cmds->size);
- } else {
- pr_debug("%s:%d, CMD mode not supported", __func__, __LINE__);
- return -EINVAL;
- }
+ ctrl->off_cmds->buf,
+ ctrl->off_cmds->size);
return 0;
}
static int mdss_panel_parse_dt(struct platform_device *pdev,
- struct mdss_panel_common_pdata *panel_data,
- char *bl_ctrl)
+ struct mdss_panel_common_pdata *panel_data)
{
struct device_node *np = pdev->dev.of_node;
u32 res[6], tmp;
@@ -229,7 +294,32 @@
if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) {
led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
- *bl_ctrl = BL_WLED;
+
+ panel_data->panel_info.bklt_ctrl = BL_WLED;
+ } else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) {
+ panel_data->panel_info.bklt_ctrl = BL_PWM;
+
+ rc = of_property_read_u32(np, "qcom,dsi-pwm-period", &tmp);
+ if (rc) {
+ pr_err("%s:%d, Error, dsi pwm_period\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ panel_data->panel_info.pwm_period = tmp;
+
+ rc = of_property_read_u32(np, "qcom,dsi-lpg-channel", &tmp);
+ if (rc) {
+ pr_err("%s:%d, Error, dsi lpg channel\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ panel_data->panel_info.pwm_lpg_chan = tmp;
+
+ tmp = of_get_named_gpio(np, "qcom,dsi-pwm-gpio", 0);
+ panel_data->panel_info.pwm_gpio = tmp;
+ } else {
+ pr_debug("%s: Unknown backlight control\n", __func__);
+ panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
}
rc = of_property_read_u32_array(np,
@@ -240,6 +330,13 @@
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
+ rc = of_property_read_u32(np, "qcom,mdss-vsync-enable", &tmp);
+ panel_data->panel_info.mipi.vsync_enable = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(np, "qcom,mdss-hw-vsync-mode", &tmp);
+ panel_data->panel_info.mipi.hw_vsync_mode = (!rc ? tmp : 0);
+
+
rc = of_property_read_u32(np,
"qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
@@ -263,6 +360,26 @@
(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
rc = of_property_read_u32(np,
+ "qcom,mdss-pan-insert-dcs-cmd", &tmp);
+ panel_data->panel_info.mipi.insert_dcs_cmd =
+ (!rc ? tmp : 1);
+
+ rc = of_property_read_u32(np,
+ "qcom,mdss-pan-wr-mem-continue", &tmp);
+ panel_data->panel_info.mipi.wr_mem_continue =
+ (!rc ? tmp : 0x3c);
+
+ rc = of_property_read_u32(np,
+ "qcom,mdss-pan-wr-mem-start", &tmp);
+ panel_data->panel_info.mipi.wr_mem_start =
+ (!rc ? tmp : 0x2c);
+
+ rc = of_property_read_u32(np,
+ "qcom,mdss-pan-te-sel", &tmp);
+ panel_data->panel_info.mipi.te_sel =
+ (!rc ? tmp : 1);
+
+ rc = of_property_read_u32(np,
"qcom,mdss-pan-dsi-dst-format", &tmp);
panel_data->panel_info.mipi.dst_format =
(!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
@@ -313,6 +430,9 @@
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
+ rc = of_property_read_u32(np, "qcom,mdss-pan-clk-rate", &tmp);
+ panel_data->panel_info.clk_rate = (!rc ? tmp : 0);
+
data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
if ((!data) || (len != 7)) {
pr_err("%s:%d, Unable to read Phy regulator settings",
@@ -533,7 +653,6 @@
int rc = 0;
static struct mdss_panel_common_pdata vendor_pdata;
static const char *panel_name;
- char bl_ctrl = UNKNOWN_CTRL;
pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
if (!pdev->dev.of_node)
@@ -546,7 +665,7 @@
else
pr_info("%s: Panel Name = %s\n", __func__, panel_name);
- rc = mdss_panel_parse_dt(pdev, &vendor_pdata, &bl_ctrl);
+ rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
if (rc)
return rc;
@@ -554,7 +673,7 @@
vendor_pdata.off = mdss_dsi_panel_off;
vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl;
- rc = dsi_panel_device_register(pdev, &vendor_pdata, bl_ctrl);
+ rc = dsi_panel_device_register(pdev, &vendor_pdata);
if (rc)
return rc;
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 6986117..aea2de0 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -363,7 +363,7 @@
case MDSS_EVENT_UNBLANK:
rc = mdss_edp_on(pdata);
break;
- case MDSS_EVENT_TIMEGEN_OFF:
+ case MDSS_EVENT_PANEL_OFF:
rc = mdss_edp_off(pdata);
break;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4e74858..ed730b3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -45,11 +45,8 @@
#include <mach/board.h>
#include <mach/memory.h>
-#include <mach/msm_memtypes.h>
-#include <mach/iommu_domains.h>
#include "mdss_fb.h"
-#include "mdss_mdp.h"
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
#define MDSS_FB_NUM 3
@@ -68,6 +65,8 @@
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
};
+static struct msm_mdp_interface *mdp_instance;
+
static int mdss_fb_register(struct msm_fb_data_type *mfd);
static int mdss_fb_open(struct fb_info *info, int user);
static int mdss_fb_release(struct fb_info *info, int user);
@@ -261,6 +260,7 @@
mfd->pdev = pdev;
if (pdata->next)
mfd->split_display = true;
+ mfd->mdp = *mdp_instance;
mutex_init(&mfd->lock);
@@ -272,6 +272,14 @@
if (rc)
return rc;
+ if (mfd->mdp.init_fnc) {
+ rc = mfd->mdp.init_fnc(mfd);
+ if (rc) {
+ pr_err("init_fnc failed\n");
+ return rc;
+ }
+ }
+
rc = pm_runtime_set_active(mfd->fbi->dev);
if (rc < 0)
pr_err("pm_runtime: fail to set active.\n");
@@ -301,11 +309,7 @@
}
}
- rc = mdss_mdp_overlay_init(mfd);
- if (rc)
- pr_err("unable to init overlay\n");
-
- return 0;
+ return rc;
}
static int mdss_fb_remove(struct platform_device *pdev)
@@ -503,24 +507,6 @@
static int unset_bl_level, bl_updated;
static int bl_level_old;
-static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
- struct mdp_bl_scale_data *data)
-{
- int ret = 0;
- int curr_bl;
- mutex_lock(&mfd->lock);
- curr_bl = mfd->bl_level;
- mfd->bl_scale = data->scale;
- mfd->bl_min_lvl = data->min_lvl;
- pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
- mfd->bl_min_lvl);
-
- /* update current backlight to use new scaling*/
- mdss_fb_set_backlight(mfd, curr_bl);
- mutex_unlock(&mfd->lock);
- return ret;
-}
-
static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
{
u32 temp = *bl_lvl;
@@ -601,9 +587,8 @@
switch (blank_mode) {
case FB_BLANK_UNBLANK:
- if (!mfd->panel_power_on) {
- msleep(20);
- ret = mfd->on_fnc(mfd);
+ if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
+ ret = mfd->mdp.on_fnc(mfd);
if (ret == 0)
mfd->panel_power_on = true;
}
@@ -614,7 +599,7 @@
case FB_BLANK_NORMAL:
case FB_BLANK_POWERDOWN:
default:
- if (mfd->panel_power_on) {
+ if (mfd->panel_power_on && mfd->mdp.off_fnc) {
int curr_pwr_state;
del_timer(&mfd->no_update.timer);
@@ -625,8 +610,7 @@
mfd->panel_power_on = false;
bl_updated = 0;
- msleep(20);
- ret = mfd->off_fnc(mfd);
+ ret = mfd->mdp.off_fnc(mfd);
if (ret)
mfd->panel_power_on = curr_pwr_state;
else
@@ -731,28 +715,11 @@
static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{
- void *virt = NULL;
- unsigned long phys = 0;
- size_t size;
- u32 yres = mfd->fbi->var.yres_virtual;
-
- size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
- if (mfd->index == 0) {
- if (mdss_mdp_alloc_fb_mem(mfd, size, (u32 *)&phys, &virt))
- return -ENOMEM;
- pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
- } else {
- pr_debug("no memory allocated for fb%d\n", mfd->index);
- size = 0;
+ if (!mfd->mdp.fb_mem_alloc_fnc) {
+ pr_err("no fb memory allocator function defined\n");
+ return -ENOMEM;
}
-
- mfd->fbi->screen_base = virt;
- mfd->fbi->fix.smem_start = phys;
- mfd->fbi->fix.smem_len = size;
-
- return 0;
+ return mfd->mdp.fb_mem_alloc_fnc(mfd);
}
static int mdss_fb_register(struct msm_fb_data_type *mfd)
@@ -899,7 +866,11 @@
var->xres *= 2;
fix->type = panel_info->is_3d_panel;
- fix->line_length = mdss_mdp_fb_stride(mfd->index, var->xres, bpp);
+ if (mfd->mdp.fb_stride)
+ fix->line_length = mfd->mdp.fb_stride(mfd->index, var->xres,
+ bpp);
+ else
+ fix->line_length = var->xres * bpp;
var->yres = panel_info->yres;
var->xres_virtual = var->xres;
@@ -949,15 +920,13 @@
pr_err("error: not enough memory!\n");
return -ENOMEM;
}
- if (mfd->lut_update) {
- ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
- if (ret)
- pr_err("fb_alloc_cmap() failed!\n");
- }
+
+ ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+ if (ret)
+ pr_err("fb_alloc_cmap() failed!\n");
if (register_framebuffer(fbi) < 0) {
- if (mfd->lut_update)
- fb_dealloc_cmap(&fbi->cmap);
+ fb_dealloc_cmap(&fbi->cmap);
mfd->op_enable = false;
return -EPERM;
@@ -1200,8 +1169,8 @@
(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
mdss_fb_wait_for_fence(mfd);
- if (mfd->dma_fnc)
- mfd->dma_fnc(mfd);
+ if (mfd->mdp.dma_fnc)
+ mfd->mdp.dma_fnc(mfd);
else
pr_warn("dma function not set for panel type=%d\n",
mfd->panel.type);
@@ -1238,7 +1207,8 @@
if (fb_backup->disp_commit.flags &
MDP_DISPLAY_COMMIT_OVERLAY) {
mdss_fb_wait_for_fence(mfd);
- mdss_mdp_overlay_kickoff(mfd->ctl);
+ if (mfd->mdp.kickoff_fnc)
+ mfd->mdp.kickoff_fnc(mfd);
mdss_fb_signal_timeline(mfd);
} else {
var = &fb_backup->disp_commit.var;
@@ -1403,8 +1373,14 @@
return -EINVAL;
}
- mfd->fbi->fix.line_length = mdss_mdp_fb_stride(mfd->index, var->xres,
+
+ if (mfd->mdp.fb_stride)
+ mfd->fbi->fix.line_length = mfd->mdp.fb_stride(mfd->index,
+ var->xres,
var->bits_per_pixel / 8);
+ else
+ mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
+
if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
@@ -1422,14 +1398,14 @@
struct fb_cursor cursor;
int ret;
- if (!mfd->cursor_update)
+ if (!mfd->mdp.cursor_update)
return -ENODEV;
ret = copy_from_user(&cursor, p, sizeof(cursor));
if (ret)
return ret;
- return mfd->cursor_update(mfd, &cursor);
+ return mfd->mdp.cursor_update(mfd, &cursor);
}
static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
@@ -1438,86 +1414,17 @@
struct fb_cmap cmap;
int ret;
- if (!mfd->lut_update)
+ if (!mfd->mdp.lut_update)
return -ENODEV;
ret = copy_from_user(&cmap, p, sizeof(cmap));
if (ret)
return ret;
- mfd->lut_update(mfd, &cmap);
+ mfd->mdp.lut_update(mfd, &cmap);
return 0;
}
-static int mdss_fb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
- void __user *argp)
-{
- int ret;
- struct msmfb_mdp_pp mdp_pp;
- u32 copyback = 0;
-
- ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
- if (ret)
- return ret;
-
- switch (mdp_pp.op) {
- case mdp_op_pa_cfg:
- ret = mdss_mdp_pa_config(mfd->ctl, &mdp_pp.data.pa_cfg_data,
- ©back);
- break;
-
- case mdp_op_pcc_cfg:
- ret = mdss_mdp_pcc_config(mfd->ctl, &mdp_pp.data.pcc_cfg_data,
- ©back);
- break;
-
- case mdp_op_lut_cfg:
- switch (mdp_pp.data.lut_cfg_data.lut_type) {
- case mdp_lut_igc:
- ret = mdss_mdp_igc_lut_config(mfd->ctl,
- (struct mdp_igc_lut_data *)
- &mdp_pp.data.lut_cfg_data.data,
- ©back);
- break;
-
- case mdp_lut_pgc:
- ret = mdss_mdp_argc_config(mfd->ctl,
- &mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
- ©back);
- break;
-
- case mdp_lut_hist:
- ret = mdss_mdp_hist_lut_config(mfd->ctl,
- (struct mdp_hist_lut_data *)
- &mdp_pp.data.lut_cfg_data.data, ©back);
- break;
-
- default:
- ret = -ENOTSUPP;
- break;
- }
- break;
- case mdp_op_dither_cfg:
- ret = mdss_mdp_dither_config(mfd->ctl,
- &mdp_pp.data.dither_cfg_data, ©back);
- break;
- case mdp_op_gamut_cfg:
- ret = mdss_mdp_gamut_config(mfd->ctl,
- &mdp_pp.data.gamut_cfg_data, ©back);
- break;
- case mdp_bl_scale_cfg:
- ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
- &mdp_pp.data.bl_scale_data);
- break;
- default:
- pr_err("Unsupported request to MDP_PP IOCTL.\n");
- ret = -EINVAL;
- break;
- }
- if ((ret == 0) && copyback)
- ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
- return ret;
-}
static int mdss_fb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
struct mdp_buf_sync *buf_sync)
{
@@ -1618,74 +1525,15 @@
return ret;
}
-static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
- struct msmfb_metadata *metadata)
-{
- int ret = 0;
- switch (metadata->op) {
- case metadata_op_vic:
- if (mfd->panel_info)
- mfd->panel_info->vic =
- metadata->data.video_info_code;
- else
- ret = -EINVAL;
- break;
- default:
- pr_warn("unsupported request to MDP META IOCTL\n");
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
- struct mdss_hw_caps *caps)
-{
- struct mdss_data_type *mdata = mfd->mdata;
-
- if (!mdata)
- return -ENODEV;
-
- caps->mdp_rev = mdata->mdp_rev;
- caps->vig_pipes = mdata->nvig_pipes;
- caps->rgb_pipes = mdata->nrgb_pipes;
- caps->dma_pipes = mdata->ndma_pipes;
-
- return 0;
-}
-
-static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
- struct msmfb_metadata *metadata)
-{
- int ret = 0;
- switch (metadata->op) {
- case metadata_op_frame_rate:
- metadata->data.panel_frame_rate =
- mdss_get_panel_framerate(mfd);
- break;
- case metadata_op_get_caps:
- ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
- break;
- default:
- pr_warn("Unsupported request to MDP META IOCTL.\n");
- ret = -EINVAL;
- break;
- }
- return ret;
-}
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
void __user *argp = (void __user *)arg;
- struct mdp_histogram_data hist;
- struct mdp_histogram_start_req hist_req;
- u32 block, hist_data_addr = 0;
struct mdp_page_protection fb_page_protection;
int ret = -ENOSYS;
struct mdp_buf_sync buf_sync;
- struct msmfb_metadata metadata;
mdss_fb_power_setting_idle(mfd);
@@ -1700,43 +1548,6 @@
ret = mdss_fb_set_lut(info, argp);
break;
- case MSMFB_HISTOGRAM:
- if (!mfd->panel_power_on)
- return -EPERM;
-
- ret = copy_from_user(&hist, argp, sizeof(hist));
- if (ret)
- return ret;
-
- ret = mdss_mdp_hist_collect(mfd->ctl, &hist, &hist_data_addr);
- if ((ret == 0) && hist_data_addr) {
- ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
- sizeof(u32) * hist.bin_cnt);
- if (ret == 0)
- ret = copy_to_user(argp, &hist,
- sizeof(hist));
- }
- break;
-
- case MSMFB_HISTOGRAM_START:
- if (!mfd->panel_power_on)
- return -EPERM;
-
- ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
- if (ret)
- return ret;
-
- ret = mdss_mdp_histogram_start(mfd->ctl, &hist_req);
- break;
-
- case MSMFB_HISTOGRAM_STOP:
- ret = copy_from_user(&block, argp, sizeof(int));
- if (ret)
- return ret;
-
- ret = mdss_mdp_histogram_stop(mfd->ctl, block);
- break;
-
case MSMFB_GET_PAGE_PROTECTION:
fb_page_protection.page_protection =
mfd->mdp_fb_page_protection;
@@ -1746,10 +1557,6 @@
return ret;
break;
- case MSMFB_MDP_PP:
- ret = mdss_fb_handle_pp_ioctl(mfd, argp);
- break;
-
case MSMFB_BUFFER_SYNC:
ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
if (ret)
@@ -1769,25 +1576,9 @@
ret = mdss_fb_display_commit(info, argp);
break;
- case MSMFB_METADATA_SET:
- ret = copy_from_user(&metadata, argp, sizeof(metadata));
- if (ret)
- return ret;
- ret = mdss_fb_set_metadata(mfd, &metadata);
- break;
-
- case MSMFB_METADATA_GET:
- ret = copy_from_user(&metadata, argp, sizeof(metadata));
- if (ret)
- return ret;
- ret = mdss_fb_get_metadata(mfd, &metadata);
- if (!ret)
- ret = copy_to_user(argp, &metadata, sizeof(metadata));
- break;
-
default:
- if (mfd->ioctl_handler)
- ret = mfd->ioctl_handler(mfd, cmd, argp);
+ if (mfd->mdp.ioctl_handler)
+ ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
break;
}
@@ -1853,6 +1644,11 @@
return -ENODEV;
}
+ if (!mdp_instance) {
+ pr_err("mdss mdp resource not initialized yet\n");
+ return -ENODEV;
+ }
+
node = of_parse_phandle(pdev->dev.of_node, "qcom,mdss-fb-map", 0);
if (!node) {
pr_err("Unable to find fb node for device: %s\n",
@@ -1876,23 +1672,27 @@
fb_pdev->dev.platform_data = pdata;
}
- /*
- * Clocks are already on if continuous splash is enabled,
- * increasing ref_cnt to help balance clocks once done.
- */
- if (pdata->panel_info.cont_splash_enabled) {
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- mdss_mdp_footswitch_ctrl_splash(1);
- mdss_mdp_copy_splash_screen(pdata);
- }
+ if (mdp_instance->panel_register_done)
+ mdp_instance->panel_register_done(pdata);
mdss_notfound:
of_node_put(node);
-
return rc;
}
EXPORT_SYMBOL(mdss_register_panel);
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp)
+{
+ if (mdp_instance) {
+ pr_err("multiple MDP instance registration");
+ return -EINVAL;
+ }
+
+ mdp_instance = mdp;
+ return 0;
+}
+EXPORT_SYMBOL(mdss_fb_register_mdp_instance);
+
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
{
struct fb_info *info;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index db2e305..fdbbea9 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -19,7 +19,6 @@
#include <linux/msm_mdp.h>
#include <linux/types.h>
-#include "mdss_mdp.h"
#include "mdss_panel.h"
#define MSM_FB_DEFAULT_PAGE_SIZE 2
@@ -53,6 +52,26 @@
struct mutex lock;
};
+struct msm_fb_data_type;
+
+struct msm_mdp_interface {
+ int (*fb_mem_alloc_fnc)(struct msm_fb_data_type *mfd);
+ int (*init_fnc)(struct msm_fb_data_type *mfd);
+ int (*on_fnc)(struct msm_fb_data_type *mfd);
+ int (*off_fnc)(struct msm_fb_data_type *mfd);
+ int (*kickoff_fnc)(struct msm_fb_data_type *mfd);
+ int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
+ void (*dma_fnc)(struct msm_fb_data_type *mfd);
+ int (*cursor_update)(struct msm_fb_data_type *mfd,
+ struct fb_cursor *cursor);
+ int (*lut_update)(struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
+ int (*do_histogram)(struct msm_fb_data_type *mfd,
+ struct mdp_histogram *hist);
+ int (*panel_register_done)(struct mdss_panel_data *pdata);
+ u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
+ void *private1;
+};
+
struct msm_fb_data_type {
u32 key;
u32 index;
@@ -71,30 +90,9 @@
int panel_reconfig;
u32 dst_format;
- int vsync_pending;
- ktime_t vsync_time;
- struct completion vsync_comp;
- spinlock_t vsync_lock;
- int borderfill_enable;
-
- int hw_refresh;
-
- int overlay_play_enable;
-
int panel_power_on;
struct disp_info_type_suspend suspend;
- int (*on_fnc) (struct msm_fb_data_type *mfd);
- int (*off_fnc) (struct msm_fb_data_type *mfd);
- int (*kickoff_fnc) (struct mdss_mdp_ctl *ctl);
- int (*ioctl_handler) (struct msm_fb_data_type *mfd, u32 cmd, void *arg);
- void (*dma_fnc) (struct msm_fb_data_type *mfd);
- int (*cursor_update) (struct msm_fb_data_type *mfd,
- struct fb_cursor *cursor);
- int (*lut_update) (struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
- int (*do_histogram) (struct msm_fb_data_type *mfd,
- struct mdp_histogram *hist);
-
struct ion_handle *ihdl;
unsigned long iova;
void *cursor_buf;
@@ -105,21 +103,16 @@
u32 bl_scale;
u32 bl_min_lvl;
struct mutex lock;
- struct mutex ov_lock;
struct platform_device *pdev;
u32 mdp_fb_page_protection;
- struct mdss_data_type *mdata;
- struct mdss_mdp_ctl *ctl;
- struct mdss_mdp_wb *wb;
- struct list_head overlay_list;
- struct list_head pipes_used;
- struct list_head pipes_cleanup;
struct disp_info_notify update;
struct disp_info_notify no_update;
+ struct msm_mdp_interface mdp;
+
u32 acq_fen_cnt;
struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
int cur_rel_fen_fd;
@@ -150,5 +143,5 @@
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd);
void mdss_fb_signal_timeline(struct msm_fb_data_type *mfd);
-
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
#endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index b93efd9..6a96369 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2539,7 +2539,7 @@
__func__, rc);
break;
- case MDSS_EVENT_TIMEGEN_ON:
+ case MDSS_EVENT_PANEL_ON:
if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
DEV_DBG("%s: Starting HDCP authentication\n", __func__);
rc = hdmi_hdcp_authenticate(
@@ -2575,7 +2575,7 @@
}
break;
- case MDSS_EVENT_TIMEGEN_OFF:
+ case MDSS_EVENT_PANEL_OFF:
hdmi_ctrl->timing_gen_on = false;
break;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 0e68e3d..e89fc7a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -55,6 +55,12 @@
#include "mdss_debug.h"
struct mdss_data_type *mdss_res;
+struct msm_mdp_interface mdp5 = {
+ .init_fnc = mdss_mdp_overlay_init,
+ .fb_mem_alloc_fnc = mdss_mdp_alloc_fb_mem,
+ .panel_register_done = mdss_panel_register_done,
+ .fb_stride = mdss_mdp_fb_stride,
+};
#define IB_QUOTA 800000000
#define AB_QUOTA 800000000
@@ -127,24 +133,38 @@
static int mdss_mdp_parse_dt_prop_len(struct platform_device *pdev,
char *prop_name);
static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
+static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
- u32 size, u32 *phys, void **virt)
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd)
{
int dom;
- void *fb_virt;
- u32 fb_phys;
- fb_virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
- if (!fb_virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
- fb_phys = memory_pool_node_paddr(fb_virt);
- dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
- msm_iommu_map_contig_buffer(fb_phys, dom, 0, size, SZ_4K,
- 0, &(mfd->iova));
- *phys = fb_phys;
- *virt = fb_virt;
+ void *virt = NULL;
+ unsigned long phys = 0;
+ size_t size;
+ u32 yres = mfd->fbi->var.yres_virtual;
+
+ size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
+ if (mfd->index == 0) {
+ virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ if (!virt) {
+ pr_err("unable to alloc fbmem size=%u\n", size);
+ return -ENOMEM;
+ }
+ phys = memory_pool_node_paddr(virt);
+ dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+ msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+ &mfd->iova);
+
+ pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
+ size, virt, phys, mfd->index);
+ } else
+ size = 0;
+
+ mfd->fbi->screen_base = virt;
+ mfd->fbi->fix.smem_start = phys;
+ mfd->fbi->fix.smem_len = size;
+
return 0;
}
@@ -993,6 +1013,10 @@
if (!pm_runtime_enabled(&pdev->dev))
mdss_mdp_footswitch_ctrl(mdata, true);
+ rc = mdss_fb_register_mdp_instance(&mdp5);
+ if (rc)
+ pr_err("unable to register mdp instance\n");
+
probe_done:
if (IS_ERR_VALUE(rc)) {
mdss_res = NULL;
@@ -1100,6 +1124,12 @@
return rc;
}
+ rc = mdss_mdp_parse_dt_misc(pdev);
+ if (rc) {
+ pr_err("Error in device tree : misc\n");
+ return rc;
+ }
+
return 0;
}
@@ -1205,9 +1235,10 @@
static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev)
{
- u32 nmixers, ndspp;
+ u32 nmixers, ndspp, npingpong;
int rc = 0;
- u32 *mixer_offsets = NULL, *dspp_offsets = NULL;
+ u32 *mixer_offsets = NULL, *dspp_offsets = NULL,
+ *pingpong_offsets = NULL;
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
@@ -1217,6 +1248,8 @@
"qcom,mdss-mixer-wb-off");
ndspp = mdss_mdp_parse_dt_prop_len(pdev,
"qcom,mdss-dspp-off");
+ npingpong = mdss_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-pingpong-off");
nmixers = mdata->nmixers_intf + mdata->nmixers_wb;
if (mdata->nmixers_intf != ndspp) {
@@ -1224,6 +1257,11 @@
return -EINVAL;
}
+ if (mdata->nmixers_intf != npingpong) {
+ pr_err("device tree err: unequal no of pingpong and intf mixers\n");
+ return -EINVAL;
+ }
+
mixer_offsets = kzalloc(sizeof(u32) * nmixers, GFP_KERNEL);
if (!mixer_offsets) {
pr_err("no mem assigned: kzalloc fail\n");
@@ -1236,6 +1274,12 @@
rc = -ENOMEM;
goto dspp_alloc_fail;
}
+ pingpong_offsets = kzalloc(sizeof(u32) * npingpong, GFP_KERNEL);
+ if (!pingpong_offsets) {
+ pr_err("no mem assigned: kzalloc fail\n");
+ rc = -ENOMEM;
+ goto pingpong_alloc_fail;
+ }
rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-mixer-intf-off",
mixer_offsets, mdata->nmixers_intf);
@@ -1252,19 +1296,26 @@
if (rc)
goto parse_done;
+ rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pingpong-off",
+ pingpong_offsets, npingpong);
+ if (rc)
+ goto parse_done;
+
rc = mdss_mdp_mixer_addr_setup(mdata, mixer_offsets,
- dspp_offsets, MDSS_MDP_MIXER_TYPE_INTF,
- mdata->nmixers_intf);
+ dspp_offsets, pingpong_offsets,
+ MDSS_MDP_MIXER_TYPE_INTF, mdata->nmixers_intf);
if (rc)
goto parse_done;
rc = mdss_mdp_mixer_addr_setup(mdata, mixer_offsets +
- mdata->nmixers_intf, NULL,
+ mdata->nmixers_intf, NULL, NULL,
MDSS_MDP_MIXER_TYPE_WRITEBACK, mdata->nmixers_wb);
if (rc)
goto parse_done;
parse_done:
+ kfree(pingpong_offsets);
+pingpong_alloc_fail:
kfree(dspp_offsets);
dspp_alloc_fail:
kfree(mixer_offsets);
@@ -1384,6 +1435,19 @@
return rc;
}
+static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+ u32 data;
+ int rc;
+
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,mdss-rot-block-size",
+ &data);
+ mdata->rot_block_size = (!rc ? data : 128);
+
+ return 0;
+}
+
static int mdss_mdp_parse_dt_handler(struct platform_device *pdev,
char *prop_name, u32 *offsets, int len)
{
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 14c1e52..df5e5d3 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -156,6 +156,7 @@
u32 ref_cnt;
char __iomem *base;
char __iomem *dspp_base;
+ char __iomem *pingpong_base;
u8 type;
u8 params_changed;
u16 width;
@@ -197,6 +198,8 @@
u32 plane_size[MAX_PLANES];
u32 total_size;
u32 ystride[MAX_PLANES];
+ u32 rau_cnt;
+ u32 rau_h[2];
};
struct mdss_mdp_img_data {
@@ -283,6 +286,24 @@
void *priv_data;
};
+struct mdss_overlay_private {
+ int vsync_pending;
+ ktime_t vsync_time;
+ struct completion vsync_comp;
+ spinlock_t vsync_lock;
+ int borderfill_enable;
+ int overlay_play_enable;
+ int hw_refresh;
+
+ struct mdss_data_type *mdata;
+ struct mutex ov_lock;
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_mdp_wb *wb;
+ struct list_head overlay_list;
+ struct list_head pipes_used;
+ struct list_head pipes_cleanup;
+};
+
#define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
u32 reg, u32 val)
@@ -295,6 +316,17 @@
return readl_relaxed(ctl->base + reg);
}
+static inline void mdss_mdp_pingpong_write(struct mdss_mdp_mixer *mixer,
+ u32 reg, u32 val)
+{
+ writel_relaxed(val, mixer->pingpong_base + reg);
+}
+
+static inline u32 mdss_mdp_pingpong_read(struct mdss_mdp_mixer *mixer, u32 reg)
+{
+ return readl_relaxed(mixer->pingpong_base + reg);
+}
+
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_iommu_attach(struct mdss_data_type *mdata);
int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
@@ -319,11 +351,12 @@
int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
u32 *offsets, u32 count);
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl);
int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd);
struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
- struct msm_fb_data_type *mfd);
+ struct msm_fb_data_type *mfd);
int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata);
@@ -400,7 +433,7 @@
int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
u32 *ftch_y_id, u32 type, u32 num_base, u32 len);
int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
- u32 *dspp_offsets, u32 type, u32 len);
+ u32 *dspp_offsets, u32 *pingpong_offsets, u32 type, u32 len);
int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
u32 *wb_offsets, u32 len);
@@ -411,17 +444,29 @@
int mdss_mdp_data_check(struct mdss_mdp_data *data,
struct mdss_mdp_plane_sizes *ps);
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
- struct mdss_mdp_plane_sizes *ps);
+ struct mdss_mdp_plane_sizes *ps, u32 bwc_mode);
+int mdss_mdp_get_rau_strides(u32 w, u32 h, struct mdss_mdp_format_params *fmt,
+ struct mdss_mdp_plane_sizes *ps);
struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
-int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd);
int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id);
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
- u32 size, u32 *phys, void **virt);
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd);
u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
+
+int mdss_panel_register_done(struct mdss_panel_data *pdata);
+
+#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
+#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
+ (mfd->mdp.private1))->mdata)
+#define mfd_to_ctl(mfd) (((struct mdss_overlay_private *)\
+ (mfd->mdp.private1))->ctl)
+#define mfd_to_wb(mfd) (((struct mdss_overlay_private *)\
+ (mfd->mdp.private1))->wb)
+
#endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index e850321..108340d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -575,7 +575,8 @@
struct mdss_mdp_ctl *ctl;
int ret = 0;
- ctl = mdss_mdp_ctl_alloc(mfd->mdata);
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+ ctl = mdss_mdp_ctl_alloc(mdata);
if (!ctl) {
pr_err("unable to allocate ctl\n");
return ERR_PTR(-ENOMEM);
@@ -599,6 +600,15 @@
ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
ctl->start_fnc = mdss_mdp_video_start;
break;
+ case MIPI_CMD_PANEL:
+ if (pdata->panel_info.pdest == DISPLAY_1)
+ ctl->intf_num = MDSS_MDP_INTF1;
+ else
+ ctl->intf_num = MDSS_MDP_INTF2;
+ ctl->intf_type = MDSS_INTF_DSI;
+ ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE;
+ ctl->start_fnc = mdss_mdp_cmd_start;
+ break;
case DTV_PANEL:
ctl->intf_num = MDSS_MDP_INTF3;
ctl->intf_type = MDSS_INTF_HDMI;
@@ -1032,7 +1042,8 @@
}
int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata,
- u32 *mixer_offsets, u32 *dspp_offsets, u32 type, u32 len)
+ u32 *mixer_offsets, u32 *dspp_offsets, u32 *pingpong_offsets,
+ u32 type, u32 len)
{
struct mdss_mdp_mixer *head;
u32 i;
@@ -1052,8 +1063,11 @@
head[i].base = mdata->mdp_base + mixer_offsets[i];
head[i].ref_cnt = 0;
head[i].num = i;
- if (type == MDSS_MDP_MIXER_TYPE_INTF)
+ if (type == MDSS_MDP_MIXER_TYPE_INTF) {
head[i].dspp_base = mdata->mdp_base + dspp_offsets[i];
+ head[i].pingpong_base = mdata->mdp_base +
+ pingpong_offsets[i];
+ }
}
switch (type) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index f8cd0ce..bf78c61 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -164,6 +164,9 @@
#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C
#define MDSS_MDP_REG_SSPP_SRC_FORMAT 0x030
#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034
+#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0 0x050
+#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1 0x054
+#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2 0x058
#define MDSS_MDP_REG_SSPP_SRC_OP_MODE 0x038
#define MDSS_MDP_OP_DEINTERLACE BIT(22)
@@ -428,8 +431,6 @@
MDSS_MDP_MAX_PINGPONG
};
-#define MDSS_MDP_REG_PP_OFFSET(pp) (0x21B00 + ((pp) * 0x100))
-
#define MDSS_MDP_REG_PP_TEAR_CHECK_EN 0x000
#define MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC 0x004
#define MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT 0x008
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
new file mode 100644
index 0000000..d6b0fb2
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -0,0 +1,333 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include "mdss_panel.h"
+#include "mdss_mdp.h"
+
+#define START_THRESHOLD 4
+#define CONTINUE_TRESHOLD 4
+
+#define MAX_SESSIONS 2
+
+struct mdss_mdp_cmd_ctx {
+ u32 pp_num;
+ u8 ref_cnt;
+
+ struct completion pp_comp;
+ atomic_t vsync_ref;
+ spinlock_t vsync_lock;
+ mdp_vsync_handler_t vsync_handler;
+ int panel_on;
+
+ /* te config */
+ u8 tear_check;
+ u16 total_lcd_lines;
+ u16 v_porch; /* vertical porches */
+ u32 vsync_cnt;
+};
+
+struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
+
+static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
+ struct mdss_mdp_cmd_ctx *ctx, int enable)
+{
+ u32 cfg;
+
+ cfg = BIT(19); /* VSYNC_COUNTER_EN */
+ if (ctx->tear_check)
+ cfg |= BIT(20); /* VSYNC_IN_EN */
+ cfg |= ctx->vsync_cnt;
+
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT,
+ 0xfff0); /* set to verh height */
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL, 0);
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ, 0);
+
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS, ctx->v_porch);
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
+ (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
+
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
+ return 0;
+}
+
+static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, int enable)
+{
+ struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+ struct mdss_panel_info *pinfo;
+ struct mdss_mdp_mixer *mixer;
+
+ pinfo = &ctl->panel_data->panel_info;
+
+ if (pinfo->mipi.vsync_enable && enable) {
+ u32 mdp_vsync_clk_speed_hz, total_lines;
+ u32 vsync_cnt_cfg_dem;
+
+ mdss_mdp_vsync_clk_enable(1);
+
+ mdp_vsync_clk_speed_hz =
+ mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
+ pr_debug("%s: vsync_clk_rate=%d\n", __func__,
+ mdp_vsync_clk_speed_hz);
+
+ if (mdp_vsync_clk_speed_hz == 0) {
+ pr_err("can't get clk speed\n");
+ return -EINVAL;
+ }
+
+ ctx->tear_check = pinfo->mipi.hw_vsync_mode;
+
+ total_lines = pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch +
+ pinfo->lcdc.v_pulse_width + pinfo->yres;
+
+ vsync_cnt_cfg_dem =
+ mult_frac(pinfo->mipi.frame_rate * total_lines,
+ 1, 100);
+
+ ctx->vsync_cnt = mdp_vsync_clk_speed_hz / vsync_cnt_cfg_dem;
+
+ ctx->v_porch = pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch +
+ pinfo->lcdc.v_pulse_width;
+ ctx->total_lcd_lines = total_lines;
+ } else {
+ enable = 0;
+ }
+
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+ if (mixer)
+ mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
+
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
+ if (mixer)
+ mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
+
+ return 0;
+}
+
+static inline void cmd_readptr_irq_enable(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+ if (atomic_inc_return(&ctx->vsync_ref) == 1) {
+ pr_debug("%s:\n", __func__);
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
+ }
+}
+
+static inline void cmd_readptr_irq_disable(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+ if (atomic_dec_return(&ctx->vsync_ref) == 0) {
+ pr_debug("%s:\n", __func__);
+ mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+ ctx->pp_num);
+ }
+}
+
+int mdss_mdp_cmd_set_vsync_handler(struct mdss_mdp_ctl *ctl,
+ mdp_vsync_handler_t vsync_handler)
+{
+ struct mdss_mdp_cmd_ctx *ctx;
+ unsigned long flags;
+
+ ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx for ctl=%d\n", ctl->num);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&ctx->vsync_lock, flags);
+
+ if (!ctx->vsync_handler && vsync_handler) {
+ ctx->vsync_handler = vsync_handler;
+ cmd_readptr_irq_enable(ctl);
+ } else if (ctx->vsync_handler && !vsync_handler) {
+ cmd_readptr_irq_disable(ctl);
+ ctx->vsync_handler = vsync_handler;
+ }
+
+ spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+
+ return 0;
+}
+
+static void mdss_mdp_cmd_readptr_done(void *arg)
+{
+ struct mdss_mdp_ctl *ctl = arg;
+ struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+ ktime_t vsync_time;
+
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return;
+ }
+
+ pr_debug("%s: ctl=%d intf_num=%d\n", __func__, ctl->num, ctl->intf_num);
+
+ vsync_time = ktime_get();
+
+ spin_lock(&ctx->vsync_lock);
+ if (ctx->vsync_handler)
+ ctx->vsync_handler(ctl, vsync_time);
+ spin_unlock(&ctx->vsync_lock);
+}
+
+static void mdss_mdp_cmd_pingpong_done(void *arg)
+{
+ struct mdss_mdp_ctl *ctl = arg;
+ struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+ pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
+
+ mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
+
+ if (ctx)
+ complete(&ctx->pp_comp);
+}
+
+int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_cmd_ctx *ctx;
+ int rc;
+
+ ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+ pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
+ ctl->intf_num, ctx);
+
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
+ }
+
+ if (ctx->panel_on == 0) {
+ rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
+ WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
+
+ ctx->panel_on++;
+
+ rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
+ WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
+ }
+
+ INIT_COMPLETION(ctx->pp_comp);
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
+
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+
+ wait_for_completion_interruptible(&ctx->pp_comp);
+
+ return 0;
+}
+
+int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_cmd_ctx *ctx;
+ int ret;
+
+ pr_debug("%s: +\n", __func__);
+
+ ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
+ }
+
+ ctx->panel_on = 0;
+
+ mdss_mdp_cmd_set_vsync_handler(ctl, NULL);
+
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num,
+ NULL, NULL);
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+ NULL, NULL);
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctl->priv_data = NULL;
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL);
+ WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
+ WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ pr_debug("%s:-\n", __func__);
+
+ return 0;
+}
+
+int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_cmd_ctx *ctx;
+ struct mdss_mdp_mixer *mixer;
+ int i, ret;
+
+ pr_debug("%s:+\n", __func__);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+ if (!mixer) {
+ pr_err("mixer not setup correctly\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ ctx = &mdss_mdp_cmd_ctx_list[i];
+ if (ctx->ref_cnt == 0) {
+ ctx->ref_cnt++;
+ break;
+ }
+ }
+ if (i == MAX_SESSIONS) {
+ pr_err("too many sessions\n");
+ return -ENOMEM;
+ }
+
+ ctl->priv_data = ctx;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
+ }
+
+ ctx->pp_num = mixer->num;
+ init_completion(&ctx->pp_comp);
+ spin_lock_init(&ctx->vsync_lock);
+ atomic_set(&ctx->vsync_ref, 0);
+
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
+ mdss_mdp_cmd_readptr_done, ctl);
+
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+ mdss_mdp_cmd_pingpong_done, ctl);
+
+ ret = mdss_mdp_cmd_tearcheck_setup(ctl, 1);
+ if (ret) {
+ pr_err("tearcheck setup failed\n");
+ return ret;
+ }
+
+ ctl->stop_fnc = mdss_mdp_cmd_stop;
+ ctl->display_fnc = mdss_mdp_cmd_kickoff;
+ ctl->set_vsync_handler = mdss_mdp_cmd_set_vsync_handler;
+
+ pr_debug("%s:-\n", __func__);
+
+ return 0;
+}
+
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index dab8674..e7f70b6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -242,7 +242,7 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
ctx->timegen_en = false;
- rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_OFF, NULL);
+ rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
WARN(rc, "intf %d timegen off error (%d)\n", ctl->intf_num, rc);
mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
@@ -359,8 +359,8 @@
rc, ctl->num);
ctx->timegen_en = true;
- rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
- WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
+ rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
+ WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
}
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index c6b6e3f..7fbb031 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -17,8 +17,6 @@
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
-#define ROT_BLK_SIZE 128
-
enum mdss_mdp_writeback_type {
MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
MDSS_MDP_WRITEBACK_TYPE_LINE,
@@ -39,7 +37,7 @@
u16 width;
u16 height;
u8 rot90;
-
+ u32 bwc_mode;
int initialized;
struct mdss_mdp_plane_sizes dst_planes;
@@ -92,6 +90,9 @@
pr_debug("wb_num=%d addr=0x%x\n", ctx->wb_num, data->p[0].addr);
+ if (ctx->bwc_mode)
+ data->bwc_enabled = 1;
+
ret = mdss_mdp_data_check(data, &ctx->dst_planes);
if (ret)
return ret;
@@ -114,7 +115,8 @@
pr_debug("wb_num=%d format=%d\n", ctx->wb_num, ctx->format);
mdss_mdp_get_plane_sizes(ctx->format, ctx->width, ctx->height,
- &ctx->dst_planes);
+ &ctx->dst_planes,
+ ctx->opmode & MDSS_MDP_OP_BWC_EN);
fmt = mdss_mdp_get_format_params(ctx->format);
if (!fmt) {
@@ -251,10 +253,11 @@
pr_debug("rot setup wb_num=%d\n", ctx->wb_num);
ctx->opmode = BIT(6); /* ROT EN */
- if (ROT_BLK_SIZE == 128)
+ if (ctl->mdata->rot_block_size == 128)
ctx->opmode |= BIT(4); /* block size 128 */
- ctx->opmode |= rot->bwc_mode;
+ ctx->bwc_mode = rot->bwc_mode;
+ ctx->opmode |= ctx->bwc_mode;
ctx->width = rot->src_rect.w;
ctx->height = rot->src_rect.h;
@@ -262,12 +265,15 @@
ctx->format = rot->format;
ctx->rot90 = !!(rot->flags & MDP_ROT_90);
+
+ if (ctx->bwc_mode || ctx->rot90)
+ ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
+ else
+ ctx->format = rot->format;
+
if (ctx->rot90) {
ctx->opmode |= BIT(5); /* ROT 90 */
swap(ctx->width, ctx->height);
- ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
- } else {
- ctx->format = rot->format;
}
return mdss_mdp_writeback_format_setup(ctx);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 0a56ba4..dae3e05 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -21,6 +21,7 @@
#include <linux/pm_runtime.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
+#include <linux/msm_mdp.h>
#include <mach/iommu_domains.h>
@@ -41,8 +42,9 @@
struct mdp_overlay *req)
{
struct mdss_mdp_pipe *pipe;
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
- pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+ pipe = mdss_mdp_pipe_get(mdata, req->id);
if (IS_ERR_OR_NULL(pipe)) {
pr_err("invalid pipe ndx=%x\n", req->id);
return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -60,11 +62,12 @@
{
u32 xres, yres;
u32 min_src_size, min_dst_size;
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
xres = mfd->fbi->var.xres;
yres = mfd->fbi->var.yres;
- if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+ if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
min_src_size = fmt->is_yuv ? 2 : 1;
min_dst_size = 1;
} else {
@@ -170,11 +173,12 @@
static int mdss_mdp_overlay_rotator_setup(struct msm_fb_data_type *mfd,
struct mdp_overlay *req)
{
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_rotator_session *rot;
struct mdss_mdp_format_params *fmt;
int ret = 0;
- pr_debug("rot ctl=%u req id=%x\n", mfd->ctl->num, req->id);
+ pr_debug("rot ctl=%u req id=%x\n", mdp5_data->ctl->num, req->id);
fmt = mdss_mdp_get_format_params(req->src.format);
if (!fmt) {
@@ -209,6 +213,7 @@
rot->flags = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD |
MDP_SECURE_OVERLAY_SESSION);
+ rot->bwc_mode = (req->flags & MDP_BWC_EN) ? 1 : 0;
rot->format = fmt->format;
rot->img_width = req->src.width;
rot->img_height = req->src.height;
@@ -237,9 +242,10 @@
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_mixer *mixer = NULL;
u32 pipe_type, mixer_mux, len, src_format;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
int ret;
- if (mfd == NULL || mfd->ctl == NULL)
+ if (mdp5_data->ctl == NULL)
return -ENODEV;
if (req->flags & MDSS_MDP_RIGHT_MIXER)
@@ -247,7 +253,7 @@
else
mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
- pr_debug("pipe ctl=%u req id=%x mux=%d\n", mfd->ctl->num, req->id,
+ pr_debug("pipe ctl=%u req id=%x mux=%d\n", mdp5_data->ctl->num, req->id,
mixer_mux);
if (req->flags & MDP_ROT_90) {
@@ -256,7 +262,7 @@
}
src_format = req->src.format;
- if (req->flags & MDP_SOURCE_ROTATED_90)
+ if (req->flags & (MDP_SOURCE_ROTATED_90 | MDP_BWC_EN))
src_format = mdss_mdp_get_rotator_dst_format(src_format);
fmt = mdss_mdp_get_format_params(src_format);
@@ -269,14 +275,15 @@
if (ret)
return ret;
- pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
+ pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
+ req->z_order);
if (pipe && pipe->ndx != req->id) {
pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
pipe->num, req->z_order, mixer_mux);
pipe->params_changed = true;
}
- mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+ mixer = mdss_mdp_mixer_get(mdp5_data->ctl, mixer_mux);
if (!mixer) {
pr_err("unable to get mixer\n");
return -ENODEV;
@@ -310,13 +317,13 @@
}
mutex_lock(&mfd->lock);
- list_add(&pipe->used_list, &mfd->pipes_used);
+ list_add(&pipe->used_list, &mdp5_data->pipes_used);
mutex_unlock(&mfd->lock);
pipe->mixer = mixer;
pipe->mfd = mfd;
pipe->play_cnt = 0;
} else {
- pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+ pipe = mdss_mdp_pipe_get(mdp5_data->mdata, req->id);
if (IS_ERR_OR_NULL(pipe)) {
pr_err("invalid pipe ndx=%x\n", req->id);
return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -339,7 +346,8 @@
}
pipe->flags = req->flags;
-
+ pipe->bwc_mode = pipe->mixer->rotator_mode ?
+ 0 : (req->flags & MDP_BWC_EN ? 1 : 0) ;
pipe->img_width = req->src.width & 0x3fff;
pipe->img_height = req->src.height & 0x3fff;
pipe->src.x = req->src_rect.x;
@@ -406,14 +414,15 @@
static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
struct mdp_overlay *req)
{
- int ret = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ int ret;
- ret = mutex_lock_interruptible(&mfd->ov_lock);
+ ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
if (ret)
return ret;
if (!mfd->panel_power_on) {
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return -EPERM;
}
@@ -432,7 +441,7 @@
req->z_order -= MDSS_MDP_STAGE_0;
}
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return ret;
}
@@ -481,16 +490,18 @@
static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_pipe *pipe, *tmp;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
LIST_HEAD(destroy_pipes);
mutex_lock(&mfd->lock);
- list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
+ list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup,
+ cleanup_list) {
list_move(&pipe->cleanup_list, &destroy_pipes);
mdss_mdp_overlay_free_buf(&pipe->back_buf);
mdss_mdp_overlay_free_buf(&pipe->front_buf);
}
- list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+ list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
if (pipe->back_buf.num_planes) {
/* make back buffer active */
mdss_mdp_overlay_free_buf(&pipe->front_buf);
@@ -595,8 +606,9 @@
static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
{
int rc;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- if (mfd->ctl->power_on)
+ if (mdp5_data->ctl->power_on)
return 0;
pr_debug("starting fb%d overlay\n", mfd->index);
@@ -608,20 +620,20 @@
}
if (mfd->panel_info->cont_splash_enabled)
- mdss_mdp_reconfigure_splash_done(mfd->ctl);
+ mdss_mdp_reconfigure_splash_done(mdp5_data->ctl);
if (!is_mdss_iommu_attached()) {
mdss_iommu_attach(mdss_res);
mdss_hw_init(mdss_res);
}
- rc = mdss_mdp_ctl_start(mfd->ctl);
+ rc = mdss_mdp_ctl_start(mdp5_data->ctl);
if (rc == 0) {
atomic_inc(&ov_active_panels);
} else {
pr_err("overlay start failed.\n");
- mdss_mdp_ctl_destroy(mfd->ctl);
- mfd->ctl = NULL;
+ mdss_mdp_ctl_destroy(mdp5_data->ctl);
+ mdp5_data->ctl = NULL;
pm_runtime_put(&mfd->pdev->dev);
}
@@ -629,15 +641,15 @@
return rc;
}
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
{
- struct msm_fb_data_type *mfd = ctl->mfd;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe;
int ret;
- mutex_lock(&mfd->ov_lock);
+ mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
- list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+ list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
struct mdss_mdp_data *buf;
if (pipe->back_buf.num_planes) {
buf = &pipe->back_buf;
@@ -658,16 +670,17 @@
}
}
- if (mfd->kickoff_fnc)
- ret = mfd->kickoff_fnc(ctl);
+ if (mfd->panel.type == WRITEBACK_PANEL)
+ ret = mdss_mdp_wb_kickoff(mfd);
else
- ret = mdss_mdp_display_commit(ctl, NULL);
+ ret = mdss_mdp_display_commit(mdp5_data->ctl, NULL);
+
mutex_unlock(&mfd->lock);
if (IS_ERR_VALUE(ret))
goto commit_fail;
- ret = mdss_mdp_display_wait4comp(ctl);
+ ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
complete(&mfd->update.comp);
mutex_lock(&mfd->no_update.lock);
@@ -681,7 +694,7 @@
commit_fail:
ret = mdss_mdp_overlay_cleanup(mfd);
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return ret;
}
@@ -689,6 +702,7 @@
static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx)
{
struct mdss_mdp_pipe *pipe;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
u32 pipe_ndx, unset_ndx = 0;
int i;
@@ -696,14 +710,15 @@
pipe_ndx = BIT(i);
if (pipe_ndx & ndx) {
unset_ndx |= pipe_ndx;
- pipe = mdss_mdp_pipe_get(mfd->mdata, pipe_ndx);
+ pipe = mdss_mdp_pipe_get(mdp5_data->mdata, pipe_ndx);
if (IS_ERR_OR_NULL(pipe)) {
pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
continue;
}
mutex_lock(&mfd->lock);
list_del(&pipe->used_list);
- list_add(&pipe->cleanup_list, &mfd->pipes_cleanup);
+ list_add(&pipe->cleanup_list,
+ &mdp5_data->pipes_cleanup);
mutex_unlock(&mfd->lock);
mdss_mdp_mixer_pipe_unstage(pipe);
mdss_mdp_pipe_unmap(pipe);
@@ -715,22 +730,23 @@
static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
{
int ret = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- if (!mfd || !mfd->ctl)
+ if (!mfd || !mdp5_data->ctl)
return -ENODEV;
- ret = mutex_lock_interruptible(&mfd->ov_lock);
+ ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
if (ret)
return ret;
if (ndx == BORDERFILL_NDX) {
pr_debug("borderfill disable\n");
- mfd->borderfill_enable = false;
+ mdp5_data->borderfill_enable = false;
return 0;
}
if (!mfd->panel_power_on) {
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return -EPERM;
}
@@ -741,7 +757,7 @@
else
ret = mdss_mdp_overlay_release(mfd, ndx);
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return ret;
}
@@ -749,18 +765,19 @@
static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_pipe *pipe;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
u32 unset_ndx = 0;
int cnt = 0;
- mutex_lock(&mfd->ov_lock);
+ mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
- list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+ list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
unset_ndx |= pipe->ndx;
cnt++;
}
- if (cnt == 0 && !list_empty(&mfd->pipes_cleanup)) {
- pr_warn("overlay release on fb%d called without commit!",
+ if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
+ pr_debug("overlay release on fb%d called without commit!",
mfd->index);
cnt++;
}
@@ -771,10 +788,10 @@
pr_debug("%d pipes need cleanup (%x)\n", cnt, unset_ndx);
mdss_mdp_overlay_release(mfd, unset_ndx);
}
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
if (cnt)
- mdss_mdp_overlay_kickoff(mfd->ctl);
+ mfd->mdp.kickoff_fnc(mfd);
return 0;
}
@@ -782,12 +799,12 @@
static int mdss_mdp_overlay_play_wait(struct msm_fb_data_type *mfd,
struct msmfb_overlay_data *req)
{
- int ret;
+ int ret = 0;
- if (!mfd || !mfd->ctl)
+ if (!mfd)
return -ENODEV;
- ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+ ret = mfd->mdp.kickoff_fnc(mfd);
if (!ret)
pr_err("error displaying\n");
@@ -840,8 +857,9 @@
struct mdss_mdp_data *src_data;
int ret;
u32 flags;
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
- pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+ pipe = mdss_mdp_pipe_get(mdata, req->id);
if (IS_ERR_OR_NULL(pipe)) {
pr_err("pipe ndx=%x doesn't exist\n", req->id);
return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -870,16 +888,17 @@
static int mdss_mdp_overlay_play(struct msm_fb_data_type *mfd,
struct msmfb_overlay_data *req)
{
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
int ret = 0;
pr_debug("play req id=%x\n", req->id);
- ret = mutex_lock_interruptible(&mfd->ov_lock);
+ ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
if (ret)
return ret;
if (!mfd->panel_power_on) {
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return -EPERM;
}
@@ -893,13 +912,13 @@
ret = mdss_mdp_overlay_rotate(mfd, req);
} else if (req->id == BORDERFILL_NDX) {
pr_debug("borderfill enable\n");
- mfd->borderfill_enable = true;
+ mdp5_data->borderfill_enable = true;
ret = mdss_mdp_overlay_free_fb_pipe(mfd);
} else {
ret = mdss_mdp_overlay_queue(mfd, req);
}
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return ret;
}
@@ -908,13 +927,16 @@
{
struct mdss_mdp_pipe *pipe;
u32 fb_ndx = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT,
+ pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl,
+ MDSS_MDP_MIXER_MUX_LEFT,
MDSS_MDP_STAGE_BASE);
if (pipe)
fb_ndx |= pipe->ndx;
- pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, MDSS_MDP_MIXER_MUX_RIGHT,
+ pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl,
+ MDSS_MDP_MIXER_MUX_RIGHT,
MDSS_MDP_STAGE_BASE);
if (pipe)
fb_ndx |= pipe->ndx;
@@ -930,9 +952,10 @@
struct mdss_mdp_pipe **ppipe,
int mixer_mux)
{
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe;
- pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux,
+ pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
MDSS_MDP_STAGE_BASE);
if (pipe == NULL) {
struct mdp_overlay req;
@@ -940,7 +963,8 @@
struct mdss_mdp_mixer *mixer;
int ret, bpp;
- mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT);
+ mixer = mdss_mdp_mixer_get(mdp5_data->ctl,
+ MDSS_MDP_MIXER_MUX_LEFT);
if (!mixer) {
pr_err("unable to retrieve mixer\n");
return -ENODEV;
@@ -981,7 +1005,7 @@
if (ret)
return ret;
- pr_debug("ctl=%d pnum=%d\n", mfd->ctl->num, pipe->num);
+ pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
}
*ppipe = pipe;
@@ -993,24 +1017,25 @@
struct mdss_mdp_data data;
struct mdss_mdp_pipe *pipe;
struct fb_info *fbi;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
u32 offset;
int bpp, ret;
- if (!mfd || !mfd->ctl)
+ if (!mfd || !mdp5_data->ctl)
return;
fbi = mfd->fbi;
- if (fbi->fix.smem_len == 0 || mfd->borderfill_enable) {
- mdss_mdp_overlay_kickoff(mfd->ctl);
+ if (fbi->fix.smem_len == 0 || mdp5_data->borderfill_enable) {
+ mfd->mdp.kickoff_fnc(mfd);
return;
}
- if (mutex_lock_interruptible(&mfd->ov_lock))
+ if (mutex_lock_interruptible(&mdp5_data->ov_lock))
return;
if (!mfd->panel_power_on) {
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
return;
}
@@ -1023,13 +1048,13 @@
if (offset > fbi->fix.smem_len) {
pr_err("invalid fb offset=%u total length=%u\n",
offset, fbi->fix.smem_len);
- return;
+ goto pan_display_error;
}
ret = mdss_mdp_overlay_start(mfd);
if (ret) {
pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
- return;
+ goto pan_display_error;
}
if (is_mdss_iommu_attached())
@@ -1044,18 +1069,18 @@
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
if (ret) {
pr_err("unable to allocate base pipe\n");
- return;
+ goto pan_display_error;
}
if (mdss_mdp_pipe_map(pipe)) {
pr_err("unable to map base pipe\n");
- return;
+ goto pan_display_error;
}
ret = mdss_mdp_pipe_queue_data(pipe, &data);
mdss_mdp_pipe_unmap(pipe);
if (ret) {
pr_err("unable to queue data\n");
- return;
+ goto pan_display_error;
}
if (fbi->var.xres > MAX_MIXER_WIDTH || mfd->split_display) {
@@ -1063,46 +1088,56 @@
MDSS_MDP_MIXER_MUX_RIGHT);
if (ret) {
pr_err("unable to allocate right base pipe\n");
- return;
+ goto pan_display_error;
}
if (mdss_mdp_pipe_map(pipe)) {
pr_err("unable to map right base pipe\n");
- return;
+ goto pan_display_error;
}
ret = mdss_mdp_pipe_queue_data(pipe, &data);
mdss_mdp_pipe_unmap(pipe);
if (ret) {
pr_err("unable to queue right data\n");
- return;
+ goto pan_display_error;
}
}
- mutex_unlock(&mfd->ov_lock);
+ mutex_unlock(&mdp5_data->ov_lock);
if ((fbi->var.activate & FB_ACTIVATE_VBL) ||
(fbi->var.activate & FB_ACTIVATE_FORCE))
- mdss_mdp_overlay_kickoff(mfd->ctl);
+ mfd->mdp.kickoff_fnc(mfd);
+
+ return;
+
+pan_display_error:
+ mutex_unlock(&mdp5_data->ov_lock);
}
/* function is called in irq context should have minimum processing */
-static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
+static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
+ ktime_t t)
{
struct msm_fb_data_type *mfd = ctl->mfd;
- if (!mfd) {
+ struct mdss_overlay_private *mdp5_data;
+
+ if (!mfd || !mfd->mdp.private1) {
pr_warn("Invalid handle for vsync\n");
return;
}
+ mdp5_data = mfd_to_mdp5_data(mfd);
pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
- spin_lock(&mfd->vsync_lock);
- mfd->vsync_time = t;
- complete(&mfd->vsync_comp);
- spin_unlock(&mfd->vsync_lock);
+ spin_lock(&mdp5_data->vsync_lock);
+ mdp5_data->vsync_time = t;
+ complete(&mdp5_data->vsync_comp);
+ spin_unlock(&mdp5_data->vsync_lock);
}
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
{
- struct mdss_mdp_ctl *ctl = mfd->ctl;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
unsigned long flags;
int rc;
@@ -1118,16 +1153,16 @@
if (!ctl->power_on) {
pr_debug("fb%d vsync pending first update en=%d\n",
mfd->index, en);
- mfd->vsync_pending = en;
+ mdp5_data->vsync_pending = en;
mutex_unlock(&ctl->lock);
return 0;
}
pr_debug("fb%d vsync en=%d\n", mfd->index, en);
- spin_lock_irqsave(&mfd->vsync_lock, flags);
- INIT_COMPLETION(mfd->vsync_comp);
- spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+ spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
+ INIT_COMPLETION(mdp5_data->vsync_comp);
+ spin_unlock_irqrestore(&mdp5_data->vsync_lock, flags);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (en)
@@ -1146,26 +1181,27 @@
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
unsigned long flags;
u64 vsync_ticks;
unsigned long timeout;
int ret;
- if (!mfd->ctl || !mfd->ctl->power_on)
+ if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
return 0;
timeout = msecs_to_jiffies(VSYNC_PERIOD * 5);
- ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
+ ret = wait_for_completion_interruptible_timeout(&mdp5_data->vsync_comp,
timeout);
if (ret <= 0) {
pr_debug("Sending current time as vsync timestamp for fb%d\n",
mfd->index);
- mfd->vsync_time = ktime_get();
+ mdp5_data->vsync_time = ktime_get();
}
- spin_lock_irqsave(&mfd->vsync_lock, flags);
- vsync_ticks = ktime_to_ns(mfd->vsync_time);
- spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+ spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
+ vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
+ spin_unlock_irqrestore(&mdp5_data->vsync_lock, flags);
pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
@@ -1187,6 +1223,7 @@
static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
struct fb_cursor *cursor)
{
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_mixer *mixer;
struct fb_image *img = &cursor->image;
u32 blendcfg;
@@ -1215,12 +1252,12 @@
}
}
- mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+ mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
- (img->height > MDSS_MDP_CURSOR_HEIGHT) ||
- (img->depth != 32))
+ (img->height > MDSS_MDP_CURSOR_HEIGHT) ||
+ (img->depth != 32))
return -EINVAL;
pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable,
@@ -1316,13 +1353,227 @@
return 0;
}
+static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
+ struct mdp_bl_scale_data *data)
+{
+ int ret = 0;
+ int curr_bl;
+ mutex_lock(&mfd->lock);
+ curr_bl = mfd->bl_level;
+ mfd->bl_scale = data->scale;
+ mfd->bl_min_lvl = data->min_lvl;
+ pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
+ mfd->bl_min_lvl);
+
+ /* update current backlight to use new scaling*/
+ mdss_fb_set_backlight(mfd, curr_bl);
+ mutex_unlock(&mfd->lock);
+ return ret;
+}
+
+static int mdss_mdp_pp_ioctl(struct msm_fb_data_type *mfd,
+ void __user *argp)
+{
+ int ret;
+ struct msmfb_mdp_pp mdp_pp;
+ u32 copyback = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+ ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
+ if (ret)
+ return ret;
+
+ switch (mdp_pp.op) {
+ case mdp_op_pa_cfg:
+ ret = mdss_mdp_pa_config(mdp5_data->ctl,
+ &mdp_pp.data.pa_cfg_data,
+ ©back);
+ break;
+
+ case mdp_op_pcc_cfg:
+ ret = mdss_mdp_pcc_config(mdp5_data->ctl,
+ &mdp_pp.data.pcc_cfg_data,
+ ©back);
+ break;
+
+ case mdp_op_lut_cfg:
+ switch (mdp_pp.data.lut_cfg_data.lut_type) {
+ case mdp_lut_igc:
+ ret = mdss_mdp_igc_lut_config(
+ mdp5_data->ctl,
+ (struct mdp_igc_lut_data *)
+ &mdp_pp.data.lut_cfg_data.data,
+ ©back);
+ break;
+
+ case mdp_lut_pgc:
+ ret = mdss_mdp_argc_config(
+ mdp5_data->ctl,
+ &mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
+ ©back);
+ break;
+
+ case mdp_lut_hist:
+ ret = mdss_mdp_hist_lut_config(
+ mdp5_data->ctl,
+ (struct mdp_hist_lut_data *)
+ &mdp_pp.data.lut_cfg_data.data, ©back);
+ break;
+
+ default:
+ ret = -ENOTSUPP;
+ break;
+ }
+ break;
+ case mdp_op_dither_cfg:
+ ret = mdss_mdp_dither_config(
+ mdp5_data->ctl,
+ &mdp_pp.data.dither_cfg_data,
+ ©back);
+ break;
+ case mdp_op_gamut_cfg:
+ ret = mdss_mdp_gamut_config(
+ mdp5_data->ctl,
+ &mdp_pp.data.gamut_cfg_data,
+ ©back);
+ break;
+ case mdp_bl_scale_cfg:
+ ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+ &mdp_pp.data.bl_scale_data);
+ break;
+ default:
+ pr_err("Unsupported request to MDP_PP IOCTL.\n");
+ ret = -EINVAL;
+ break;
+ }
+ if ((ret == 0) && copyback)
+ ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
+ return ret;
+}
+
+static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
+ void __user *argp)
+{
+ int ret = -ENOSYS;
+ struct mdp_histogram_data hist;
+ struct mdp_histogram_start_req hist_req;
+ u32 block, hist_data_addr = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+ switch (cmd) {
+ case MSMFB_HISTOGRAM_START:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+
+ ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+ if (ret)
+ return ret;
+
+ ret = mdss_mdp_histogram_start(mdp5_data->ctl, &hist_req);
+ break;
+
+ case MSMFB_HISTOGRAM_STOP:
+ ret = copy_from_user(&block, argp, sizeof(int));
+ if (ret)
+ return ret;
+
+ ret = mdss_mdp_histogram_stop(mdp5_data->ctl, block);
+ break;
+
+ case MSMFB_HISTOGRAM:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+
+ ret = copy_from_user(&hist, argp, sizeof(hist));
+ if (ret)
+ return ret;
+
+ ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist,
+ &hist_data_addr);
+ if ((ret == 0) && hist_data_addr) {
+ ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
+ sizeof(u32) * hist.bin_cnt);
+ if (ret == 0)
+ ret = copy_to_user(argp, &hist,
+ sizeof(hist));
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
+ struct msmfb_metadata *metadata)
+{
+ int ret = 0;
+ switch (metadata->op) {
+ case metadata_op_vic:
+ if (mfd->panel_info)
+ mfd->panel_info->vic =
+ metadata->data.video_info_code;
+ else
+ ret = -EINVAL;
+ break;
+ default:
+ pr_warn("unsupported request to MDP META IOCTL\n");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
+ struct mdss_hw_caps *caps)
+{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+ caps->mdp_rev = mdata->mdp_rev;
+ caps->vig_pipes = mdata->nvig_pipes;
+ caps->rgb_pipes = mdata->nrgb_pipes;
+ caps->dma_pipes = mdata->ndma_pipes;
+ return 0;
+}
+
+static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
+ struct msmfb_metadata *metadata)
+{
+ int ret = 0;
+ switch (metadata->op) {
+ case metadata_op_frame_rate:
+ metadata->data.panel_frame_rate =
+ mdss_get_panel_framerate(mfd);
+ break;
+ case metadata_op_get_caps:
+ ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
+ break;
+ default:
+ pr_warn("Unsupported request to MDP META IOCTL.\n");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
u32 cmd, void __user *argp)
{
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdp_overlay req;
int val, ret = -ENOSYS;
+ struct msmfb_metadata metadata;
switch (cmd) {
+ case MSMFB_MDP_PP:
+ ret = mdss_mdp_pp_ioctl(mfd, argp);
+ break;
+
+ case MSMFB_HISTOGRAM_START:
+ case MSMFB_HISTOGRAM_STOP:
+ case MSMFB_HISTOGRAM:
+ ret = mdss_mdp_histo_ioctl(mfd, cmd, argp);
+ break;
+
case MSMFB_OVERLAY_GET:
ret = copy_from_user(&req, argp, sizeof(req));
if (!ret) {
@@ -1360,7 +1611,7 @@
case MSMFB_OVERLAY_PLAY_ENABLE:
if (!copy_from_user(&val, argp, sizeof(val))) {
- mfd->overlay_play_enable = val;
+ mdp5_data->overlay_play_enable = val;
} else {
pr_err("OVERLAY_PLAY_ENABLE failed (%d)\n", ret);
ret = -EFAULT;
@@ -1368,7 +1619,7 @@
break;
case MSMFB_OVERLAY_PLAY:
- if (mfd->overlay_play_enable) {
+ if (mdp5_data->overlay_play_enable) {
struct msmfb_overlay_data data;
ret = copy_from_user(&data, argp, sizeof(data));
@@ -1388,7 +1639,7 @@
break;
case MSMFB_OVERLAY_PLAY_WAIT:
- if (mfd->overlay_play_enable) {
+ if (mdp5_data->overlay_play_enable) {
struct msmfb_overlay_data data;
ret = copy_from_user(&data, argp, sizeof(data));
@@ -1415,9 +1666,23 @@
break;
case MSMFB_OVERLAY_COMMIT:
mdss_fb_wait_for_fence(mfd);
- ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+ ret = mfd->mdp.kickoff_fnc(mfd);
mdss_fb_signal_timeline(mfd);
break;
+ case MSMFB_METADATA_SET:
+ ret = copy_from_user(&metadata, argp, sizeof(metadata));
+ if (ret)
+ return ret;
+ ret = mdss_fb_set_metadata(mfd, &metadata);
+ break;
+ case MSMFB_METADATA_GET:
+ ret = copy_from_user(&metadata, argp, sizeof(metadata));
+ if (ret)
+ return ret;
+ ret = mdss_fb_get_metadata(mfd, &metadata);
+ if (!ret)
+ ret = copy_to_user(argp, &metadata, sizeof(metadata));
+ break;
default:
if (mfd->panel.type == WRITEBACK_PANEL)
ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -1429,7 +1694,8 @@
static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
{
- int rc = 0;
+ int rc;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
if (!mfd)
return -ENODEV;
@@ -1437,7 +1703,7 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- if (!mfd->ctl) {
+ if (!mdp5_data->ctl) {
struct mdss_mdp_ctl *ctl;
struct mdss_panel_data *pdata;
@@ -1462,22 +1728,22 @@
return rc;
}
}
- mfd->ctl = ctl;
+ mdp5_data->ctl = ctl;
}
if (!mfd->panel_info->cont_splash_enabled) {
rc = mdss_mdp_overlay_start(mfd);
if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL))
- rc = mdss_mdp_overlay_kickoff(mfd->ctl);
+ rc = mdss_mdp_overlay_kickoff(mfd);
} else {
- rc = mdss_mdp_ctl_setup(mfd->ctl);
+ rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
if (rc)
return rc;
}
- if (!IS_ERR_VALUE(rc) && mfd->vsync_pending) {
- mfd->vsync_pending = 0;
- mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+ if (!IS_ERR_VALUE(rc) && mdp5_data->vsync_pending) {
+ mdp5_data->vsync_pending = 0;
+ mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
}
return rc;
@@ -1486,6 +1752,7 @@
static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd)
{
int rc;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
if (!mfd)
return -ENODEV;
@@ -1493,22 +1760,22 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- if (!mfd->ctl) {
+ if (!mdp5_data->ctl) {
pr_err("ctl not initialized\n");
return -ENODEV;
}
- if (!mfd->ctl->power_on)
+ if (!mdp5_data->ctl->power_on)
return 0;
mdss_mdp_overlay_release_all(mfd);
- rc = mdss_mdp_ctl_stop(mfd->ctl);
+ rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
if (rc == 0) {
if (!mfd->ref_cnt) {
- mfd->borderfill_enable = false;
- mdss_mdp_ctl_destroy(mfd->ctl);
- mfd->ctl = NULL;
+ mdp5_data->borderfill_enable = false;
+ mdss_mdp_ctl_destroy(mdp5_data->ctl);
+ mdp5_data->ctl = NULL;
}
if (atomic_dec_return(&ov_active_panels) == 0)
@@ -1522,39 +1789,63 @@
return rc;
}
+int mdss_panel_register_done(struct mdss_panel_data *pdata)
+{
+ /*
+ * Clocks are already on if continuous splash is enabled,
+ * increasing ref_cnt to help balance clocks once done.
+ */
+ if (pdata->panel_info.cont_splash_enabled) {
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_footswitch_ctrl_splash(1);
+ mdss_mdp_copy_splash_screen(pdata);
+ }
+ return 0;
+}
+
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
+ struct msm_mdp_interface *mdp5_interface = &mfd->mdp;
+ struct mdss_overlay_private *mdp5_data = NULL;
int rc;
- mfd->mdata = dev_get_drvdata(mfd->pdev->dev.parent);
- if (!mfd->mdata) {
- pr_err("unable to initialize overlay for fb%d\n", mfd->index);
- return -ENODEV;
+ mdp5_interface->on_fnc = mdss_mdp_overlay_on;
+ mdp5_interface->off_fnc = mdss_mdp_overlay_off;
+ mdp5_interface->do_histogram = NULL;
+ mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update;
+ mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display;
+ mdp5_interface->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
+ mdp5_interface->panel_register_done = mdss_panel_register_done;
+ mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
+
+ mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
+ if (!mdp5_data) {
+ pr_err("fail to allocate mdp5 private data structure");
+ return -ENOMEM;
}
+ memset(mdp5_data, 0, sizeof(struct mdss_overlay_private));
- mfd->on_fnc = mdss_mdp_overlay_on;
- mfd->off_fnc = mdss_mdp_overlay_off;
- mfd->hw_refresh = true;
- mfd->do_histogram = NULL;
- mfd->overlay_play_enable = true;
- mfd->cursor_update = mdss_mdp_hw_cursor_update;
- mfd->dma_fnc = mdss_mdp_overlay_pan_display;
- mfd->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
+ INIT_LIST_HEAD(&mdp5_data->pipes_used);
+ INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
+ init_completion(&mdp5_data->vsync_comp);
+ spin_lock_init(&mdp5_data->vsync_lock);
+ mutex_init(&mdp5_data->ov_lock);
+ mdp5_data->hw_refresh = true;
+ mdp5_data->overlay_play_enable = true;
- if (mfd->panel.type == WRITEBACK_PANEL)
- mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
-
- INIT_LIST_HEAD(&mfd->pipes_used);
- INIT_LIST_HEAD(&mfd->pipes_cleanup);
- init_completion(&mfd->vsync_comp);
- spin_lock_init(&mfd->vsync_lock);
- mutex_init(&mfd->ov_lock);
+ mdp5_data->mdata = dev_get_drvdata(mfd->pdev->dev.parent);
+ if (!mdp5_data->mdata) {
+ pr_err("unable to initialize overlay for fb%d\n", mfd->index);
+ rc = -ENODEV;
+ goto init_fail;
+ }
+ mfd->mdp.private1 = mdp5_data;
rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
if (rc) {
pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
- return rc;
+ goto init_fail;
}
pm_runtime_set_suspended(&mfd->pdev->dev);
@@ -1564,4 +1855,7 @@
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
return rc;
+init_fail:
+ kfree(mdp5_data);
+ return rc;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 7ff6414..b169c43 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -19,7 +19,9 @@
#include "mdss_mdp.h"
-#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
+#define SMP_MB_SIZE (mdss_res->smp_mb_size)
+#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
+#define SMP_ENTRIES_PER_MB (SMP_MB_SIZE / 16)
static DEFINE_MUTEX(mdss_mdp_sspp_lock);
static DEFINE_MUTEX(mdss_mdp_smp_lock);
@@ -29,6 +31,17 @@
u32 ndx);
static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe);
+static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
+ u32 reg, u32 val)
+{
+ writel_relaxed(val, pipe->base + reg);
+}
+
+static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
+{
+ return readl_relaxed(pipe->base + reg);
+}
+
static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
{
u32 i, mmb;
@@ -45,9 +58,10 @@
return i;
}
-static void mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
+static int mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
{
u32 mmb, off, data, s;
+ int cnt = 0;
for_each_set_bit(mmb, smp, SMP_MB_CNT) {
off = (mmb / 3) * 4;
@@ -57,7 +71,9 @@
data |= client_id << s;
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_W0 + off, data);
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_R0 + off, data);
+ cnt++;
}
+ return cnt;
}
static void mdss_mdp_smp_mmb_free(unsigned long *smp)
@@ -70,6 +86,24 @@
}
}
+static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt)
+{
+ u32 entries, val, wm[3];
+
+ entries = mb_cnt * SMP_ENTRIES_PER_MB;
+ val = entries >> 2;
+
+ wm[0] = val;
+ wm[1] = wm[0] + val;
+ wm[2] = wm[1] + val;
+
+ pr_debug("pnum=%d watermarks %u,%u,%u\n", pipe->num,
+ wm[0], wm[1], wm[2]);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0, wm[0]);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1, wm[1]);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2, wm[2]);
+}
+
static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
{
mutex_lock(&mdss_mdp_smp_lock);
@@ -85,25 +119,31 @@
u32 num_blks = 0, reserved = 0;
struct mdss_mdp_plane_sizes ps;
int i, rc;
+ u32 nlines;
- if ((mdata->mdp_rev >= MDSS_MDP_HW_REV_102) &&
+ if (pipe->bwc_mode) {
+ rc = mdss_mdp_get_rau_strides(pipe->src.w, pipe->src.h,
+ pipe->src_fmt, &ps);
+ if (rc)
+ return rc;
+ pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
+ ps.ystride[0], ps.ystride[1]);
+ } else if ((mdata->mdp_rev >= MDSS_MDP_HW_REV_102) &&
pipe->src_fmt->is_yuv) {
ps.num_planes = 2;
ps.ystride[0] = pipe->src.w;
ps.ystride[1] = pipe->src.w;
} else {
rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
- pipe->src.w, pipe->src.h, &ps);
+ pipe->src.w, pipe->src.h, &ps, 0);
if (rc)
return rc;
}
- if ((ps.num_planes > 1) && (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
- return -EINVAL;
-
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < ps.num_planes; i++) {
- num_blks = DIV_ROUND_UP(2 * ps.ystride[i],
+ nlines = pipe->bwc_mode ? ps.rau_h[i] : 2;
+ num_blks = DIV_ROUND_UP(nlines * ps.ystride[i],
mdss_res->smp_mb_size);
if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
@@ -131,9 +171,12 @@
static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
{
int i;
+ int cnt = 0;
+
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < MAX_PLANES; i++)
- mdss_mdp_smp_mmb_set(pipe->ftch_id + i, &pipe->smp[i]);
+ cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i, &pipe->smp[i]);
+ mdss_mdp_smp_set_wm_levels(pipe, cnt);
mutex_unlock(&mdss_mdp_smp_lock);
return 0;
}
@@ -305,6 +348,8 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_pipe_sspp_term(pipe);
mdss_mdp_smp_free(pipe);
+ pipe->flags = 0;
+ pipe->bwc_mode = 0;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return 0;
@@ -327,17 +372,6 @@
}
-static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
- u32 reg, u32 val)
-{
- writel_relaxed(val, pipe->base + reg);
-}
-
-static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
-{
- return readl_relaxed(pipe->base + reg);
-}
-
static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
{
u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
@@ -351,7 +385,7 @@
width = pipe->img_width;
height = pipe->img_height;
mdss_mdp_get_plane_sizes(pipe->src_fmt->format, width, height,
- &pipe->src_planes);
+ &pipe->src_planes, pipe->bwc_mode);
if ((pipe->flags & MDP_DEINTERLACE) &&
!(pipe->flags & MDP_SOURCE_ROTATED_90)) {
@@ -391,8 +425,9 @@
static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
{
struct mdss_mdp_format_params *fmt;
- u32 opmode, chroma_samp, unpack, src_format;
+ u32 chroma_samp, unpack, src_format;
u32 secure = 0;
+ u32 opmode;
fmt = pipe->src_fmt;
@@ -529,8 +564,7 @@
pr_debug("pnum=%d\n", pipe->num);
- if (!is_rot)
- data->bwc_enabled = pipe->bwc_mode;
+ data->bwc_enabled = pipe->bwc_mode;
ret = mdss_mdp_data_check(data, &pipe->src_planes);
if (ret)
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 8bff5cb..5711653 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -203,7 +203,6 @@
rot_pipe->img_height = rot->img_height;
rot_pipe->src = rot->src_rect;
rot_pipe->dst = rot->src_rect;
- rot_pipe->bwc_mode = rot->bwc_mode;
rot_pipe->params_changed++;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index c46f271..21ee9bb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -45,10 +45,14 @@
static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
{
switch (in_format) {
+ case MDP_RGB_565:
+ case MDP_BGR_565:
+ return MDP_RGB_888;
case MDP_Y_CBCR_H2V2_VENUS:
- return MDP_Y_CBCR_H2V2;
+ case MDP_Y_CB_CR_H2V2:
case MDP_Y_CR_CB_GH2V2:
- return MDP_Y_CR_CB_H2V2;
+ case MDP_Y_CR_CB_H2V2:
+ return MDP_Y_CRCB_H2V2;
default:
return in_format;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b54e0ec..5915f61 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -42,6 +42,9 @@
MDP_INTR_PING_PONG_0,
MDP_INTR_PING_PONG_1,
MDP_INTR_PING_PONG_2,
+ MDP_INTR_PING_PONG_0_RD_PTR,
+ MDP_INTR_PING_PONG_1_RD_PTR,
+ MDP_INTR_PING_PONG_2_RD_PTR,
MDP_INTR_WB_0,
MDP_INTR_WB_1,
MDP_INTR_WB_2,
@@ -69,6 +72,9 @@
case MDSS_MDP_IRQ_PING_PONG_COMP:
index = MDP_INTR_PING_PONG_0 + intf_num;
break;
+ case MDSS_MDP_IRQ_PING_PONG_RD_PTR:
+ index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num;
+ break;
case MDSS_MDP_IRQ_WB_ROT_COMP:
index = MDP_INTR_WB_0 + intf_num;
break;
@@ -126,11 +132,12 @@
if (isr == 0)
goto mdp_isr_done;
- pr_debug("isr=%x\n", isr);
mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
+ pr_debug("%s: isr=%x mask=%x\n", __func__, isr, mask);
+
isr &= mask;
if (isr == 0)
goto mdp_isr_done;
@@ -156,6 +163,15 @@
if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
+ if (isr & MDSS_MDP_INTR_PING_PONG_0_RD_PTR)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_RD_PTR);
+
+ if (isr & MDSS_MDP_INTR_PING_PONG_1_RD_PTR)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_RD_PTR);
+
+ if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
+
if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
@@ -205,11 +221,48 @@
return NULL;
}
+int mdss_mdp_get_rau_strides(u32 w, u32 h,
+ struct mdss_mdp_format_params *fmt,
+ struct mdss_mdp_plane_sizes *ps)
+{
+ u32 stride_off;
+ if (fmt->is_yuv) {
+ ps->rau_cnt = DIV_ROUND_UP(w, 64);
+ ps->ystride[0] = 64 * 4;
+ ps->rau_h[0] = 4;
+ ps->rau_h[1] = 2;
+ if (fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)
+ ps->ystride[1] = 64 * 2;
+ else if (fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1) {
+ ps->ystride[1] = 32 * 4;
+ ps->rau_h[1] = 4;
+ } else
+ ps->ystride[1] = 32 * 2;
+ } else if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+ ps->rau_cnt = DIV_ROUND_UP(w, 32);
+ ps->ystride[0] = 32 * 4;
+ ps->ystride[1] = 0;
+ ps->rau_h[0] = 4;
+ ps->rau_h[1] = 0;
+ } else {
+ pr_err("Invalid format=%d\n", fmt->format);
+ return -EINVAL;
+ }
+
+ stride_off = DIV_ROUND_UP(ps->rau_cnt, 8);
+ ps->ystride[0] = ps->ystride[0] * ps->rau_cnt * fmt->bpp + stride_off;
+ ps->ystride[1] = ps->ystride[1] * ps->rau_cnt * fmt->bpp + stride_off;
+ ps->num_planes = 2;
+
+ return 0;
+}
+
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
- struct mdss_mdp_plane_sizes *ps)
+ struct mdss_mdp_plane_sizes *ps, u32 bwc_mode)
{
struct mdss_mdp_format_params *fmt;
- int i;
+ int i, rc;
+ u32 bpp, stride_off;
if (ps == NULL)
return -EINVAL;
@@ -221,55 +274,69 @@
if (!fmt)
return -EINVAL;
+ bpp = fmt->bpp;
memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
- if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
- u32 bpp = fmt->bpp;
- ps->num_planes = 1;
- ps->plane_size[0] = w * h * bpp;
- ps->ystride[0] = w * bpp;
- } else if (format == MDP_Y_CBCR_H2V2_VENUS) {
- int cf = COLOR_FMT_NV12;
- ps->num_planes = 2;
- ps->ystride[0] = VENUS_Y_STRIDE(cf, w);
- ps->ystride[1] = VENUS_UV_STRIDE(cf, w);
- ps->plane_size[0] = VENUS_Y_SCANLINES(cf, h) * ps->ystride[0];
- ps->plane_size[1] = VENUS_UV_SCANLINES(cf, h) * ps->ystride[1];
+ if (bwc_mode) {
+ rc = mdss_mdp_get_rau_strides(w, h, fmt, ps);
+ if (rc)
+ return rc;
+ stride_off = DIV_ROUND_UP(h, ps->rau_h[0]);
+ ps->ystride[0] = ps->ystride[0] + ps->ystride[1];
+ ps->plane_size[0] = ps->ystride[0] * stride_off;
+ ps->ystride[1] = 2;
+ ps->plane_size[1] = ps->rau_cnt * ps->ystride[1] * stride_off;
+
} else {
- u8 hmap[] = { 1, 2, 1, 2 };
- u8 vmap[] = { 1, 1, 2, 2 };
- u8 horiz, vert, stride_align, height_align;
-
- horiz = hmap[fmt->chroma_sample];
- vert = vmap[fmt->chroma_sample];
-
- switch (format) {
- case MDP_Y_CR_CB_GH2V2:
- stride_align = 16;
- height_align = 1;
- break;
- default:
- stride_align = 1;
- height_align = 1;
- break;
- }
-
- ps->ystride[0] = ALIGN(w, stride_align);
- ps->ystride[1] = ALIGN(w / horiz, stride_align);
- ps->plane_size[0] = ps->ystride[0] * ALIGN(h, height_align);
- ps->plane_size[1] = ps->ystride[1] * (h / vert);
-
- if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
+ if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+ ps->num_planes = 1;
+ ps->plane_size[0] = w * h * bpp;
+ ps->ystride[0] = w * bpp;
+ } else if (format == MDP_Y_CBCR_H2V2_VENUS) {
+ int cf = COLOR_FMT_NV12;
ps->num_planes = 2;
- ps->plane_size[1] *= 2;
- ps->ystride[1] *= 2;
- } else { /* planar */
- ps->num_planes = 3;
- ps->plane_size[2] = ps->plane_size[1];
- ps->ystride[2] = ps->ystride[1];
+ ps->ystride[0] = VENUS_Y_STRIDE(cf, w);
+ ps->ystride[1] = VENUS_UV_STRIDE(cf, w);
+ ps->plane_size[0] = VENUS_Y_SCANLINES(cf, h) *
+ ps->ystride[0];
+ ps->plane_size[1] = VENUS_UV_SCANLINES(cf, h) *
+ ps->ystride[1];
+ } else {
+ u8 hmap[] = { 1, 2, 1, 2 };
+ u8 vmap[] = { 1, 1, 2, 2 };
+ u8 horiz, vert, stride_align, height_align;
+
+ horiz = hmap[fmt->chroma_sample];
+ vert = vmap[fmt->chroma_sample];
+
+ switch (format) {
+ case MDP_Y_CR_CB_GH2V2:
+ stride_align = 16;
+ height_align = 1;
+ break;
+ default:
+ stride_align = 1;
+ height_align = 1;
+ break;
+ }
+
+ ps->ystride[0] = ALIGN(w, stride_align);
+ ps->ystride[1] = ALIGN(w / horiz, stride_align);
+ ps->plane_size[0] = ps->ystride[0] *
+ ALIGN(h, height_align);
+ ps->plane_size[1] = ps->ystride[1] * (h / vert);
+
+ if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
+ ps->num_planes = 2;
+ ps->plane_size[1] *= 2;
+ ps->ystride[1] *= 2;
+ } else { /* planar */
+ ps->num_planes = 3;
+ ps->plane_size[2] = ps->plane_size[1];
+ ps->ystride[2] = ps->ystride[1];
+ }
}
}
-
for (i = 0; i < ps->num_planes; i++)
ps->total_size += ps->plane_size[i];
@@ -286,7 +353,8 @@
return -ENOMEM;
if (data->bwc_enabled) {
- return -EPERM; /* not supported */
+ data->num_planes = ps->num_planes;
+ data->p[1].addr = data->p[0].addr + ps->plane_size[0];
} else {
struct mdss_mdp_img_data *prev, *curr;
int i;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index d24a7c9..88e7605 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -124,18 +124,13 @@
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable)
{
- struct mdss_mdp_wb *wb;
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_mixer *mixer;
pr_debug("setting secure=%d\n", enable);
- wb = mfd->wb;
- if (wb == NULL) {
- pr_err("Invalid writeback session\n");
- return -ENODEV;
- }
-
wb->is_secure = enable;
pipe = wb->secure_pipe;
@@ -149,7 +144,7 @@
return 0;
}
- mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
if (!mixer) {
pr_err("Unable to find mixer for wb\n");
return -ENOENT;
@@ -190,14 +185,14 @@
static int mdss_mdp_wb_init(struct msm_fb_data_type *mfd)
{
- struct mdss_mdp_wb *wb;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
mutex_lock(&mdss_mdp_wb_buf_lock);
- wb = mfd->wb;
if (wb == NULL) {
wb = &mdss_mdp_wb_info;
wb->fb_ndx = mfd->index;
- mfd->wb = wb;
+ mdp5_data->wb = wb;
} else if (mfd->index != wb->fb_ndx) {
pr_err("only one writeback intf supported at a time\n");
return -EMLINK;
@@ -214,14 +209,15 @@
wb->state = WB_OPEN;
init_waitqueue_head(&wb->wait_q);
- mfd->wb = wb;
+ mdp5_data->wb = wb;
mutex_unlock(&mdss_mdp_wb_buf_lock);
return 0;
}
static int mdss_mdp_wb_terminate(struct msm_fb_data_type *mfd)
{
- struct mdss_mdp_wb *wb = mfd->wb;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
if (!wb) {
pr_err("unable to terminate, writeback is not initialized\n");
@@ -246,7 +242,7 @@
mdss_mdp_pipe_destroy(wb->secure_pipe);
mutex_unlock(&wb->lock);
- mfd->wb = NULL;
+ mdp5_data->wb = NULL;
mutex_unlock(&mdss_mdp_wb_buf_lock);
return 0;
@@ -254,7 +250,7 @@
static int mdss_mdp_wb_start(struct msm_fb_data_type *mfd)
{
- struct mdss_mdp_wb *wb = mfd->wb;
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
if (!wb) {
pr_err("unable to start, writeback is not initialized\n");
@@ -271,7 +267,7 @@
static int mdss_mdp_wb_stop(struct msm_fb_data_type *mfd)
{
- struct mdss_mdp_wb *wb = mfd->wb;
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
if (!wb) {
pr_err("unable to stop, writeback is not initialized\n");
@@ -343,8 +339,10 @@
}
static struct mdss_mdp_wb_data *get_user_node(struct msm_fb_data_type *mfd,
- struct msmfb_data *data) {
- struct mdss_mdp_wb *wb = mfd->wb;
+ struct msmfb_data *data)
+{
+
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
struct mdss_mdp_wb_data *node;
struct mdss_mdp_img_data *buf;
int ret;
@@ -383,9 +381,9 @@
}
static int mdss_mdp_wb_queue(struct msm_fb_data_type *mfd,
- struct msmfb_data *data, int local)
+ struct msmfb_data *data, int local)
{
- struct mdss_mdp_wb *wb = mfd->wb;
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
struct mdss_mdp_wb_data *node = NULL;
int ret = 0;
@@ -426,9 +424,9 @@
}
static int mdss_mdp_wb_dequeue(struct msm_fb_data_type *mfd,
- struct msmfb_data *data)
+ struct msmfb_data *data)
{
- struct mdss_mdp_wb *wb = mfd->wb;
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
struct mdss_mdp_wb_data *node = NULL;
int ret;
@@ -473,9 +471,10 @@
complete((struct completion *) arg);
}
-int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd)
{
- struct mdss_mdp_wb *wb;
+ struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_mdp_wb_data *node = NULL;
int ret = 0;
DECLARE_COMPLETION_ONSTACK(comp);
@@ -484,14 +483,10 @@
.priv_data = &comp,
};
- if (!ctl || !ctl->mfd)
- return -ENODEV;
-
if (!ctl->power_on)
return 0;
mutex_lock(&mdss_mdp_wb_buf_lock);
- wb = ctl->mfd->wb;
if (wb) {
mutex_lock(&wb->lock);
/* in case of reinit of control path need to reset secure */
@@ -540,7 +535,8 @@
return ret;
}
-int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg)
+int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd,
+ void *arg)
{
struct msmfb_data data;
int ret = -ENOSYS;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 31fb2e7..23f7445 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -58,9 +58,9 @@
enum mdss_intf_events {
MDSS_EVENT_RESET,
MDSS_EVENT_UNBLANK,
- MDSS_EVENT_TIMEGEN_ON,
+ MDSS_EVENT_PANEL_ON,
MDSS_EVENT_BLANK,
- MDSS_EVENT_TIMEGEN_OFF,
+ MDSS_EVENT_PANEL_OFF,
MDSS_EVENT_CLOSE,
MDSS_EVENT_SUSPEND,
MDSS_EVENT_RESUME,
@@ -69,19 +69,7 @@
MDSS_EVENT_FB_REGISTERED,
};
-/* panel info type */
struct lcd_panel_info {
- u32 vsync_enable;
- u32 refx100;
- u32 v_back_porch;
- u32 v_front_porch;
- u32 v_pulse_width;
- u32 hw_vsync_mode;
- u32 vsync_notifier_period;
- u32 rev;
-};
-
-struct lcdc_panel_info {
u32 h_back_porch;
u32 h_front_porch;
u32 h_pulse_width;
@@ -153,6 +141,9 @@
char no_max_pkt_size;
/* Clock required during LP commands */
char force_clk_lane_hs;
+
+ char vsync_enable;
+ char hw_vsync_mode;
};
enum lvds_mode {
@@ -183,13 +174,16 @@
u32 is_3d_panel;
u32 out_format;
u32 vic; /* video identification code */
+ int bklt_ctrl; /* backlight ctrl */
+ int pwm_gpio;
+ int pwm_lpg_chan;
+ int pwm_period;
u32 cont_splash_enabled;
struct ion_handle *splash_ihdl;
u32 panel_power_on;
- struct lcd_panel_info lcd;
- struct lcdc_panel_info lcdc;
+ struct lcd_panel_info lcdc;
struct mipi_panel_info mipi;
struct lvds_panel_info lvds;
};
diff --git a/drivers/video/msm/mdss/mdss_qpic.c b/drivers/video/msm/mdss/mdss_qpic.c
index 647504f..be02113 100644
--- a/drivers/video/msm/mdss/mdss_qpic.c
+++ b/drivers/video/msm/mdss/mdss_qpic.c
@@ -113,11 +113,24 @@
(u32 *)fb_offset, size);
}
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
- u32 size, u32 *phys, void **virt)
+int mdss_qpic_alloc_fb_mem(struct msm_fb_data_type *mfd)
{
+ size_t size;
+ u32 yres = mfd->fbi->var.yres_virtual;
+
+ size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
if (!qpic_res->res_init)
return -EINVAL;
+
+ if (mfd->index != 0) {
+ mfd->fbi->fix.smem_start = 0;
+ mfd->fbi->screen_base = NULL;
+ mfd->fbi->fix.smem_len = 0;
+ mfd->iova = 0;
+ return 0;
+ }
+
if (!qpic_res->fb_virt) {
qpic_res->fb_virt = (void *)dmam_alloc_coherent(
&qpic_res->pdev->dev,
@@ -132,29 +145,31 @@
qpic_res->cmd_buf_virt = qpic_res->fb_virt + size;
qpic_res->cmd_buf_phys = qpic_res->fb_phys + size;
}
- *phys = qpic_res->fb_phys;
- *virt = qpic_res->fb_virt;
+ mfd->fbi->fix.smem_start = qpic_res->fb_phys;
+ mfd->fbi->screen_base = qpic_res->fb_virt;
+ mfd->fbi->fix.smem_len = size;
+ mfd->iova = 0;
return 0;
}
-u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
+u32 mdss_qpic_fb_stride(u32 fb_index, u32 xres, int bpp)
{
return xres * bpp;
}
-int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
+int mdss_qpic_overlay_init(struct msm_fb_data_type *mfd)
{
- mfd->on_fnc = qpic_on;
- mfd->off_fnc = qpic_off;
- mfd->dma_fnc = mdss_qpic_pan_display;
+ struct msm_mdp_interface *qpic_interface = &mfd->mdp;
+ qpic_interface->on_fnc = qpic_on;
+ qpic_interface->off_fnc = qpic_off;
+ qpic_interface->do_histogram = NULL;
+ qpic_interface->cursor_update = NULL;
+ qpic_interface->dma_fnc = mdss_qpic_pan_display;
+ qpic_interface->ioctl_handler = NULL;
+ qpic_interface->kickoff_fnc = NULL;
return 0;
}
-u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
-{
- return qpic_panel_get_framerate();
-}
-
int qpic_register_panel(struct mdss_panel_data *pdata)
{
struct platform_device *mdss_fb_dev = NULL;
@@ -511,6 +526,12 @@
{
struct resource *res;
int rc = 0;
+ static struct msm_mdp_interface qpic_interface = {
+ .init_fnc = mdss_qpic_overlay_init,
+ .fb_mem_alloc_fnc = mdss_qpic_alloc_fb_mem,
+ .fb_stride = mdss_qpic_fb_stride,
+ };
+
if (!pdev->dev.of_node) {
pr_err("qpic driver only supports device tree probe\n");
@@ -564,6 +585,11 @@
qpic_res->irq = res->start;
qpic_res->res_init = true;
+
+ rc = mdss_fb_register_mdp_instance(&qpic_interface);
+ if (rc)
+ pr_err("unable to register QPIC instance\n");
+
probe_done:
return rc;
}
@@ -585,124 +611,4 @@
module_init(mdss_qpic_driver_init);
-int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
- struct mdp_pa_cfg_data *config, u32 *copyback)
-{
- return 0;
-}
-int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
- struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback)
-{
- return 0;
-}
-
-int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
- struct mdp_igc_lut_data *config, u32 *copyback)
-{
- return 0;
-}
-
-int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
- struct mdp_pgc_lut_data *config, u32 *copyback)
-{
- return 0;
-}
-
-int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
- struct mdp_hist_lut_data *config, u32 *copyback)
-{
- return 0;
-}
-
-int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
- struct mdp_dither_cfg_data *config, u32 *copyback)
-{
- return 0;
-}
-
-int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
- struct mdp_gamut_cfg_data *config, u32 *copyback)
-{
- return 0;
-}
-
-int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
- struct mdp_histogram_start_req *req)
-{
- return 0;
-}
-
-int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
-{
- return 0;
-}
-
-int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
- struct mdp_histogram_data *hist,
- u32 *hist_data_addr)
-{
- return 0;
-}
-
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
-{
- return 0;
-}
-
-void mdss_mdp_clk_ctrl(int enable, int isr)
-{
-}
-
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
-{
- return 0;
-}
-
-void mdss_mdp_footswitch_ctrl_splash(int on)
-{
-}
-
-int msm_fb_writeback_init(struct fb_info *info)
-{
- return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_init);
-
-int msm_fb_writeback_start(struct fb_info *info)
-{
- return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_start);
-
-int msm_fb_writeback_queue_buffer(struct fb_info *info,
- struct msmfb_data *data)
-{
- return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_queue_buffer);
-
-int msm_fb_writeback_dequeue_buffer(struct fb_info *info,
- struct msmfb_data *data)
-{
- return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer);
-
-int msm_fb_writeback_stop(struct fb_info *info)
-{
- return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_stop);
-
-int msm_fb_writeback_terminate(struct fb_info *info)
-{
- return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_terminate);
-
-int msm_fb_get_iommu_domain(struct fb_info *info, int domain)
-{
- return 0;
-}
-EXPORT_SYMBOL(msm_fb_get_iommu_domain);
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index d208f1e..969b400 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -20,12 +20,14 @@
#define DEINIT_TYPE 16
#define USER_SPACE_DATA_TYPE 32
#define DCI_DATA_TYPE 64
+#define CALLBACK_DATA_TYPE 128
#define USB_MODE 1
#define MEMORY_DEVICE_MODE 2
#define NO_LOGGING_MODE 3
#define UART_MODE 4
#define SOCKET_MODE 5
#define CALLBACK_MODE 6
+#define MEMORY_DEVICE_MODE_NRT 7
/* different values that go in for diag_data_type */
#define DATA_TYPE_EVENT 0
#define DATA_TYPE_F3 1
diff --git a/include/linux/ion.h b/include/linux/ion.h
index fb1c5f6..7c54004 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -59,6 +59,9 @@
cached, ion will do cache
maintenance when the buffer is
mapped for dma */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created
+ at mmap time, if this is set
+ caches must be managed manually */
#ifdef __KERNEL__
#include <linux/err.h>
@@ -606,6 +609,16 @@
#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
/**
+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
+ *
+ * Deprecated in favor of using the dma_buf api's correctly (syncing
+ * will happend automatically when the buffer is mapped to a device).
+ * If necessary should be used after touching a cached buffer from the cpu,
+ * this will make the buffer in memory coherent.
+ */
+#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+
+/**
* DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
*
* Takes the argument of the architecture specific ioctl to call and
diff --git a/include/linux/mfd/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
index fa97ba9..98ec93f 100644
--- a/include/linux/mfd/pm8xxx/misc.h
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -224,6 +224,16 @@
* RETURNS: an appropriate -ERRNO error value on error, or zero for success.
*/
int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable);
+
+/**
+ * pm8xxx_read_register - Read a PMIC register
+ * @addr: PMIC register address
+ * @value: Output parameter which gets the value of the register read.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_read_register(u16 addr, u8 *value);
+
#else
static inline int pm8xxx_reset_pwr_off(int reset)
@@ -278,6 +288,10 @@
{
return -ENODEV;
}
+static inline int pm8xxx_read_register(u16 addr, u8 *value)
+{
+ return -ENODEV;
+}
#endif
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca7a586..5dc65bd 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -61,14 +61,6 @@
MIGRATE_TYPES
};
-/*
- * Returns a list which contains the migrate types on to which
- * an allocation falls back when the free list for the migrate
- * type mtype is depleted.
- * The end of the list is delimited by the type MIGRATE_RESERVE.
- */
-extern int *get_migratetype_fallbacks(int mtype);
-
#ifdef CONFIG_CMA
bool is_cma_pageblock(struct page *page);
# define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 646c22e..3d159c4 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -57,7 +57,8 @@
struct msm_spk_prot_cfg)
#define AUDIO_GET_SPEAKER_PROT _IOR(AUDIO_IOCTL_MAGIC, 26, \
struct msm_spk_prot_status)
-
+#define AUDIO_SET_AANC_CAL _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+27), unsigned)
#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+30)
/* ACDB structures */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index b7d393f..307be2b 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -200,6 +200,26 @@
unsigned int dev_minor;
};
+/* Performance counter groups */
+
+#define KGSL_PERFCOUNTER_GROUP_CP 0x0
+#define KGSL_PERFCOUNTER_GROUP_RBBM 0x1
+#define KGSL_PERFCOUNTER_GROUP_PC 0x2
+#define KGSL_PERFCOUNTER_GROUP_VFD 0x3
+#define KGSL_PERFCOUNTER_GROUP_HLSQ 0x4
+#define KGSL_PERFCOUNTER_GROUP_VPC 0x5
+#define KGSL_PERFCOUNTER_GROUP_TSE 0x6
+#define KGSL_PERFCOUNTER_GROUP_RAS 0x7
+#define KGSL_PERFCOUNTER_GROUP_UCHE 0x8
+#define KGSL_PERFCOUNTER_GROUP_TP 0x9
+#define KGSL_PERFCOUNTER_GROUP_SP 0xA
+#define KGSL_PERFCOUNTER_GROUP_RB 0xB
+#define KGSL_PERFCOUNTER_GROUP_PWR 0xC
+#define KGSL_PERFCOUNTER_GROUP_VBIF 0xD
+#define KGSL_PERFCOUNTER_GROUP_VBIF_PWR 0xE
+
+#define KGSL_PERFCOUNTER_NOT_USED 0xFFFFFFFF
+
/* structure holds list of ibs */
struct kgsl_ibdesc {
unsigned int gpuaddr;
@@ -650,6 +670,110 @@
#define IOCTL_KGSL_GPUMEM_SYNC_CACHE \
_IOW(KGSL_IOC_TYPE, 0x37, struct kgsl_gpumem_sync_cache)
+/**
+ * struct kgsl_perfcounter_get - argument to IOCTL_KGSL_PERFCOUNTER_GET
+ * @groupid: Performance counter group ID
+ * @countable: Countable to select within the group
+ * @offset: Return offset of the reserved counter
+ *
+ * Get an available performance counter from a specified groupid. The offset
+ * of the performance counter will be returned after successfully assigning
+ * the countable to the counter for the specified group. An error will be
+ * returned and an offset of 0 if the groupid is invalid or there are no
+ * more counters left. After successfully getting a perfcounter, the user
+ * must call kgsl_perfcounter_put(groupid, contable) when finished with
+ * the perfcounter to clear up perfcounter resources.
+ *
+ */
+struct kgsl_perfcounter_get {
+ unsigned int groupid;
+ unsigned int countable;
+ unsigned int offset;
+/* private: reserved for future use */
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_GET \
+ _IOWR(KGSL_IOC_TYPE, 0x38, struct kgsl_perfcounter_get)
+
+/**
+ * struct kgsl_perfcounter_put - argument to IOCTL_KGSL_PERFCOUNTER_PUT
+ * @groupid: Performance counter group ID
+ * @countable: Countable to release within the group
+ *
+ * Put an allocated performance counter to allow others to have access to the
+ * resource that was previously taken. This is only to be called after
+ * successfully getting a performance counter from kgsl_perfcounter_get().
+ *
+ */
+struct kgsl_perfcounter_put {
+ unsigned int groupid;
+ unsigned int countable;
+/* private: reserved for future use */
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_PUT \
+ _IOW(KGSL_IOC_TYPE, 0x39, struct kgsl_perfcounter_put)
+
+/**
+ * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY
+ * @groupid: Performance counter group ID
+ * @countable: Return active countables array
+ * @size: Size of active countables array
+ * @max_counters: Return total number counters for the group ID
+ *
+ * Query the available performance counters given a groupid. The array
+ * *countables is used to return the current active countables in counters.
+ * The size of the array is passed in so the kernel will only write at most
+ * size or counter->size for the group id. The total number of available
+ * counters for the group ID is returned in max_counters.
+ * If the array or size passed in are invalid, then only the maximum number
+ * of counters will be returned, no data will be written to *countables.
+ * If the groupid is invalid an error code will be returned.
+ *
+ */
+struct kgsl_perfcounter_query {
+ unsigned int groupid;
+ /* Array to return the current countable for up to size counters */
+ unsigned int *countables;
+ unsigned int count;
+ unsigned int max_counters;
+/* private: reserved for future use */
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_QUERY \
+ _IOWR(KGSL_IOC_TYPE, 0x3A, struct kgsl_perfcounter_query)
+
+/**
+ * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY
+ * @groupid: Performance counter group IDs
+ * @countable: Performance counter countable IDs
+ * @value: Return performance counter reads
+ * @size: Size of all arrays (groupid/countable pair and return value)
+ *
+ * Read in the current value of a performance counter given by the groupid
+ * and countable.
+ *
+ */
+
+struct kgsl_perfcounter_read_group {
+ unsigned int groupid;
+ unsigned int countable;
+ uint64_t value;
+};
+
+struct kgsl_perfcounter_read {
+ struct kgsl_perfcounter_read_group *reads;
+ unsigned int count;
+/* private: reserved for future use */
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_READ \
+ _IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read)
+
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 5deff7a..7e1a709 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -170,7 +170,7 @@
#define MDP_SECURE_OVERLAY_SESSION 0x00008000
#define MDP_OV_PIPE_FORCE_DMA 0x00004000
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
-
+#define MDP_BWC_EN 0x00000400
#define MDP_TRANSP_NOP 0xffffffff
#define MDP_ALPHA_NOP 0xff
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0ab5143..84e099d 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1704,9 +1704,14 @@
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -1715,6 +1720,11 @@
NL80211_RATE_INFO_MCS,
NL80211_RATE_INFO_40_MHZ_WIDTH,
NL80211_RATE_INFO_SHORT_GI,
+ NL80211_RATE_INFO_VHT_MCS,
+ NL80211_RATE_INFO_VHT_NSS,
+ NL80211_RATE_INFO_80_MHZ_WIDTH,
+ NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+ NL80211_RATE_INFO_160_MHZ_WIDTH,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index a853aff..15e5dc9 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -637,34 +637,48 @@
* enum qpnp_tm_state - This lets the client know whether the threshold
* that was crossed was high/low.
* %ADC_TM_HIGH_STATE: Client is notified of crossing the requested high
- * threshold.
+ * voltage threshold.
+ * %ADC_TM_COOL_STATE: Client is notified of crossing the requested cool
+ * temperature threshold.
* %ADC_TM_LOW_STATE: Client is notified of crossing the requested low
- * threshold.
+ * voltage threshold.
+ * %ADC_TM_WARM_STATE: Client is notified of crossing the requested high
+ * temperature threshold.
*/
enum qpnp_tm_state {
ADC_TM_HIGH_STATE = 0,
+ ADC_TM_COOL_STATE = ADC_TM_HIGH_STATE,
ADC_TM_LOW_STATE,
+ ADC_TM_WARM_STATE = ADC_TM_LOW_STATE,
ADC_TM_STATE_NUM,
};
/**
* enum qpnp_state_request - Request to enable/disable the corresponding
* high/low voltage/temperature thresholds.
- * %ADC_TM_HIGH_THR_ENABLE: Enable high voltage/temperature threshold.
+ * %ADC_TM_HIGH_THR_ENABLE: Enable high voltage threshold.
+ * %ADC_TM_COOL_THR_ENABLE = Enables cool temperature threshold.
* %ADC_TM_LOW_THR_ENABLE: Enable low voltage/temperature threshold.
+ * %ADC_TM_WARM_THR_ENABLE = Enables warm temperature threshold.
* %ADC_TM_HIGH_LOW_THR_ENABLE: Enable high and low voltage/temperature
* threshold.
* %ADC_TM_HIGH_THR_DISABLE: Disable high voltage/temperature threshold.
+ * %ADC_TM_COOL_THR_ENABLE = Disables cool temperature threshold.
* %ADC_TM_LOW_THR_DISABLE: Disable low voltage/temperature threshold.
+ * %ADC_TM_WARM_THR_ENABLE = Disables warm temperature threshold.
* %ADC_TM_HIGH_THR_DISABLE: Disable high and low voltage/temperature
* threshold.
*/
enum qpnp_state_request {
ADC_TM_HIGH_THR_ENABLE = 0,
+ ADC_TM_COOL_THR_ENABLE = ADC_TM_HIGH_THR_ENABLE,
ADC_TM_LOW_THR_ENABLE,
+ ADC_TM_WARM_THR_ENABLE = ADC_TM_LOW_THR_ENABLE,
ADC_TM_HIGH_LOW_THR_ENABLE,
ADC_TM_HIGH_THR_DISABLE,
+ ADC_TM_COOL_THR_DISABLE = ADC_TM_HIGH_THR_DISABLE,
ADC_TM_LOW_THR_DISABLE,
+ ADC_TM_WARM_THR_DISABLE = ADC_TM_LOW_THR_DISABLE,
ADC_TM_HIGH_LOW_THR_DISABLE,
ADC_TM_THR_NUM,
};
@@ -1345,6 +1359,12 @@
int32_t qpnp_iadc_vadc_sync_read(
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result);
+/**
+ * qpnp_iadc_calibrate_for_trim() - Clients can use this API to re-calibrate
+ * IADC.
+ * @result: 0 on success.
+ */
+int32_t qpnp_iadc_calibrate_for_trim(void);
#else
static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
struct qpnp_iadc_result *result)
@@ -1360,6 +1380,8 @@
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
{ return -ENXIO; }
+static inline int32_t qpnp_iadc_calibrate_for_trim(void)
+{ return -ENXIO; }
#endif
/* Public API */
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
new file mode 100644
index 0000000..538ad15
--- /dev/null
+++ b/include/linux/regulator/cpr-regulator.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __REGULATOR_CPR_REGULATOR_H__
+#define __REGULATOR_CPR_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+#define CPR_REGULATOR_DRIVER_NAME "qcom,cpr-regulator"
+
+#define CPR_PVS_EFUSE_BITS_MAX 5
+#define CPR_PVS_EFUSE_BINS_MAX (1 << CPR_PVS_EFUSE_BITS_MAX)
+
+/**
+ * enum cpr_corner_enum - CPR corner enum values
+ * %CPR_CORNER_SVS: Lowest voltage for APC
+ * %CPR_CORNER_NORMAL: Normal mode voltage
+ * %CPR_CORNER_TURBO: Turbo mode voltage
+ * %CPR_CORNER_SUPER_TURBO: Super Turbo mode voltage
+ *
+ * These should be used in regulator_set_voltage() for CPR
+ * regulator as if they had units of uV.
+ */
+enum cpr_corner_enum {
+ CPR_CORNER_SVS = 1,
+ CPR_CORNER_NORMAL,
+ CPR_CORNER_TURBO,
+ CPR_CORNER_SUPER_TURBO,
+ CPR_CORNER_MAX,
+};
+
+/**
+ * enum pvs_process_enum - PVS process enum values
+ * %APC_PVS_NO: No PVS
+ * %APC_PVS_SLOW: Slow PVS process
+ * %APC_PVS_NOM: Nominal PVS process
+ * %APC_PVS_FAST: Fast PVS process
+ */
+enum apc_pvs_process_enum {
+ APC_PVS_NO,
+ APC_PVS_SLOW,
+ APC_PVS_NOM,
+ APC_PVS_FAST,
+ NUM_APC_PVS,
+};
+
+#ifdef CONFIG_MSM_CPR_REGULATOR
+
+int __init cpr_regulator_init(void);
+
+#else
+
+static inline int __init cpr_regulator_init(void)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_MSM_CPR_REGULATOR */
+
+#endif /* __REGULATOR_CPR_REGULATOR_H__ */
diff --git a/include/media/msmb_generic_buf_mgr.h b/include/media/msmb_generic_buf_mgr.h
index 17cb947..efcb425 100644
--- a/include/media/msmb_generic_buf_mgr.h
+++ b/include/media/msmb_generic_buf_mgr.h
@@ -9,6 +9,7 @@
uint32_t index;
};
+struct v4l2_subdev *msm_buf_mngr_get_subdev(void);
#define VIDIOC_MSM_BUF_MNGR_GET_BUF \
_IOWR('V', BASE_VIDIOC_PRIVATE + 33, struct msm_buf_mngr_info)
diff --git a/include/media/msmb_ispif.h b/include/media/msmb_ispif.h
index 3546004..f0f015e 100644
--- a/include/media/msmb_ispif.h
+++ b/include/media/msmb_ispif.h
@@ -64,14 +64,17 @@
};
struct msm_ispif_params_entry {
+ enum msm_ispif_vfe_intf vfe_intf;
enum msm_ispif_intftype intftype;
int num_cids;
enum msm_ispif_cid cids[3];
enum msm_ispif_csid csid;
+ int crop_enable;
+ uint16_t crop_start_pixel;
+ uint16_t crop_end_pixel;
};
struct msm_ispif_param_data {
- enum msm_ispif_vfe_intf vfe_intf;
uint32_t num;
struct msm_ispif_params_entry entries[INTF_MAX];
};
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 6f8e865..9000774 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -11,6 +11,7 @@
#define MAX_PLANES VIDEO_MAX_PLANES
#define MAX_NUM_CPP_STRIPS 8
+#define MSM_CPP_MAX_NUM_PLANES 3
enum msm_cpp_frame_type {
MSM_CPP_OFFLINE_FRAME,
@@ -74,9 +75,25 @@
int postscale_crop_en;
};
+struct msm_cpp_buffer_info_t {
+ int fd;
+ uint32_t index;
+ uint32_t offset;
+ uint8_t native_buff;
+ uint8_t processed_divert;
+};
+
+struct msm_cpp_stream_buff_info_t {
+ uint32_t identity;
+ uint32_t num_buffs;
+ struct msm_cpp_buffer_info_t *buffer_info;
+};
+
struct msm_cpp_frame_info_t {
int32_t frame_id;
+ struct timeval timestamp;
uint32_t inst_id;
+ uint32_t identity;
uint32_t client_id;
enum msm_cpp_frame_type frame_type;
uint32_t num_strips;
@@ -87,6 +104,11 @@
int dst_fd;
struct ion_handle *src_ion_handle;
struct ion_handle *dest_ion_handle;
+ struct timeval in_time, out_time;
+ void *cookie;
+
+ struct msm_cpp_buffer_info_t input_buffer_info;
+ struct msm_cpp_buffer_info_t output_buffer_info;
};
struct cpp_hw_info {
@@ -112,6 +134,12 @@
#define VIDIOC_MSM_CPP_FLUSH_QUEUE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
+#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
struct msm_camera_v4l2_ioctl_t {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 52811ae..bfa0eca 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -578,14 +578,24 @@
* Used by the driver to indicate the specific rate transmission
* type for 802.11n transmissions.
*
- * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
- * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
+ * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
+ * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
+ * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
+ * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
+ * @RATE_INFO_FLAGS_60G: 60GHz MCS
*/
enum rate_info_flags {
- RATE_INFO_FLAGS_MCS = 1<<0,
- RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1,
- RATE_INFO_FLAGS_SHORT_GI = 1<<2,
+ RATE_INFO_FLAGS_MCS = BIT(0),
+ RATE_INFO_FLAGS_VHT_MCS = BIT(1),
+ RATE_INFO_FLAGS_40_MHZ_WIDTH = BIT(2),
+ RATE_INFO_FLAGS_80_MHZ_WIDTH = BIT(3),
+ RATE_INFO_FLAGS_80P80_MHZ_WIDTH = BIT(4),
+ RATE_INFO_FLAGS_160_MHZ_WIDTH = BIT(5),
+ RATE_INFO_FLAGS_SHORT_GI = BIT(6),
+ RATE_INFO_FLAGS_60G = BIT(7),
};
/**
@@ -596,11 +606,13 @@
* @flags: bitflag of flags from &enum rate_info_flags
* @mcs: mcs index if struct describes a 802.11n bitrate
* @legacy: bitrate in 100kbit/s for 802.11abg
+ * @nss: number of streams (VHT only)
*/
struct rate_info {
u8 flags;
u8 mcs;
u16 legacy;
+ u8 nss;
};
/**
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1484f16..04e683f 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6515,6 +6515,54 @@
#define AFE_MAX_CDC_REGISTERS_TO_CONFIG (20)
+/* AANC Port Config Specific */
+#define AFE_PARAM_ID_AANC_PORT_CONFIG (0x00010215)
+#define AFE_API_VERSION_AANC_PORT_CONFIG (0x1)
+#define AANC_TX_MIC_UNUSED (0)
+#define AANC_TX_VOICE_MIC (1)
+#define AANC_TX_ERROR_MIC (2)
+#define AANC_TX_NOISE_MIC (3)
+#define AFE_PORT_MAX_CHANNEL_CNT (8)
+#define AFE_MODULE_AANC (0x00010214)
+#define AFE_PARAM_ID_CDC_AANC_VERSION (0x0001023A)
+#define AFE_API_VERSION_CDC_AANC_VERSION (0x1)
+#define AANC_HW_BLOCK_VERSION_1 (1)
+#define AANC_HW_BLOCK_VERSION_2 (2)
+
+struct afe_param_aanc_port_cfg {
+ /* Minor version used for tracking the version of the module's
+ * source port configuration.
+ */
+ uint32_t aanc_port_cfg_minor_version;
+
+ /* Sampling rate of the source Tx port. 8k - 192k*/
+ uint32_t tx_port_sample_rate;
+
+ /* Channel mapping for the Tx port signal carrying Noise (X),
+ * Error (E), and Voice (V) signals.
+ */
+ uint8_t tx_port_channel_map[AFE_PORT_MAX_CHANNEL_CNT];
+
+ /* Number of channels on the source Tx port. */
+ uint16_t tx_port_num_channels;
+
+ /* Port ID of the Rx path reference signal. */
+ uint16_t rx_path_ref_port_id;
+
+ /* Sampling rate of the reference port. 8k - 192k*/
+ uint32_t ref_port_sample_rate;
+} __packed;
+
+struct afe_param_id_cdc_aanc_version {
+ /* Minor version used for tracking the version of the module's
+ * hw version
+ */
+ uint32_t cdc_aanc_minor_version;
+
+ /* HW version. */
+ uint32_t aanc_hw_version;
+} __packed;
+
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
@@ -6746,6 +6794,7 @@
AFE_SLIMBUS_SLAVE_PORT_CONFIG,
AFE_SLIMBUS_SLAVE_CONFIG,
AFE_CDC_REGISTERS_CONFIG,
+ AFE_AANC_VERSION,
AFE_MAX_CONFIG_TYPES,
};
@@ -6842,4 +6891,26 @@
struct afe_param_cdc_slimbus_slave_cfg sb_slave_cfg;
} __packed;
+struct afe_svc_cmd_cdc_aanc_version {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_cdc_aanc_version version;
+} __packed;
+
+struct afe_port_cmd_set_aanc_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ union {
+ struct afe_param_aanc_port_cfg aanc_port_cfg;
+ struct afe_mod_enable_param mod_enable;
+ } __packed data;
+} __packed;
+
+struct afe_port_cmd_set_aanc_acdb_table {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+} __packed;
+
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 22ddbbc..9c86e1d 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -127,6 +127,14 @@
uint32_t mem_map_handle;
};
+struct aanc_data {
+ bool aanc_active;
+ uint16_t aanc_rx_port;
+ uint16_t aanc_tx_port;
+ uint32_t aanc_rx_port_sample_rate;
+ uint32_t aanc_tx_port_sample_rate;
+};
+
int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
int afe_close(int port_id);
int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
@@ -188,4 +196,5 @@
int afe_set_config(enum afe_config_type config_type, void *config_data,
int arg);
+void afe_set_aanc_info(struct aanc_data *aanc_info);
#endif /* __Q6AFE_V2_H__ */
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index d1e73a4..edd656c 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -641,21 +641,9 @@
* and expiry check is done in the hrtimer_interrupt or in the softirq.
*/
static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
- struct hrtimer_clock_base *base,
- int wakeup)
+ struct hrtimer_clock_base *base)
{
- if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) {
- if (wakeup) {
- raw_spin_unlock(&base->cpu_base->lock);
- raise_softirq_irqoff(HRTIMER_SOFTIRQ);
- raw_spin_lock(&base->cpu_base->lock);
- } else
- __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
-
- return 1;
- }
-
- return 0;
+ return base->cpu_base->hres_active && hrtimer_reprogram(timer, base);
}
/*
@@ -726,8 +714,7 @@
static inline void
hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
- struct hrtimer_clock_base *base,
- int wakeup)
+ struct hrtimer_clock_base *base)
{
return 0;
}
@@ -986,8 +973,21 @@
*
* XXX send_remote_softirq() ?
*/
- if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases))
- hrtimer_enqueue_reprogram(timer, new_base, wakeup);
+ if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)
+ && hrtimer_enqueue_reprogram(timer, new_base)) {
+ if (wakeup) {
+ /*
+ * We need to drop cpu_base->lock to avoid a
+ * lock ordering issue vs. rq->lock.
+ */
+ raw_spin_unlock(&new_base->cpu_base->lock);
+ raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+ local_irq_restore(flags);
+ return ret;
+ } else {
+ __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+ }
+ }
unlock_hrtimer_base(timer, &flags);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d6dd07a..b179e71 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -926,11 +926,6 @@
[MIGRATE_ISOLATE] = { MIGRATE_RESERVE }, /* Never used */
};
-int *get_migratetype_fallbacks(int mtype)
-{
- return fallbacks[mtype];
-}
-
/*
* Move the free pages in a range to the free lists of the requested type.
* Note that start_page and end_pages are not aligned on a pageblock
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 5063fa3..8861f91 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -145,6 +145,12 @@
{
struct fib_info *fi = container_of(head, struct fib_info, rcu);
+ change_nexthops(fi) {
+ if (nexthop_nh->nh_dev)
+ dev_put(nexthop_nh->nh_dev);
+ } endfor_nexthops(fi);
+
+ release_net(fi->fib_net);
if (fi->fib_metrics != (u32 *) dst_default_metrics)
kfree(fi->fib_metrics);
kfree(fi);
@@ -156,13 +162,7 @@
pr_warn("Freeing alive fib_info %p\n", fi);
return;
}
- change_nexthops(fi) {
- if (nexthop_nh->nh_dev)
- dev_put(nexthop_nh->nh_dev);
- nexthop_nh->nh_dev = NULL;
- } endfor_nexthops(fi);
fib_info_cnt--;
- release_net(fi->fib_net);
call_rcu(&fi->rcu, free_fib_info_rcu);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 69318b0..5097036 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2384,25 +2384,46 @@
rate = nla_nest_start(msg, attr);
if (!rate)
- goto nla_put_failure;
+ return false;
/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
bitrate = cfg80211_calculate_bitrate(info);
if (bitrate > 0)
- NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
+ nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
- if (info->flags & RATE_INFO_FLAGS_MCS)
- NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
- if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
- if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
+ if (info->flags & RATE_INFO_FLAGS_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+ return false;
+ } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
+ return false;
+ if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+ return false;
+ }
nla_nest_end(msg, rate);
return true;
-
-nla_put_failure:
- return false;
}
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 017d4fc..b89fb94 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -876,13 +876,86 @@
return err;
}
+static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
+{
+ static const u32 base[4][10] = {
+ { 6500000,
+ 13000000,
+ 19500000,
+ 26000000,
+ 39000000,
+ 52000000,
+ 58500000,
+ 65000000,
+ 78000000,
+ 0,
+ },
+ { 13500000,
+ 27000000,
+ 40500000,
+ 54000000,
+ 81000000,
+ 108000000,
+ 121500000,
+ 135000000,
+ 162000000,
+ 180000000,
+ },
+ { 29300000,
+ 58500000,
+ 87800000,
+ 117000000,
+ 175500000,
+ 234000000,
+ 263300000,
+ 292500000,
+ 351000000,
+ 390000000,
+ },
+ { 58500000,
+ 117000000,
+ 175500000,
+ 234000000,
+ 351000000,
+ 468000000,
+ 526500000,
+ 585000000,
+ 702000000,
+ 780000000,
+ },
+ };
+ u32 bitrate;
+ int idx;
+
+ if (WARN_ON_ONCE(rate->mcs > 9))
+ return 0;
+
+ idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
+ RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
+ rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
+ rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+
+ bitrate = base[idx][rate->mcs];
+ bitrate *= rate->nss;
+
+ if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+ bitrate = (bitrate / 9) * 10;
+
+ /* do NOT round down here */
+ return (bitrate + 50000) / 100000;
+}
+
u16 cfg80211_calculate_bitrate(struct rate_info *rate)
{
int modulation, streams, bitrate;
- if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+ if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+ !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
return rate->legacy;
+ if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
+ return cfg80211_calculate_bitrate_vht(rate);
+
/* the formula below does only work for MCS values smaller than 32 */
if (rate->mcs >= 32)
return 0;
diff --git a/scripts/build-all.py b/scripts/build-all.py
index 4789af7..3cecbe2 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -88,6 +88,7 @@
r'[fm]sm[0-9]*_defconfig',
r'apq*_defconfig',
r'qsd*_defconfig',
+ r'msmzinc*_defconfig',
)
for p in arch_pats:
for n in glob.glob('arch/arm/configs/' + p):
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 634493b..ca8cfaa 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -2135,12 +2135,12 @@
dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
if (w->shift == 5) {
- e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
- e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
- req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
- } else if (w->shift == 4) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
+ } else if (w->shift == 4) {
+ e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
+ e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
} else {
pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 80738ba..5f4490b 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -99,10 +99,17 @@
SB_PGD_PORT_TX_ENABLE_n,
SB_PGD_PORT_RX_WATERMARK_n,
SB_PGD_PORT_RX_ENABLE_n,
+ SB_PGD_TX_PORTn_MULTI_CHNL_0,
+ SB_PGD_TX_PORTn_MULTI_CHNL_1,
+ SB_PGD_RX_PORTn_MULTI_CHNL_0,
+ SB_PGD_RX_PORTn_MULTI_CHNL_1,
+ AANC_FF_GAIN_ADAPTIVE,
+ AANC_FFGAIN_ADAPTIVE_EN,
+ AANC_GAIN_CONTROL,
MAX_CFG_REGISTERS,
};
-static struct afe_param_cdc_reg_cfg mad_audio_reg_cfg[] = {
+static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_MAIN_CTL_1),
@@ -157,12 +164,30 @@
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
- }
+ },
+ { 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_IIR_B1_CTL),
+ AANC_FF_GAIN_ADAPTIVE, 0x4, 8, 0
+ },
+ { 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_IIR_B1_CTL),
+ AANC_FFGAIN_ADAPTIVE_EN, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_GAIN_CTL),
+ AANC_GAIN_CONTROL, 0xFF, 8, 0
+ },
};
-static struct afe_param_cdc_reg_cfg_data taiko_mad_audio_reg_cfg = {
- .num_registers = ARRAY_SIZE(mad_audio_reg_cfg),
- .reg_data = mad_audio_reg_cfg,
+static struct afe_param_cdc_reg_cfg_data taiko_audio_reg_cfg = {
+ .num_registers = ARRAY_SIZE(audio_reg_cfg),
+ .reg_data = audio_reg_cfg,
+};
+
+static struct afe_param_id_cdc_aanc_version taiko_cdc_aanc_version = {
+ .cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
+ .aanc_hw_version = AANC_HW_BLOCK_VERSION_2,
};
module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
@@ -556,55 +581,6 @@
return 0;
}
-static int taiko_pa_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 ear_pa_gain;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- ear_pa_gain = snd_soc_read(codec, TAIKO_A_RX_EAR_GAIN);
-
- ear_pa_gain = ear_pa_gain >> 5;
-
- if (ear_pa_gain == 0x00) {
- ucontrol->value.integer.value[0] = 0;
- } else if (ear_pa_gain == 0x04) {
- ucontrol->value.integer.value[0] = 1;
- } else {
- pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
- __func__, ear_pa_gain);
- return -EINVAL;
- }
-
- pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
-
- return 0;
-}
-
-static int taiko_pa_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 ear_pa_gain;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- ear_pa_gain = 0x00;
- break;
- case 1:
- ear_pa_gain = 0x80;
- break;
- default:
- return -EINVAL;
- }
-
- snd_soc_update_bits(codec, TAIKO_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
- return 0;
-}
-
static int taiko_get_iir_enable_audio_mixer(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -961,10 +937,7 @@
return 0;
}
-static const char * const taiko_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
-static const struct soc_enum taiko_ear_pa_gain_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, taiko_ear_pa_gain_text),
-};
+
static const char *const taiko_anc_func_text[] = {"OFF", "ON"};
static const struct soc_enum taiko_anc_func_enum =
@@ -1044,26 +1017,6 @@
static const struct snd_kcontrol_new taiko_snd_controls[] = {
- SOC_ENUM_EXT("EAR PA Gain", taiko_ear_pa_gain_enum[0],
- taiko_pa_gain_get, taiko_pa_gain_put),
-
- SOC_SINGLE_TLV("LINEOUT1 Volume", TAIKO_A_RX_LINE_1_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("LINEOUT2 Volume", TAIKO_A_RX_LINE_2_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("LINEOUT3 Volume", TAIKO_A_RX_LINE_3_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("LINEOUT4 Volume", TAIKO_A_RX_LINE_4_GAIN, 0, 12, 1,
- line_gain),
-
- SOC_SINGLE_TLV("HPHL Volume", TAIKO_A_RX_HPH_L_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("HPHR Volume", TAIKO_A_RX_HPH_R_GAIN, 0, 12, 1,
- line_gain),
-
- SOC_SINGLE_TLV("SPK DRV Volume", TAIKO_A_SPKR_DRV_GAIN, 3, 7, 1,
- line_gain),
-
SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL,
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -1099,6 +1052,7 @@
digital_gain),
SOC_SINGLE_S8_TLV("DEC10 Volume", TAIKO_A_CDC_TX10_VOL_CTL_GAIN, -84,
40, digital_gain),
+
SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAIKO_A_CDC_IIR1_GAIN_B1_CTL, -84,
40, digital_gain),
SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TAIKO_A_CDC_IIR1_GAIN_B2_CTL, -84,
@@ -1107,17 +1061,12 @@
40, digital_gain),
SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAIKO_A_CDC_IIR1_GAIN_B4_CTL, -84,
40, digital_gain),
- SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_TX_1_2_EN, 5, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_TX_1_2_EN, 1, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_TX_3_4_EN, 5, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_TX_3_4_EN, 1, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, taiko_get_anc_slot,
taiko_put_anc_slot),
SOC_ENUM_EXT("ANC Function", taiko_anc_func_enum, taiko_get_anc_func,
taiko_put_anc_func),
+
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -1207,6 +1156,122 @@
};
+static int taiko_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ ear_pa_gain = snd_soc_read(codec, TAIKO_A_RX_EAR_GAIN);
+
+ ear_pa_gain = ear_pa_gain >> 5;
+
+ ucontrol->value.integer.value[0] = ear_pa_gain;
+
+ pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+
+ return 0;
+}
+
+static int taiko_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ ear_pa_gain = ucontrol->value.integer.value[0] << 5;
+
+ snd_soc_update_bits(codec, TAIKO_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
+ return 0;
+}
+
+static const char * const taiko_1_x_ear_pa_gain_text[] = {
+ "POS_6_DB", "UNDEFINED_1", "UNDEFINED_2", "UNDEFINED_3", "POS_2_DB",
+ "NEG_2P5_DB", "UNDEFINED_4", "NEG_12_DB"
+};
+
+static const struct soc_enum taiko_1_x_ear_pa_gain_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(taiko_1_x_ear_pa_gain_text),
+ taiko_1_x_ear_pa_gain_text);
+
+static const struct snd_kcontrol_new taiko_1_x_analog_gain_controls[] = {
+
+ SOC_ENUM_EXT("EAR PA Gain", taiko_1_x_ear_pa_gain_enum,
+ taiko_pa_gain_get, taiko_pa_gain_put),
+
+ SOC_SINGLE_TLV("HPHL Volume", TAIKO_A_RX_HPH_L_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", TAIKO_A_RX_HPH_R_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAIKO_A_RX_LINE_1_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAIKO_A_RX_LINE_2_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT3 Volume", TAIKO_A_RX_LINE_3_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT4 Volume", TAIKO_A_RX_LINE_4_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("SPK DRV Volume", TAIKO_A_SPKR_DRV_GAIN, 3, 7, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_TX_1_2_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_TX_3_4_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_TX_3_4_EN, 1, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
+};
+
+static const char * const taiko_2_x_ear_pa_gain_text[] = {
+ "POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB",
+ "POS_0_DB", "NEG_2P5_DB", "UNDEFINED", "NEG_12_DB"
+};
+
+static const struct soc_enum taiko_2_x_ear_pa_gain_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(taiko_2_x_ear_pa_gain_text),
+ taiko_2_x_ear_pa_gain_text);
+
+static const struct snd_kcontrol_new taiko_2_x_analog_gain_controls[] = {
+
+ SOC_ENUM_EXT("EAR PA Gain", taiko_2_x_ear_pa_gain_enum,
+ taiko_pa_gain_get, taiko_pa_gain_put),
+
+ SOC_SINGLE_TLV("HPHL Volume", TAIKO_A_RX_HPH_L_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", TAIKO_A_RX_HPH_R_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAIKO_A_RX_LINE_1_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAIKO_A_RX_LINE_2_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT3 Volume", TAIKO_A_RX_LINE_3_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT4 Volume", TAIKO_A_RX_LINE_4_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("SPK DRV Volume", TAIKO_A_SPKR_DRV_GAIN, 3, 8, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_CDC_TX_1_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_CDC_TX_2_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_CDC_TX_3_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_CDC_TX_4_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_CDC_TX_5_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_CDC_TX_6_GAIN, 2, 19, 0,
+ analog_gain),
+};
+
static const char * const rx_mix1_text[] = {
"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
"RX5", "RX6", "RX7"
@@ -3581,8 +3646,8 @@
return 1;
}
- for (i = 0; i < ARRAY_SIZE(mad_audio_reg_cfg); i++)
- if (mad_audio_reg_cfg[i].reg_logical_addr -
+ for (i = 0; i < ARRAY_SIZE(audio_reg_cfg); i++)
+ if (audio_reg_cfg[i].reg_logical_addr -
TAIKO_REGISTER_START_OFFSET == reg)
return 1;
@@ -3869,7 +3934,7 @@
taiko->comp_fs[comp_rx_path[j]]
= compander_fs;
}
- if (j <= 2)
+ if (j < 2)
rx_mix_1_reg_1 += 3;
else
rx_mix_1_reg_1 += 2;
@@ -5420,6 +5485,12 @@
TAIKO_REG_VAL(TAIKO_A_CDC_TX9_MUX_CTL, 0x48),
TAIKO_REG_VAL(TAIKO_A_CDC_TX10_MUX_CTL, 0x48),
TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX3_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX4_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B4_CTL, 0x8),
TAIKO_REG_VAL(TAIKO_A_CDC_VBAT_GAIN_UPD_MON, 0x0),
TAIKO_REG_VAL(TAIKO_A_CDC_PA_RAMP_B1_CTL, 0x0),
TAIKO_REG_VAL(TAIKO_A_CDC_PA_RAMP_B2_CTL, 0x0),
@@ -5632,9 +5703,11 @@
case AFE_SLIMBUS_SLAVE_CONFIG:
return &priv->slimbus_slave_cfg;
case AFE_CDC_REGISTERS_CONFIG:
- return &taiko_mad_audio_reg_cfg;
+ return &taiko_audio_reg_cfg;
case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
return &taiko_slimbus_slave_port_cfg;
+ case AFE_AANC_VERSION:
+ return &taiko_cdc_aanc_version;
default:
pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
return NULL;
@@ -5843,12 +5916,19 @@
taiko_init_slim_slave_cfg(codec);
}
- if (TAIKO_IS_1_0(control->version))
+ if (TAIKO_IS_1_0(control->version)) {
snd_soc_dapm_new_controls(dapm, taiko_1_dapm_widgets,
ARRAY_SIZE(taiko_1_dapm_widgets));
- else
+ snd_soc_add_codec_controls(codec,
+ taiko_1_x_analog_gain_controls,
+ ARRAY_SIZE(taiko_1_x_analog_gain_controls));
+ } else {
snd_soc_dapm_new_controls(dapm, taiko_2_dapm_widgets,
ARRAY_SIZE(taiko_2_dapm_widgets));
+ snd_soc_add_codec_controls(codec,
+ taiko_2_x_analog_gain_controls,
+ ARRAY_SIZE(taiko_2_x_analog_gain_controls));
+ }
control->num_rx_port = TAIKO_RX_MAX;
control->rx_chs = ptr;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 5b54e1b..cbfff1c 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -604,8 +604,12 @@
ins ? "insert" : "removal");
/* Disable detection to avoid glitch */
snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
- snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
- (0x68 | (ins ? (1 << 1) : 0)));
+ if (mbhc->mbhc_cfg->gpio_level_insert)
+ snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
+ (0x68 | (ins ? (1 << 1) : 0)));
+ else
+ snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
+ (0x6C | (ins ? (1 << 1) : 0)));
/* Re-enable detection */
snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
}
@@ -3018,14 +3022,19 @@
switch (event) {
case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
ret = MBHC_MICBIAS1;
+ break;
case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
ret = MBHC_MICBIAS2;
+ break;
case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
ret = MBHC_MICBIAS3;
+ break;
case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
ret = MBHC_MICBIAS4;
+ break;
default:
ret = MBHC_MICBIAS_INVALID;
+ break;
}
return ret;
}
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 4dc6505..b97d9dc 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -772,20 +772,19 @@
.codec_name = "snd-soc-dummy",
},
{
- .name = "VoLTE",
- .stream_name = "VoLTE",
- .cpu_dai_name = "VoLTE",
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
- .be_id = MSM_FRONTEND_DAI_VOLTE,
},
{
.name = "MSM8226 LowLatency",
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 8c0d1a9..65b3a57 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -746,21 +746,21 @@
btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
btn_low[0] = -50;
- btn_high[0] = 10;
- btn_low[1] = 11;
- btn_high[1] = 52;
- btn_low[2] = 53;
- btn_high[2] = 94;
- btn_low[3] = 95;
- btn_high[3] = 133;
- btn_low[4] = 134;
- btn_high[4] = 171;
- btn_low[5] = 172;
- btn_high[5] = 208;
- btn_low[6] = 209;
- btn_high[6] = 244;
- btn_low[7] = 245;
- btn_high[7] = 330;
+ btn_high[0] = 21;
+ btn_low[1] = 22;
+ btn_high[1] = 67;
+ btn_low[2] = 68;
+ btn_high[2] = 111;
+ btn_low[3] = 112;
+ btn_high[3] = 153;
+ btn_low[4] = 154;
+ btn_high[4] = 191;
+ btn_low[5] = 192;
+ btn_high[5] = 233;
+ btn_low[6] = 234;
+ btn_high[6] = 272;
+ btn_low[7] = 273;
+ btn_high[7] = 400;
n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
n_ready[0] = 80;
n_ready[1] = 68;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 50a0113..30e9629 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -44,6 +44,7 @@
#define BTSCO_RATE_16KHZ 16000
static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
#define SAMPLING_RATE_48KHZ 48000
#define SAMPLING_RATE_96KHZ 96000
@@ -733,6 +734,46 @@
return 0;
}
+static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (hdmi_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -840,6 +881,8 @@
pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
channels->min, channels->max);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ hdmi_rx_bit_format);
if (channels->max < 2)
channels->min = channels->max = 2;
rate->min = rate->max = 48000;
@@ -1067,6 +1110,8 @@
slim0_rx_bit_format_get, slim0_rx_bit_format_put),
SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
+ hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
};
static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
@@ -1154,6 +1199,14 @@
return err;
}
+ config_data = taiko_get_afe_config(codec, AFE_AANC_VERSION);
+ err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, err);
+ return err;
+ }
+
/* start mbhc */
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration)
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 259f3ed..16d6e81 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -42,6 +42,9 @@
/* ANC Cal */
struct acdb_atomic_cal_block anc_cal;
+ /* AANC Cal */
+ struct acdb_atomic_cal_block aanc_cal;
+
/* LSM Cal */
struct acdb_atomic_cal_block lsm_cal;
@@ -252,6 +255,46 @@
atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
}
+void get_aanc_cal(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ cal_block->cal_size =
+ atomic_read(&acdb_data.aanc_cal.cal_size);
+ cal_block->cal_paddr =
+ atomic_read(&acdb_data.aanc_cal.cal_paddr);
+ cal_block->cal_kvaddr =
+ atomic_read(&acdb_data.aanc_cal.cal_kvaddr);
+done:
+ return;
+}
+
+void store_aanc_cal(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ (long)atomic64_read(&acdb_data.mem_len));
+ goto done;
+ }
+
+ atomic_set(&acdb_data.aanc_cal.cal_size,
+ cal_block->cal_size);
+ atomic_set(&acdb_data.aanc_cal.cal_paddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+ atomic_set(&acdb_data.aanc_cal.cal_kvaddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+done:
+ return;
+}
+
void get_lsm_cal(struct acdb_cal_block *cal_block)
{
pr_debug("%s\n", __func__);
@@ -1109,6 +1152,9 @@
case AUDIO_SET_ASM_CUSTOM_TOPOLOGY:
store_asm_custom_topology((struct cal_block *)data);
goto done;
+ case AUDIO_SET_AANC_CAL:
+ store_aanc_cal((struct cal_block *)data);
+ goto done;
default:
pr_err("ACDB=> ACDB ioctl not found!\n");
}
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 4834855..3c644ed 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -19,6 +19,7 @@
enum {
RX_CAL,
TX_CAL,
+ AANC_TX_CAL,
MAX_AUDPROC_TYPES
};
@@ -64,5 +65,6 @@
void get_vocvol_cal(struct acdb_cal_block *cal_block);
void get_sidetone_cal(struct sidetone_cal *cal_data);
void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
+void get_aanc_cal(struct acdb_cal_block *cal_block);
#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 329d293..16df886 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -23,6 +23,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/msm-dai-q6-v2.h>
+#include <sound/pcm_params.h>
#define HDMI_RX_CA_MAX 0x32
@@ -119,7 +120,14 @@
dai_data->port_config.hdmi_multi_ch.reserved = 0;
dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version = 1;
dai_data->port_config.hdmi_multi_ch.sample_rate = dai_data->rate;
- dai_data->port_config.hdmi_multi_ch.bit_width = 16;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->port_config.hdmi_multi_ch.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dai_data->port_config.hdmi_multi_ch.bit_width = 24;
+ break;
+ }
switch (dai_data->channels) {
case 2:
@@ -257,7 +265,7 @@
static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 2,
.channels_max = 8,
.rate_max = 48000,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 819512d..d8f2759 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -56,6 +56,7 @@
static int fm_pcmrx_switch_enable;
static int srs_alsa_ctrl_ever_called;
static int lsm_mux_slim_port;
+static int slim0_rx_aanc_fb_port;
enum {
MADNONE,
@@ -565,6 +566,8 @@
session_id = voc_get_session_id(VOICE_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOLTE)
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (val == MSM_FRONTEND_DAI_VOICE2)
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else
session_id = voc_get_session_id(VOIP_SESSION_NAME);
@@ -865,6 +868,42 @@
return afe_port_set_mad_type(port_id, mad_type);
}
+static int msm_routing_slim_0_rx_aanc_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] = slim0_rx_aanc_fb_port;
+ mutex_unlock(&routing_lock);
+ pr_debug("%s: AANC Mux Port %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+};
+
+static int msm_routing_slim_0_rx_aanc_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct aanc_data aanc_info;
+
+ mutex_lock(&routing_lock);
+ memset(&aanc_info, 0x00, sizeof(aanc_info));
+ pr_debug("%s: AANC Mux Port %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ slim0_rx_aanc_fb_port = ucontrol->value.integer.value[0];
+ if (ucontrol->value.integer.value[0] == 0) {
+ aanc_info.aanc_active = false;
+ aanc_info.aanc_tx_port = 0;
+ aanc_info.aanc_rx_port = 0;
+ } else {
+ aanc_info.aanc_active = true;
+ aanc_info.aanc_rx_port = SLIMBUS_0_RX;
+ aanc_info.aanc_tx_port =
+ (SLIMBUS_0_RX - 1 + (slim0_rx_aanc_fb_port * 2));
+ }
+ afe_set_aanc_info(&aanc_info);
+ mutex_unlock(&routing_lock);
+ return 0;
+};
static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1550,6 +1589,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1565,6 +1607,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1580,6 +1625,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1595,6 +1643,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1613,6 +1664,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1631,6 +1685,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1649,6 +1706,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1667,6 +1727,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1720,6 +1783,27 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_Voice2", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_Voice2", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice2",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_Voice2", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new tx_volte_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX_VoLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
@@ -1895,6 +1979,21 @@
msm_routing_lsm_func_get, msm_routing_lsm_func_put),
};
+static const char * const aanc_slim_0_rx_text[] = {
+ "ZERO", "SLIMBUS_0_TX", "SLIMBUS_1_TX", "SLIMBUS_2_TX", "SLIMBUS_3_TX",
+ "SLIMBUS_4_TX", "SLIMBUS_5_TX", "SLIMBUS_6_TX"
+};
+
+static const struct soc_enum aanc_slim_0_rx_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aanc_slim_0_rx_text),
+ aanc_slim_0_rx_text);
+
+static const struct snd_kcontrol_new aanc_slim_0_rx_mux[] = {
+ SOC_DAPM_ENUM_EXT("AANC_SLIM_0_RX MUX", aanc_slim_0_rx_enum,
+ msm_routing_slim_0_rx_aanc_mux_get,
+ msm_routing_slim_0_rx_aanc_mux_put)
+};
+
static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
@@ -2235,6 +2334,8 @@
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_UL", "Voice2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
@@ -2348,6 +2449,8 @@
/* Mux Definitions */
SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+ SND_SOC_DAPM_MUX("SLIM_0_RX AANC MUX", SND_SOC_NOPM, 0, 0,
+ aanc_slim_0_rx_mux),
/* Mixer definitions */
SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2419,6 +2522,9 @@
SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
ARRAY_SIZE(tx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice2_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voice2_mixer_controls,
+ ARRAY_SIZE(tx_voice2_mixer_controls)),
SND_SOC_DAPM_MIXER("Voip_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_voip_mixer_controls,
ARRAY_SIZE(tx_voip_mixer_controls)),
@@ -2595,48 +2701,56 @@
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"PRI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"HDMI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
@@ -2644,6 +2758,7 @@
{"HDMI", NULL, "HDMI_DL_HL"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -2656,6 +2771,15 @@
{"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
{"Voice_Tx Mixer", "AUX_PCM_TX_Voice", "AUX_PCM_TX"},
{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
+
+ {"Voice2_Tx Mixer", "PRI_TX_Voice2", "PRI_I2S_TX"},
+ {"Voice2_Tx Mixer", "MI2S_TX_Voice2", "MI2S_TX"},
+ {"Voice2_Tx Mixer", "SLIM_0_TX_Voice2", "SLIMBUS_0_TX"},
+ {"Voice2_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice2", "INT_BT_SCO_TX"},
+ {"Voice2_Tx Mixer", "AFE_PCM_TX_Voice2", "PCM_TX"},
+ {"Voice2_Tx Mixer", "AUX_PCM_TX_Voice2", "AUX_PCM_TX"},
+ {"VOICE2_UL", NULL, "Voice2_Tx Mixer"},
+
{"VoLTE_Tx Mixer", "PRI_TX_VoLTE", "PRI_I2S_TX"},
{"VoLTE_Tx Mixer", "SLIM_0_TX_VoLTE", "SLIMBUS_0_TX"},
{"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
@@ -3002,6 +3126,10 @@
snd_soc_add_platform_controls(platform, lsm_function,
ARRAY_SIZE(lsm_function));
+
+ snd_soc_add_platform_controls(platform,
+ aanc_slim_0_rx_mux,
+ ARRAY_SIZE(aanc_slim_0_rx_mux));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 798f676..1c1029c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -73,6 +73,7 @@
MSM_FRONTEND_DAI_VOLTE,
MSM_FRONTEND_DAI_DTMF_RX,
MSM_FRONTEND_DAI_LSM1,
+ MSM_FRONTEND_DAI_VOICE2,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 333ee48..4df66d0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -59,6 +59,29 @@
return false;
}
+static int is_voice2(struct msm_voice *pvoice2)
+{
+ if (pvoice2 == &voice_info[VOICE2_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static uint16_t get_session_id(struct msm_voice *pvoc)
+{
+ uint16_t session_id = 0;
+
+ if (is_volte(pvoc))
+ session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (is_voice2(pvoc))
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ else
+ session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+ return session_id;
+}
+
+
static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -92,11 +115,15 @@
if (!strncmp("VoLTE", substream->pcm->id, 5)) {
voice = &voice_info[VOLTE_SESSION_INDEX];
pr_debug("%s: Open VoLTE Substream Id=%s\n",
- __func__, substream->pcm->id);
+ __func__, substream->pcm->id);
+ } else if (!strncmp("Voice2", substream->pcm->id, 6)) {
+ voice = &voice_info[VOICE2_SESSION_INDEX];
+ pr_debug("%s: Open Voice2 Substream Id=%s\n",
+ __func__, substream->pcm->id);
} else {
voice = &voice_info[VOICE_SESSION_INDEX];
pr_debug("%s: Open VOICE Substream Id=%s\n",
- __func__, substream->pcm->id);
+ __func__, substream->pcm->id);
}
mutex_lock(&voice->lock);
@@ -160,11 +187,10 @@
prtd->instance--;
if (!prtd->playback_start && !prtd->capture_start) {
pr_debug("end voice call\n");
- if (is_volte(prtd))
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
- voc_end_voice_call(session_id);
+
+ session_id = get_session_id(prtd);
+ if (session_id)
+ voc_end_voice_call(session_id);
}
mutex_unlock(&prtd->lock);
@@ -185,11 +211,9 @@
ret = msm_pcm_capture_prepare(substream);
if (prtd->playback_start && prtd->capture_start) {
- if (is_volte(prtd))
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
- voc_start_voice_call(session_id);
+ session_id = get_session_id(prtd);
+ if (session_id)
+ voc_start_voice_call(session_id);
}
mutex_unlock(&prtd->lock);
@@ -215,10 +239,8 @@
uint16_t session_id = 0;
pr_debug("%s: cmd = %d\n", __func__, cmd);
- if (is_volte(prtd))
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+ session_id = get_session_id(prtd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -233,8 +255,10 @@
ret = msm_pcm_playback_prepare(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ret = msm_pcm_capture_prepare(substream);
- if (prtd->playback_start && prtd->capture_start)
- voc_resume_voice_call(session_id);
+ if (prtd->playback_start && prtd->capture_start) {
+ if (session_id)
+ voc_resume_voice_call(session_id);
+ }
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -247,7 +271,8 @@
if (prtd->capture_start)
prtd->capture_start = 0;
}
- voc_standby_voice_call(session_id);
+ if (session_id)
+ voc_standby_voice_call(session_id);
break;
default:
ret = -EINVAL;
@@ -290,6 +315,24 @@
return 0;
}
+static int msm_voice2_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_voice2_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int volume = ucontrol->value.integer.value[0];
+ pr_debug("%s: volume: %d\n", __func__, volume);
+
+ voc_set_rx_vol_index(voc_get_session_id(VOICE2_SESSION_NAME),
+ RX_PATH, volume);
+ return 0;
+}
+
static int msm_voice_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -328,6 +371,25 @@
return 0;
}
+static int msm_voice2_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_voice2_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mute = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+
+ voc_set_tx_mute(voc_get_session_id(VOICE2_SESSION_NAME), TX_PATH, mute);
+
+ return 0;
+}
+
static int msm_voice_rx_device_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -368,6 +430,26 @@
return 0;
}
+static int msm_voice2_rx_device_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ voc_get_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME));
+ return 0;
+}
+
+static int msm_voice2_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mute = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+
+ voc_set_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME), mute);
+
+ return 0;
+}
+
static const char const *tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
static const struct soc_enum msm_tty_mode_enum[] = {
SOC_ENUM_SINGLE_EXT(4, tty_mode),
@@ -389,6 +471,7 @@
pr_debug("%s: tty_mode=%d\n", __func__, tty_mode);
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
return 0;
}
@@ -401,6 +484,8 @@
voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME),
wv_enable);
+ voc_set_widevoice_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ wv_enable);
return 0;
}
@@ -422,7 +507,9 @@
pr_debug("%s: st enable=%d\n", __func__, st_enable);
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_ST, st_enable);
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
+ voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
return 0;
}
@@ -444,7 +531,9 @@
pr_debug("%s: fens enable=%d\n", __func__, fens_enable);
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+ voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
return 0;
}
@@ -481,6 +570,13 @@
msm_volte_mute_get, msm_volte_mute_put),
SOC_SINGLE_EXT("VoLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
msm_volte_volume_get, msm_volte_volume_put),
+ SOC_SINGLE_EXT("Voice2 Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice2_rx_device_mute_get,
+ msm_voice2_rx_device_mute_put),
+ SOC_SINGLE_EXT("Voice2 Tx Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice2_mute_get, msm_voice2_mute_put),
+ SOC_SINGLE_EXT("Voice2 Rx Volume", SND_SOC_NOPM, 0, 5, 0,
+ msm_voice2_volume_get, msm_voice2_volume_put),
};
static struct snd_pcm_ops msm_pcm_ops = {
@@ -550,9 +646,12 @@
static int __init msm_soc_platform_init(void)
{
+ int i = 0;
+
memset(&voice_info, 0, sizeof(voice_info));
- mutex_init(&voice_info[VOICE_SESSION_INDEX].lock);
- mutex_init(&voice_info[VOLTE_SESSION_INDEX].lock);
+
+ for (i = 0; i < VOICE_SESSION_INDEX_MAX; i++)
+ mutex_init(&voice_info[i].lock);
return platform_driver_register(&msm_pcm_driver);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index a25fb2a..5425c46 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -16,6 +16,7 @@
enum {
VOICE_SESSION_INDEX,
VOLTE_SESSION_INDEX,
+ VOICE2_SESSION_INDEX,
VOICE_SESSION_INDEX_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 97cd3fc..fed0d81 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -45,6 +45,8 @@
u16 dtmf_gen_rx_portid;
struct afe_spkr_prot_calib_get_resp calib_data;
int vi_tx_port;
+ uint32_t afe_sample_rates[AFE_MAX_PORTS];
+ struct aanc_data aanc_info;
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -57,6 +59,21 @@
#define SIZEOF_CFG_CMD(y) \
(sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
+void afe_set_aanc_info(struct aanc_data *q6_aanc_info)
+{
+ pr_debug("%s\n", __func__);
+
+ this_afe.aanc_info.aanc_active = q6_aanc_info->aanc_active;
+ this_afe.aanc_info.aanc_rx_port = q6_aanc_info->aanc_rx_port;
+ this_afe.aanc_info.aanc_tx_port = q6_aanc_info->aanc_tx_port;
+
+ pr_debug("aanc active is %d rx port is %d, tx port is %d\n",
+ this_afe.aanc_info.aanc_active,
+ this_afe.aanc_info.aanc_rx_port,
+ this_afe.aanc_info.aanc_tx_port);
+}
+
+
static int32_t afe_callback(struct apr_client_data *data, void *priv)
{
if (!data) {
@@ -342,7 +359,12 @@
struct afe_audioif_config_command_no_payload afe_cal;
pr_debug("%s: path %d\n", __func__, path);
- get_afe_cal(path, &cal_block);
+ if (path == AANC_TX_CAL) {
+ get_aanc_cal(&cal_block);
+ } else {
+ get_afe_cal(path, &cal_block);
+ }
+
if (cal_block.cal_size <= 0) {
pr_debug("%s: No AFE cal to send!\n", __func__);
goto done;
@@ -403,6 +425,7 @@
int index = 0;
struct afe_spkr_prot_config_command config;
+ memset(&config, 0 , sizeof(config));
if (!prot_config) {
pr_err("%s Invalid params\n", __func__);
goto fail_cmd;
@@ -411,7 +434,6 @@
pr_err("%s invalid port %d", __func__, port);
goto fail_cmd;
}
- memset(&config, 0 , sizeof(config));
index = q6audio_get_port_index(port);
switch (param_id) {
case AFE_PARAM_ID_FBSP_MODE_RX_CFG:
@@ -464,7 +486,7 @@
}
ret = 0;
fail_cmd:
- pr_err("%s config.pdata.param_id %x status %d\n",
+ pr_debug("%s config.pdata.param_id %x status %d\n",
__func__, config.pdata.param_id, ret);
return ret;
}
@@ -738,13 +760,173 @@
pr_debug("%s: leave %d\n", __func__, ret);
return ret;
}
+static int afe_aanc_port_cfg(void *apr, uint16_t tx_port, uint16_t rx_port)
+{
+ struct afe_port_cmd_set_aanc_param cfg;
+ int ret = 0;
+ int index = 0;
+
+ pr_debug("%s: tx_port %d, rx_port %d\n",
+ __func__, tx_port, rx_port);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0)
+ return -EINVAL;
+
+ index = q6audio_get_port_index(tx_port);
+ if (q6audio_validate_port(tx_port) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, tx_port);
+ return -EINVAL;
+ }
+
+ cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cfg.hdr.pkt_size = sizeof(cfg);
+ cfg.hdr.src_port = 0;
+ cfg.hdr.dest_port = 0;
+ cfg.hdr.token = index;
+ cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+ cfg.param.port_id = tx_port;
+ cfg.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_aanc_port_cfg);
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.payload_address_msw = 0;
+ cfg.param.mem_map_handle = 0;
+
+ cfg.pdata.module_id = AFE_MODULE_AANC;
+ cfg.pdata.param_id = AFE_PARAM_ID_AANC_PORT_CONFIG;
+ cfg.pdata.param_size = sizeof(struct afe_param_aanc_port_cfg);
+ cfg.pdata.reserved = 0;
+
+ cfg.data.aanc_port_cfg.aanc_port_cfg_minor_version =
+ AFE_API_VERSION_AANC_PORT_CONFIG;
+ cfg.data.aanc_port_cfg.tx_port_sample_rate =
+ this_afe.aanc_info.aanc_tx_port_sample_rate;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[0] = AANC_TX_VOICE_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[1] = AANC_TX_NOISE_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[2] = AANC_TX_ERROR_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[3] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[4] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[5] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[6] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[7] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_num_channels = 3;
+ cfg.data.aanc_port_cfg.rx_path_ref_port_id = rx_port;
+ cfg.data.aanc_port_cfg.ref_port_sample_rate =
+ this_afe.aanc_info.aanc_rx_port_sample_rate;
+
+ ret = afe_apr_send_pkt((uint32_t *) &cfg, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE AANC port config failed for tx_port %d, rx_port %d\n",
+ __func__, tx_port, rx_port);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_aanc_mod_enable(void *apr, uint16_t tx_port, uint16_t enable)
+{
+ struct afe_port_cmd_set_aanc_param cfg;
+ int ret = 0;
+ int index = 0;
+
+ pr_debug("%s: tx_port %d\n",
+ __func__, tx_port);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0)
+ return -EINVAL;
+
+ index = q6audio_get_port_index(tx_port);
+ if (q6audio_validate_port(tx_port) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, tx_port);
+ return -EINVAL;
+ }
+
+ cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cfg.hdr.pkt_size = sizeof(cfg);
+ cfg.hdr.src_port = 0;
+ cfg.hdr.dest_port = 0;
+ cfg.hdr.token = index;
+ cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+ cfg.param.port_id = tx_port;
+ cfg.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_mod_enable_param);
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.mem_map_handle = 0;
+
+ cfg.pdata.module_id = AFE_MODULE_AANC;
+ cfg.pdata.param_id = AFE_PARAM_ID_ENABLE;
+ cfg.pdata.param_size = sizeof(struct afe_mod_enable_param);
+ cfg.pdata.reserved = 0;
+
+ cfg.data.mod_enable.enable = enable;
+ cfg.data.mod_enable.reserved = 0;
+
+ ret = afe_apr_send_pkt((uint32_t *) &cfg, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE AANC enable failed for tx_port %d\n",
+ __func__, tx_port);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+int afe_send_aanc_version(
+ struct afe_param_id_cdc_aanc_version *version_cfg)
+{
+ int ret;
+ struct afe_svc_cmd_cdc_aanc_version config;
+
+ pr_debug("%s: enter\n", __func__);
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_id_cdc_aanc_version);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CDC_AANC_VERSION;
+ config.pdata.param_size =
+ sizeof(struct afe_param_id_cdc_aanc_version);
+ config.version = *version_cfg;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CDC_AANC_VERSION failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+ pr_debug("%s: leave ret %d\n", __func__, 0);
+ return ret;
+}
int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
{
int i;
i = port_id - SLIMBUS_0_RX;
- if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+ if (i < 0 || i >= ARRAY_SIZE(afe_ports_mad_type)) {
pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
return -EINVAL;
}
@@ -790,6 +972,9 @@
case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
ret = afe_send_slimbus_slave_port_cfg(config_data, arg);
break;
+ case AFE_AANC_VERSION:
+ ret = afe_send_aanc_version(config_data);
+ break;
default:
pr_err("%s: unknown configuration type", __func__);
ret = -EINVAL;
@@ -837,6 +1022,24 @@
return ret;
}
+static int afe_aanc_start(uint16_t tx_port_id, uint16_t rx_port_id)
+{
+ int ret;
+
+ pr_debug("%s Tx port is %d, Rx port is %d\n",
+ __func__, tx_port_id, rx_port_id);
+ ret = afe_aanc_port_cfg(this_afe.apr, tx_port_id, rx_port_id);
+ if (ret) {
+ pr_err("%s Send AANC Port Config failed %d\n",
+ __func__, ret);
+ goto fail_cmd;
+ }
+ afe_send_cal_block(AANC_TX_CAL, tx_port_id);
+
+fail_cmd:
+ return ret;
+}
+
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate) /* This function is no blocking */
{
@@ -845,6 +1048,7 @@
int cfg_type;
int index = 0;
enum afe_mad_type mad_type;
+ uint16_t port_index;
if (!afe_config) {
pr_err("%s: Error, no configuration data\n", __func__);
@@ -886,6 +1090,22 @@
}
}
+ if ((this_afe.aanc_info.aanc_active) &&
+ (this_afe.aanc_info.aanc_tx_port == port_id)) {
+ this_afe.aanc_info.aanc_tx_port_sample_rate = rate;
+ port_index =
+ afe_get_port_index(this_afe.aanc_info.aanc_rx_port);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.aanc_info.aanc_rx_port_sample_rate =
+ this_afe.afe_sample_rates[port_index];
+ } else {
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = afe_aanc_start(this_afe.aanc_info.aanc_tx_port,
+ this_afe.aanc_info.aanc_rx_port);
+ pr_debug("%s afe_aanc_start ret %d\n", __func__, ret);
+ }
config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
config.hdr.pkt_size = sizeof(config);
@@ -974,6 +1194,14 @@
ret = -EINVAL;
goto fail_cmd;
}
+
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = rate;
+ } else {
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
return afe_send_cmd_port_start(port_id);
fail_cmd:
@@ -2135,11 +2363,11 @@
static void config_debug_fs_init(void)
{
debugfs_afelb = debugfs_create_file("afe_loopback",
- S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+ S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback",
&afe_debug_fops);
debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
- S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
+ S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback_gain",
&afe_debug_fops);
}
static void config_debug_fs_exit(void)
@@ -2392,6 +2620,7 @@
enum afe_mad_type mad_type;
int ret = 0;
int index = 0;
+ uint16_t port_index;
if (this_afe.apr == NULL) {
pr_err("AFE is already closed\n");
@@ -2422,6 +2651,23 @@
pr_debug("%s: Not a MAD port\n", __func__);
}
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = 0;
+ } else {
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if ((port_id == this_afe.aanc_info.aanc_tx_port) &&
+ (this_afe.aanc_info.aanc_active)) {
+ memset(&this_afe.aanc_info, 0x00, sizeof(this_afe.aanc_info));
+ ret = afe_aanc_mod_enable(this_afe.apr, port_id, 0);
+ if (ret)
+ pr_err("%s: AFE mod disable failed %d\n",
+ __func__, ret);
+ }
+
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
stop.hdr.pkt_size = sizeof(stop);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index ea2b5c6..49b6d03 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -279,13 +279,13 @@
{
out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
- S_IFREG | S_IRUGO | S_IWUGO,\
+ S_IRUGO | S_IWUSR | S_IWGRP,\
NULL, NULL, &audio_output_latency_debug_fops);
if (IS_ERR(out_dentry))
pr_err("debugfs_create_file failed\n");
in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
- S_IFREG | S_IRUGO | S_IWUGO,\
+ S_IRUGO | S_IWUSR | S_IWGRP,\
NULL, NULL, &audio_input_latency_debug_fops);
if (IS_ERR(in_dentry))
pr_err("debugfs_create_file failed\n");
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 12e83b0..754a4fa 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -35,10 +35,6 @@
#define CMD_STATUS_SUCCESS 0
#define CMD_STATUS_FAIL 1
-#define VOC_PATH_PASSIVE 0
-#define VOC_PATH_FULL 1
-#define VOC_PATH_VOLTE_PASSIVE 2
-
/* CVP CAL Size: 245760 = 240 * 1024 */
#define CVP_CAL_SIZE 245760
/* CVS CAL Size: 49152 = 48 * 1024 */
@@ -180,6 +176,9 @@
if (name != NULL) {
if (!strncmp(name, "Voice session", 13))
session_id = common.voice[VOC_PATH_PASSIVE].session_id;
+ else if (!strncmp(name, "Voice2 session", 14))
+ session_id =
+ common.voice[VOC_PATH_VOICE2_PASSIVE].session_id;
else if (!strncmp(name, "VoLTE session", 13))
session_id =
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
@@ -223,6 +222,11 @@
return (session_id == common.voice[VOC_PATH_VOLTE_PASSIVE].session_id);
}
+static bool is_voice2_session(u16 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
+}
+
static int voice_apr_register(void)
{
void *modem_mvm, *modem_cvs, *modem_cvp;
@@ -347,7 +351,8 @@
}
pr_debug("%s: VoLTE command to MVM\n", __func__);
if (is_volte_session(v->session_id) ||
- is_voice_session(v->session_id)) {
+ is_voice_session(v->session_id) ||
+ is_voice2_session(v->session_id)) {
mvm_handle = voice_get_mvm_handle(v);
mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
@@ -421,7 +426,8 @@
if (!mvm_handle) {
if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id)) {
+ is_volte_session(v->session_id) ||
+ is_voice2_session(v->session_id)) {
mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -441,8 +447,12 @@
strlcpy(mvm_session_cmd.mvm_session.name,
"default volte voice",
sizeof(mvm_session_cmd.mvm_session.name));
+ } else if (is_voice2_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ VOICE2_SESSION_VSID,
+ sizeof(mvm_session_cmd.mvm_session.name));
} else {
- strlcpy(mvm_session_cmd.mvm_session.name,
+ strlcpy(mvm_session_cmd.mvm_session.name,
"default modem voice",
sizeof(mvm_session_cmd.mvm_session.name));
}
@@ -503,7 +513,8 @@
/* send cmd to create cvs session */
if (!cvs_handle) {
if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id)) {
+ is_volte_session(v->session_id) ||
+ is_voice2_session(v->session_id)) {
pr_debug("%s: creating CVS passive session\n",
__func__);
@@ -524,6 +535,10 @@
strlcpy(cvs_session_cmd.cvs_session.name,
"default volte voice",
sizeof(cvs_session_cmd.cvs_session.name));
+ } else if (is_voice2_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ VOICE2_SESSION_VSID,
+ sizeof(cvs_session_cmd.cvs_session.name));
} else {
strlcpy(cvs_session_cmd.cvs_session.name,
"default modem voice",
@@ -4167,6 +4182,7 @@
case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
case VSS_IMVM_CMD_SET_CAL_NETWORK:
case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
+ case VSS_IMEMORY_CMD_MAP_PHYSICAL:
case VSS_IMEMORY_CMD_UNMAP:
case VSS_IMVM_CMD_STANDBY_VOICE:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 98bd002..ef5c6e3 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1275,7 +1275,7 @@
void *buf;
};
-#define MAX_VOC_SESSIONS 3
+#define MAX_VOC_SESSIONS 4
#define SESSION_ID_BASE 0xFFF0
struct common_data {
@@ -1327,6 +1327,20 @@
TX_PATH,
};
+
+#define VOC_PATH_PASSIVE 0
+#define VOC_PATH_FULL 1
+#define VOC_PATH_VOLTE_PASSIVE 2
+#define VOC_PATH_VOICE2_PASSIVE 3
+
+#define MAX_SESSION_NAME_LEN 32
+#define VOICE_SESSION_NAME "Voice session"
+#define VOIP_SESSION_NAME "VoIP session"
+#define VOLTE_SESSION_NAME "VoLTE session"
+#define VOICE2_SESSION_NAME "Voice2 session"
+
+#define VOICE2_SESSION_VSID "10DC1000"
+
/* called by alsa driver */
int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
uint32_t enable);
@@ -1353,10 +1367,6 @@
int voc_enable_dtmf_rx_detection(uint16_t session_id, uint32_t enable);
void voc_disable_dtmf_det_on_active_sessions(void);
-#define MAX_SESSION_NAME_LEN 32
-#define VOICE_SESSION_NAME "Voice session"
-#define VOIP_SESSION_NAME "VoIP session"
-#define VOLTE_SESSION_NAME "VoLTE session"
uint16_t voc_get_session_id(char *name);
int voc_start_playback(uint32_t set);