diff options
1109 files changed, 43931 insertions, 11457 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 793acf999e9e..ed3e5e949fce 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -412,6 +412,8 @@ sysctl/ - directory with info on the /proc/sys/* files. target/ - directory with info on generating TCM v4 fabric .ko modules +tee.txt + - info on the TEE subsystem and drivers this_cpu_ops.txt - List rationale behind and the way to use this_cpu operations. thermal/ diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX index f773a264ae02..1672573b037a 100644 --- a/Documentation/RCU/00-INDEX +++ b/Documentation/RCU/00-INDEX @@ -17,7 +17,7 @@ rcu_dereference.txt rcubarrier.txt - RCU and Unloadable Modules rculist_nulls.txt - - RCU list primitives for use with SLAB_DESTROY_BY_RCU + - RCU list primitives for use with SLAB_TYPESAFE_BY_RCU rcuref.txt - Reference-count design for elements of lists/arrays protected by RCU rcu.txt diff --git a/Documentation/RCU/Design/Data-Structures/Data-Structures.html b/Documentation/RCU/Design/Data-Structures/Data-Structures.html index d583c653a703..38d6d800761f 100644 --- a/Documentation/RCU/Design/Data-Structures/Data-Structures.html +++ b/Documentation/RCU/Design/Data-Structures/Data-Structures.html @@ -19,6 +19,8 @@ to each other. The <tt>rcu_state</tt> Structure</a> <li> <a href="#The rcu_node Structure"> The <tt>rcu_node</tt> Structure</a> +<li> <a href="#The rcu_segcblist Structure"> + The <tt>rcu_segcblist</tt> Structure</a> <li> <a href="#The rcu_data Structure"> The <tt>rcu_data</tt> Structure</a> <li> <a href="#The rcu_dynticks Structure"> @@ -841,6 +843,134 @@ for lockdep lock-class names. Finally, lines 64-66 produce an error if the maximum number of CPUs is too large for the specified fanout. +<h3><a name="The rcu_segcblist Structure"> +The <tt>rcu_segcblist</tt> Structure</a></h3> + +The <tt>rcu_segcblist</tt> structure maintains a segmented list of +callbacks as follows: + +<pre> + 1 #define RCU_DONE_TAIL 0 + 2 #define RCU_WAIT_TAIL 1 + 3 #define RCU_NEXT_READY_TAIL 2 + 4 #define RCU_NEXT_TAIL 3 + 5 #define RCU_CBLIST_NSEGS 4 + 6 + 7 struct rcu_segcblist { + 8 struct rcu_head *head; + 9 struct rcu_head **tails[RCU_CBLIST_NSEGS]; +10 unsigned long gp_seq[RCU_CBLIST_NSEGS]; +11 long len; +12 long len_lazy; +13 }; +</pre> + +<p> +The segments are as follows: + +<ol> +<li> <tt>RCU_DONE_TAIL</tt>: Callbacks whose grace periods have elapsed. + These callbacks are ready to be invoked. +<li> <tt>RCU_WAIT_TAIL</tt>: Callbacks that are waiting for the + current grace period. + Note that different CPUs can have different ideas about which + grace period is current, hence the <tt>->gp_seq</tt> field. +<li> <tt>RCU_NEXT_READY_TAIL</tt>: Callbacks waiting for the next + grace period to start. +<li> <tt>RCU_NEXT_TAIL</tt>: Callbacks that have not yet been + associated with a grace period. +</ol> + +<p> +The <tt>->head</tt> pointer references the first callback or +is <tt>NULL</tt> if the list contains no callbacks (which is +<i>not</i> the same as being empty). +Each element of the <tt>->tails[]</tt> array references the +<tt>->next</tt> pointer of the last callback in the corresponding +segment of the list, or the list's <tt>->head</tt> pointer if +that segment and all previous segments are empty. +If the corresponding segment is empty but some previous segment is +not empty, then the array element is identical to its predecessor. +Older callbacks are closer to the head of the list, and new callbacks +are added at the tail. +This relationship between the <tt>->head</tt> pointer, the +<tt>->tails[]</tt> array, and the callbacks is shown in this +diagram: + +</p><p><img src="nxtlist.svg" alt="nxtlist.svg" width="40%"> + +</p><p>In this figure, the <tt>->head</tt> pointer references the +first +RCU callback in the list. +The <tt>->tails[RCU_DONE_TAIL]</tt> array element references +the <tt>->head</tt> pointer itself, indicating that none +of the callbacks is ready to invoke. +The <tt>->tails[RCU_WAIT_TAIL]</tt> array element references callback +CB 2's <tt>->next</tt> pointer, which indicates that +CB 1 and CB 2 are both waiting on the current grace period, +give or take possible disagreements about exactly which grace period +is the current one. +The <tt>->tails[RCU_NEXT_READY_TAIL]</tt> array element +references the same RCU callback that <tt>->tails[RCU_WAIT_TAIL]</tt> +does, which indicates that there are no callbacks waiting on the next +RCU grace period. +The <tt>->tails[RCU_NEXT_TAIL]</tt> array element references +CB 4's <tt>->next</tt> pointer, indicating that all the +remaining RCU callbacks have not yet been assigned to an RCU grace +period. +Note that the <tt>->tails[RCU_NEXT_TAIL]</tt> array element +always references the last RCU callback's <tt>->next</tt> pointer +unless the callback list is empty, in which case it references +the <tt>->head</tt> pointer. + +<p> +There is one additional important special case for the +<tt>->tails[RCU_NEXT_TAIL]</tt> array element: It can be <tt>NULL</tt> +when this list is <i>disabled</i>. +Lists are disabled when the corresponding CPU is offline or when +the corresponding CPU's callbacks are offloaded to a kthread, +both of which are described elsewhere. + +</p><p>CPUs advance their callbacks from the +<tt>RCU_NEXT_TAIL</tt> to the <tt>RCU_NEXT_READY_TAIL</tt> to the +<tt>RCU_WAIT_TAIL</tt> to the <tt>RCU_DONE_TAIL</tt> list segments +as grace periods advance. + +</p><p>The <tt>->gp_seq[]</tt> array records grace-period +numbers corresponding to the list segments. +This is what allows different CPUs to have different ideas as to +which is the current grace period while still avoiding premature +invocation of their callbacks. +In particular, this allows CPUs that go idle for extended periods +to determine which of their callbacks are ready to be invoked after +reawakening. + +</p><p>The <tt>->len</tt> counter contains the number of +callbacks in <tt>->head</tt>, and the +<tt>->len_lazy</tt> contains the number of those callbacks that +are known to only free memory, and whose invocation can therefore +be safely deferred. + +<p><b>Important note</b>: It is the <tt>->len</tt> field that +determines whether or not there are callbacks associated with +this <tt>rcu_segcblist</tt> structure, <i>not</i> the <tt>->head</tt> +pointer. +The reason for this is that all the ready-to-invoke callbacks +(that is, those in the <tt>RCU_DONE_TAIL</tt> segment) are extracted +all at once at callback-invocation time. +If callback invocation must be postponed, for example, because a +high-priority process just woke up on this CPU, then the remaining +callbacks are placed back on the <tt>RCU_DONE_TAIL</tt> segment. +Either way, the <tt>->len</tt> and <tt>->len_lazy</tt> counts +are adjusted after the corresponding callbacks have been invoked, and so +again it is the <tt>->len</tt> count that accurately reflects whether +or not there are callbacks associated with this <tt>rcu_segcblist</tt> +structure. +Of course, off-CPU sampling of the <tt>->len</tt> count requires +the use of appropriate synchronization, for example, memory barriers. +This synchronization can be a bit subtle, particularly in the case +of <tt>rcu_barrier()</tt>. + <h3><a name="The rcu_data Structure"> The <tt>rcu_data</tt> Structure</a></h3> @@ -983,62 +1113,18 @@ choice. as follows: <pre> - 1 struct rcu_head *nxtlist; - 2 struct rcu_head **nxttail[RCU_NEXT_SIZE]; - 3 unsigned long nxtcompleted[RCU_NEXT_SIZE]; - 4 long qlen_lazy; - 5 long qlen; - 6 long qlen_last_fqs_check; + 1 struct rcu_segcblist cblist; + 2 long qlen_last_fqs_check; + 3 unsigned long n_cbs_invoked; + 4 unsigned long n_nocbs_invoked; + 5 unsigned long n_cbs_orphaned; + 6 unsigned long n_cbs_adopted; 7 unsigned long n_force_qs_snap; - 8 unsigned long n_cbs_invoked; - 9 unsigned long n_cbs_orphaned; -10 unsigned long n_cbs_adopted; -11 long blimit; + 8 long blimit; </pre> -<p>The <tt>->nxtlist</tt> pointer and the -<tt>->nxttail[]</tt> array form a four-segment list with -older callbacks near the head and newer ones near the tail. -Each segment contains callbacks with the corresponding relationship -to the current grace period. -The pointer out of the end of each of the four segments is referenced -by the element of the <tt>->nxttail[]</tt> array indexed by -<tt>RCU_DONE_TAIL</tt> (for callbacks handled by a prior grace period), -<tt>RCU_WAIT_TAIL</tt> (for callbacks waiting on the current grace period), -<tt>RCU_NEXT_READY_TAIL</tt> (for callbacks that will wait on the next -grace period), and -<tt>RCU_NEXT_TAIL</tt> (for callbacks that are not yet associated -with a specific grace period) -respectively, as shown in the following figure. - -</p><p><img src="nxtlist.svg" alt="nxtlist.svg" width="40%"> - -</p><p>In this figure, the <tt>->nxtlist</tt> pointer references the -first -RCU callback in the list. -The <tt>->nxttail[RCU_DONE_TAIL]</tt> array element references -the <tt>->nxtlist</tt> pointer itself, indicating that none -of the callbacks is ready to invoke. -The <tt>->nxttail[RCU_WAIT_TAIL]</tt> array element references callback -CB 2's <tt>->next</tt> pointer, which indicates that -CB 1 and CB 2 are both waiting on the current grace period. -The <tt>->nxttail[RCU_NEXT_READY_TAIL]</tt> array element -references the same RCU callback that <tt>->nxttail[RCU_WAIT_TAIL]</tt> -does, which indicates that there are no callbacks waiting on the next -RCU grace period. -The <tt>->nxttail[RCU_NEXT_TAIL]</tt> array element references -CB 4's <tt>->next</tt> pointer, indicating that all the -remaining RCU callbacks have not yet been assigned to an RCU grace -period. -Note that the <tt>->nxttail[RCU_NEXT_TAIL]</tt> array element -always references the last RCU callback's <tt>->next</tt> pointer -unless the callback list is empty, in which case it references -the <tt>->nxtlist</tt> pointer. - -</p><p>CPUs advance their callbacks from the -<tt>RCU_NEXT_TAIL</tt> to the <tt>RCU_NEXT_READY_TAIL</tt> to the -<tt>RCU_WAIT_TAIL</tt> to the <tt>RCU_DONE_TAIL</tt> list segments -as grace periods advance. +<p>The <tt>->cblist</tt> structure is the segmented callback list +described earlier. The CPU advances the callbacks in its <tt>rcu_data</tt> structure whenever it notices that another RCU grace period has completed. The CPU detects the completion of an RCU grace period by noticing @@ -1049,16 +1135,7 @@ Recall that each <tt>rcu_node</tt> structure's <tt>->completed</tt> field is updated at the end of each grace period. -</p><p>The <tt>->nxtcompleted[]</tt> array records grace-period -numbers corresponding to the list segments. -This allows CPUs that go idle for extended periods to determine -which of their callbacks are ready to be invoked after reawakening. - -</p><p>The <tt>->qlen</tt> counter contains the number of -callbacks in <tt>->nxtlist</tt>, and the -<tt>->qlen_lazy</tt> contains the number of those callbacks that -are known to only free memory, and whose invocation can therefore -be safely deferred. +<p> The <tt>->qlen_last_fqs_check</tt> and <tt>->n_force_qs_snap</tt> coordinate the forcing of quiescent states from <tt>call_rcu()</tt> and friends when callback @@ -1069,6 +1146,10 @@ lists grow excessively long. fields count the number of callbacks invoked, sent to other CPUs when this CPU goes offline, and received from other CPUs when those other CPUs go offline. +The <tt>->n_nocbs_invoked</tt> is used when the CPU's callbacks +are offloaded to a kthread. + +<p> Finally, the <tt>->blimit</tt> counter is the maximum number of RCU callbacks that may be invoked at a given time. @@ -1104,6 +1185,9 @@ Its fields are as follows: 1 int dynticks_nesting; 2 int dynticks_nmi_nesting; 3 atomic_t dynticks; + 4 bool rcu_need_heavy_qs; + 5 unsigned long rcu_qs_ctr; + 6 bool rcu_urgent_qs; </pre> <p>The <tt>->dynticks_nesting</tt> field counts the @@ -1117,11 +1201,32 @@ NMIs are counted by the <tt>->dynticks_nmi_nesting</tt> field, except that NMIs that interrupt non-dyntick-idle execution are not counted. -</p><p>Finally, the <tt>->dynticks</tt> field counts the corresponding +</p><p>The <tt>->dynticks</tt> field counts the corresponding CPU's transitions to and from dyntick-idle mode, so that this counter has an even value when the CPU is in dyntick-idle mode and an odd value otherwise. +</p><p>The <tt>->rcu_need_heavy_qs</tt> field is used +to record the fact that the RCU core code would really like to +see a quiescent state from the corresponding CPU, so much so that +it is willing to call for heavy-weight dyntick-counter operations. +This flag is checked by RCU's context-switch and <tt>cond_resched()</tt> +code, which provide a momentary idle sojourn in response. + +</p><p>The <tt>->rcu_qs_ctr</tt> field is used to record +quiescent states from <tt>cond_resched()</tt>. +Because <tt>cond_resched()</tt> can execute quite frequently, this +must be quite lightweight, as in a non-atomic increment of this +per-CPU field. + +</p><p>Finally, the <tt>->rcu_urgent_qs</tt> field is used to record +the fact that the RCU core code would really like to see a quiescent +state from the corresponding CPU, with the various other fields indicating +just how badly RCU wants this quiescent state. +This flag is checked by RCU's context-switch and <tt>cond_resched()</tt> +code, which, if nothing else, non-atomically increment <tt>->rcu_qs_ctr</tt> +in response. + <table> <tr><th> </th></tr> <tr><th align="left">Quick Quiz:</th></tr> diff --git a/Documentation/RCU/Design/Data-Structures/nxtlist.svg b/Documentation/RCU/Design/Data-Structures/nxtlist.svg index abc4cc73a097..0223e79c38e0 100644 --- a/Documentation/RCU/Design/Data-Structures/nxtlist.svg +++ b/Documentation/RCU/Design/Data-Structures/nxtlist.svg @@ -19,7 +19,7 @@ id="svg2" version="1.1" inkscape:version="0.48.4 r9939" - sodipodi:docname="nxtlist.fig"> + sodipodi:docname="segcblist.svg"> <metadata id="metadata94"> <rdf:RDF> @@ -28,7 +28,7 @@ <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> + <dc:title /> </cc:Work> </rdf:RDF> </metadata> @@ -241,61 +241,51 @@ xml:space="preserve" x="225" y="675" - fill="#000000" - font-family="Courier" font-style="normal" font-weight="bold" font-size="324" - text-anchor="start" - id="text64">nxtlist</text> + id="text64" + style="font-size:324px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">->head</text> <!-- Text --> <text xml:space="preserve" x="225" y="1800" - fill="#000000" - font-family="Courier" font-style="normal" font-weight="bold" font-size="324" - text-anchor="start" - id="text66">nxttail[RCU_DONE_TAIL]</text> + id="text66" + style="font-size:324px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">->tails[RCU_DONE_TAIL]</text> <!-- Text --> <text xml:space="preserve" x="225" y="2925" - fill="#000000" - font-family="Courier" font-style="normal" font-weight="bold" font-size="324" - text-anchor="start" - id="text68">nxttail[RCU_WAIT_TAIL]</text> + id="text68" + style="font-size:324px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">->tails[RCU_WAIT_TAIL]</text> <!-- Text --> <text xml:space="preserve" x="225" y="4050" - fill="#000000" - font-family="Courier" font-style="normal" font-weight="bold" font-size="324" - text-anchor="start" - id="text70">nxttail[RCU_NEXT_READY_TAIL]</text> + id="text70" + style="font-size:324px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">->tails[RCU_NEXT_READY_TAIL]</text> <!-- Text --> <text xml:space="preserve" x="225" y="5175" - fill="#000000" - font-family="Courier" font-style="normal" font-weight="bold" font-size="324" - text-anchor="start" - id="text72">nxttail[RCU_NEXT_TAIL]</text> + id="text72" + style="font-size:324px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">->tails[RCU_NEXT_TAIL]</text> <!-- Text --> <text xml:space="preserve" diff --git a/Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.html b/Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.html index 7a3194c5559a..e5d0bbd0230b 100644 --- a/Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.html +++ b/Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.html @@ -284,6 +284,7 @@ Expedited Grace Period Refinements</a></h2> Funnel locking and wait/wakeup</a>. <li> <a href="#Use of Workqueues">Use of Workqueues</a>. <li> <a href="#Stall Warnings">Stall warnings</a>. +<li> <a href="#Mid-Boot Operation">Mid-boot operation</a>. </ol> <h3><a name="Idle-CPU Checks">Idle-CPU Checks</a></h3> @@ -524,7 +525,7 @@ their grace periods and carrying out their wakeups. In earlier implementations, the task requesting the expedited grace period also drove it to completion. This straightforward approach had the disadvantage of needing to -account for signals sent to user tasks, +account for POSIX signals sent to user tasks, so more recent implemementations use the Linux kernel's <a href="https://www.kernel.org/doc/Documentation/workqueue.txt">workqueues</a>. @@ -533,8 +534,8 @@ The requesting task still does counter snapshotting and funnel-lock processing, but the task reaching the top of the funnel lock does a <tt>schedule_work()</tt> (from <tt>_synchronize_rcu_expedited()</tt> so that a workqueue kthread does the actual grace-period processing. -Because workqueue kthreads do not accept signals, grace-period-wait -processing need not allow for signals. +Because workqueue kthreads do not accept POSIX signals, grace-period-wait +processing need not allow for POSIX signals. In addition, this approach allows wakeups for the previous expedited grace period to be overlapped with processing for the next expedited @@ -586,6 +587,46 @@ blocking the current grace period are printed. Each stall warning results in another pass through the loop, but the second and subsequent passes use longer stall times. +<h3><a name="Mid-Boot Operation">Mid-boot operation</a></h3> + +<p> +The use of workqueues has the advantage that the expedited +grace-period code need not worry about POSIX signals. +Unfortunately, it has the +corresponding disadvantage that workqueues cannot be used until +they are initialized, which does not happen until some time after +the scheduler spawns the first task. +Given that there are parts of the kernel that really do want to +execute grace periods during this mid-boot “dead zone”, +expedited grace periods must do something else during thie time. + +<p> +What they do is to fall back to the old practice of requiring that the +requesting task drive the expedited grace period, as was the case +before the use of workqueues. +However, the requesting task is only required to drive the grace period +during the mid-boot dead zone. +Before mid-boot, a synchronous grace period is a no-op. +Some time after mid-boot, workqueues are used. + +<p> +Non-expedited non-SRCU synchronous grace periods must also operate +normally during mid-boot. +This is handled by causing non-expedited grace periods to take the +expedited code path during mid-boot. + +<p> +The current code assumes that there are no POSIX signals during +the mid-boot dead zone. +However, if an overwhelming need for POSIX signals somehow arises, +appropriate adjustments can be made to the expedited stall-warning code. +One such adjustment would reinstate the pre-workqueue stall-warning +checks, but only during the mid-boot dead zone. + +<p> +With this refinement, synchronous grace periods can now be used from +task context pretty much any time during the life of the kernel. + <h3><a name="Summary"> Summary</a></h3> diff --git a/Documentation/RCU/Design/Requirements/Requirements.html b/Documentation/RCU/Design/Requirements/Requirements.html index 21593496aca6..f60adf112663 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.html +++ b/Documentation/RCU/Design/Requirements/Requirements.html @@ -659,8 +659,9 @@ systems with more than one CPU: In other words, a given instance of <tt>synchronize_rcu()</tt> can avoid waiting on a given RCU read-side critical section only if it can prove that <tt>synchronize_rcu()</tt> started first. + </font> - <p> + <p><font color="ffffff"> A related question is “When <tt>rcu_read_lock()</tt> doesn't generate any code, why does it matter how it relates to a grace period?” @@ -675,8 +676,9 @@ systems with more than one CPU: within the critical section, in which case none of the accesses within the critical section may observe the effects of any access following the grace period. + </font> - <p> + <p><font color="ffffff"> As of late 2016, mathematical models of RCU take this viewpoint, for example, see slides 62 and 63 of the @@ -1616,8 +1618,8 @@ CPUs should at least make reasonable forward progress. In return for its shorter latencies, <tt>synchronize_rcu_expedited()</tt> is permitted to impose modest degradation of real-time latency on non-idle online CPUs. -That said, it will likely be necessary to take further steps to reduce this -degradation, hopefully to roughly that of a scheduling-clock interrupt. +Here, “modest” means roughly the same latency +degradation as a scheduling-clock interrupt. <p> There are a number of situations where even @@ -1913,12 +1915,9 @@ This requirement is another factor driving batching of grace periods, but it is also the driving force behind the checks for large numbers of queued RCU callbacks in the <tt>call_rcu()</tt> code path. Finally, high update rates should not delay RCU read-side critical -sections, although some read-side delays can occur when using +sections, although some small read-side delays can occur when using <tt>synchronize_rcu_expedited()</tt>, courtesy of this function's use -of <tt>try_stop_cpus()</tt>. -(In the future, <tt>synchronize_rcu_expedited()</tt> will be -converted to use lighter-weight inter-processor interrupts (IPIs), -but this will still disturb readers, though to a much smaller degree.) +of <tt>smp_call_function_single()</tt>. <p> Although all three of these corner cases were understood in the early @@ -2154,7 +2153,8 @@ as will <tt>rcu_assign_pointer()</tt>. <p> Although <tt>call_rcu()</tt> may be invoked at any time during boot, callbacks are not guaranteed to be invoked until after -the scheduler is fully up and running. +all of RCU's kthreads have been spawned, which occurs at +<tt>early_initcall()</tt> time. This delay in callback invocation is due to the fact that RCU does not invoke callbacks until it is fully initialized, and this full initialization cannot occur until after the scheduler has initialized itself to the @@ -2167,8 +2167,10 @@ on what operations those callbacks could invoke. Perhaps surprisingly, <tt>synchronize_rcu()</tt>, <a href="#Bottom-Half Flavor"><tt>synchronize_rcu_bh()</tt></a> (<a href="#Bottom-Half Flavor">discussed below</a>), -and -<a href="#Sched Flavor"><tt>synchronize_sched()</tt></a> +<a href="#Sched Flavor"><tt>synchronize_sched()</tt></a>, +<tt>synchronize_rcu_expedited()</tt>, +<tt>synchronize_rcu_bh_expedited()</tt>, and +<tt>synchronize_sched_expedited()</tt> will all operate normally during very early boot, the reason being that there is only one CPU and preemption is disabled. @@ -2178,45 +2180,59 @@ state and thus a grace period, so the early-boot implementation can be a no-op. <p> -Both <tt>synchronize_rcu_bh()</tt> and <tt>synchronize_sched()</tt> -continue to operate normally through the remainder of boot, courtesy -of the fact that preemption is disabled across their RCU read-side -critical sections and also courtesy of the fact that there is still -only one CPU. -However, once the scheduler starts initializing, preemption is enabled. -There is still only a single CPU, but the fact that preemption is enabled -means that the no-op implementation of <tt>synchronize_rcu()</tt> no -longer works in <tt>CONFIG_PREEMPT=y</tt> kernels. -Therefore, as soon as the scheduler starts initializing, the early-boot -fastpath is disabled. -This means that <tt>synchronize_rcu()</tt> switches to its runtime -mode of operation where it posts callbacks, which in turn means that -any call to <tt>synchronize_rcu()</tt> will block until the corresponding -callback is invoked. -Unfortunately, the callback cannot be invoked until RCU's runtime -grace-period machinery is up and running, which cannot happen until -the scheduler has initialized itself sufficiently to allow RCU's -kthreads to be spawned. -Therefore, invoking <tt>synchronize_rcu()</tt> during scheduler -initialization can result in deadlock. +However, once the scheduler has spawned its first kthread, this early +boot trick fails for <tt>synchronize_rcu()</tt> (as well as for +<tt>synchronize_rcu_expedited()</tt>) in <tt>CONFIG_PREEMPT=y</tt> +kernels. +The reason is that an RCU read-side critical section might be preempted, +which means that a subsequent <tt>synchronize_rcu()</tt> really does have +to wait for something, as opposed to simply returning immediately. +Unfortunately, <tt>synchronize_rcu()</tt> can't do this until all of +its kthreads are spawned, which doesn't happen until some time during +<tt>early_initcalls()</tt> time. +But this is no excuse: RCU is nevertheless required to correctly handle +synchronous grace periods during this time period. +Once all of its kthreads are up and running, RCU starts running +normally. <table> <tr><th> </th></tr> <tr><th align="left">Quick Quiz:</th></tr> <tr><td> - So what happens with <tt>synchronize_rcu()</tt> during - scheduler initialization for <tt>CONFIG_PREEMPT=n</tt> - kernels? + How can RCU possibly handle grace periods before all of its + kthreads have been spawned??? </td></tr> <tr><th align="left">Answer:</th></tr> <tr><td bgcolor="#ffffff"><font color="ffffff"> - In <tt>CONFIG_PREEMPT=n</tt> kernel, <tt>synchronize_rcu()</tt> - maps directly to <tt>synchronize_sched()</tt>. - Therefore, <tt>synchronize_rcu()</tt> works normally throughout - boot in <tt>CONFIG_PREEMPT=n</tt> kernels. - However, your code must also work in <tt>CONFIG_PREEMPT=y</tt> kernels, - so it is still necessary to avoid invoking <tt>synchronize_rcu()</tt> - during scheduler initialization. + Very carefully! + </font> + + <p><font color="ffffff"> + During the “dead zone” between the time that the + scheduler spawns the first task and the time that all of RCU's + kthreads have been spawned, all synchronous grace periods are + handled by the expedited grace-period mechanism. + At runtime, this expedited mechanism relies on workqueues, but + during the dead zone the requesting task itself drives the + desired expedited grace period. + Because dead-zone execution takes place within task context, + everything works. + Once the dead zone ends, expedited grace periods go back to + using workqueues, as is required to avoid problems that would + otherwise occur when a user task received a POSIX signal while + driving an expedited grace period. + </font> + + <p><font color="ffffff"> + And yes, this does mean that it is unhelpful to send POSIX + signals to random tasks between the time that the scheduler + spawns its first kthread and the time that RCU's kthreads + have all been spawned. + If there ever turns out to be a good reason for sending POSIX + signals during that time, appropriate adjustments will be made. + (If it turns out that POSIX signals are sent during this time for + no good reason, other adjustments will be made, appropriate + or otherwise.) </font></td></tr> <tr><td> </td></tr> </table> @@ -2295,12 +2311,61 @@ situation, and Dipankar Sarma incorporated <tt>rcu_barrier()</tt> into RCU. The need for <tt>rcu_barrier()</tt> for module unloading became apparent later. +<p> +<b>Important note</b>: The <tt>rcu_barrier()</tt> function is not, +repeat, <i>not</i>, obligated to wait for a grace period. +It is instead only required to wait for RCU callbacks that have +already been posted. +Therefore, if there are no RCU callbacks posted anywhere in the system, +<tt>rcu_barrier()</tt> is within its rights to return immediately. +Even if there are callbacks posted, <tt>rcu_barrier()</tt> does not +necessarily need to wait for a grace period. + +<table> +<tr><th> </th></tr> +<tr><th align="left">Quick Quiz:</th></tr> +<tr><td> + Wait a minute! + Each RCU callbacks must wait for a grace period to complete, + and <tt>rcu_barrier()</tt> must wait for each pre-existing + callback to be invoked. + Doesn't <tt>rcu_barrier()</tt> therefore need to wait for + a full grace period if there is even one callback posted anywhere + in the system? +</td></tr> +<tr><th align="left">Answer:</th></tr> +<tr><td bgcolor="#ffffff"><font color="ffffff"> + Absolutely not!!! + </font> + + <p><font color="ffffff"> + Yes, each RCU callbacks must wait for a grace period to complete, + but it might well be partly (or even completely) finished waiting + by the time <tt>rcu_barrier()</tt> is invoked. + In that case, <tt>rcu_barrier()</tt> need only wait for the + remaining portion of the grace period to elapse. + So even if there are quite a few callbacks posted, + <tt>rcu_barrier()</tt> might well return quite quickly. + </font> + + <p><font color="ffffff"> + So if you need to wait for a grace period as well as for all + pre-existing callbacks, you will need to invoke both + <tt>synchronize_rcu()</tt> and <tt>rcu_barrier()</tt>. + If latency is a concern, you can always use workqueues + to invoke them concurrently. +</font></td></tr> +<tr><td> </td></tr> +</table> + <h3><a name="Hotplug CPU">Hotplug CPU</a></h3> <p> The Linux kernel supports CPU hotplug, which means that CPUs can come and go. -It is of course illegal to use any RCU API member from an offline CPU. +It is of course illegal to use any RCU API member from an offline CPU, +with the exception of <a href="#Sleepable RCU">SRCU</a> read-side +critical sections. This requirement was present from day one in DYNIX/ptx, but on the other hand, the Linux kernel's CPU-hotplug implementation is “interesting.” @@ -2310,19 +2375,18 @@ The Linux-kernel CPU-hotplug implementation has notifiers that are used to allow the various kernel subsystems (including RCU) to respond appropriately to a given CPU-hotplug operation. Most RCU operations may be invoked from CPU-hotplug notifiers, -including even normal synchronous grace-period operations -such as <tt>synchronize_rcu()</tt>. -However, expedited grace-period operations such as -<tt>synchronize_rcu_expedited()</tt> are not supported, -due to the fact that current implementations block CPU-hotplug -operations, which could result in deadlock. +including even synchronous grace-period operations such as +<tt>synchronize_rcu()</tt> and <tt>synchronize_rcu_expedited()</tt>. <p> -In addition, all-callback-wait operations such as +However, all-callback-wait operations such as <tt>rcu_barrier()</tt> are also not supported, due to the fact that there are phases of CPU-hotplug operations where the outgoing CPU's callbacks will not be invoked until after the CPU-hotplug operation ends, which could also result in deadlock. +Furthermore, <tt>rcu_barrier()</tt> blocks CPU-hotplug operations +during its execution, which results in another type of deadlock +when invoked from a CPU-hotplug notifier. <h3><a name="Scheduler and RCU">Scheduler and RCU</a></h3> @@ -2864,6 +2928,27 @@ API, which, in combination with <tt>srcu_read_unlock()</tt>, guarantees a full memory barrier. <p> +Also unlike other RCU flavors, SRCU's callbacks-wait function +<tt>srcu_barrier()</tt> may be invoked from CPU-hotplug notifiers, +though this is not necessarily a good idea. +The reason that this is possible is that SRCU is insensitive +to whether or not a CPU is online, which means that <tt>srcu_barrier()</tt> +need not exclude CPU-hotplug operations. + +<p> +As of v4.12, SRCU's callbacks are maintained per-CPU, eliminating +a locking bottleneck present in prior kernel versions. +Although this will allow users to put much heavier stress on +<tt>call_srcu()</tt>, it is important to note that SRCU does not +yet take any special steps to deal with callback flooding. +So if you are posting (say) 10,000 SRCU callbacks per second per CPU, +you are probably totally OK, but if you intend to post (say) 1,000,000 +SRCU callbacks per second per CPU, please run some tests first. +SRCU just might need a few adjustment to deal with that sort of load. +Of course, your mileage may vary based on the speed of your CPUs and +the size of your memory. + +<p> The <a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">SRCU API</a> includes @@ -3021,8 +3106,8 @@ to do some redesign to avoid this scalability problem. <p> RCU disables CPU hotplug in a few places, perhaps most notably in the -expedited grace-period and <tt>rcu_barrier()</tt> operations. -If there is a strong reason to use expedited grace periods in CPU-hotplug +<tt>rcu_barrier()</tt> operations. +If there is a strong reason to use <tt>rcu_barrier()</tt> in CPU-hotplug notifiers, it will be necessary to avoid disabling CPU hotplug. This would introduce some complexity, so there had better be a <i>very</i> good reason. @@ -3096,9 +3181,5 @@ Andy Lutomirski for their help in rendering this article human readable, and to Michelle Rankin for her support of this effort. Other contributions are acknowledged in the Linux kernel's git archive. -The cartoon is copyright (c) 2013 by Melissa Broussard, -and is provided -under the terms of the Creative Commons Attribution-Share Alike 3.0 -United States license. </body></html> diff --git a/Documentation/RCU/rcu_dereference.txt b/Documentation/RCU/rcu_dereference.txt index c0bf2441a2ba..b2a613f16d74 100644 --- a/Documentation/RCU/rcu_dereference.txt +++ b/Documentation/RCU/rcu_dereference.txt @@ -138,6 +138,15 @@ o Be very careful about comparing pointers obtained from This sort of comparison occurs frequently when scanning RCU-protected circular linked lists. + Note that if checks for being within an RCU read-side + critical section are not required and the pointer is never + dereferenced, rcu_access_pointer() should be used in place + of rcu_dereference(). The rcu_access_pointer() primitive + does not require an enclosing read-side critical section, + and also omits the smp_read_barrier_depends() included in + rcu_dereference(), which in turn should provide a small + performance gain in some CPUs (e.g., the DEC Alpha). + o The comparison is against a pointer that references memory that was initialized "a long time ago." The reason this is safe is that even if misordering occurs, the diff --git a/Documentation/RCU/rculist_nulls.txt b/Documentation/RCU/rculist_nulls.txt index 18f9651ff23d..8151f0195f76 100644 --- a/Documentation/RCU/rculist_nulls.txt +++ b/Documentation/RCU/rculist_nulls.txt @@ -1,5 +1,5 @@ Using hlist_nulls to protect read-mostly linked lists and -objects using SLAB_DESTROY_BY_RCU allocations. +objects using SLAB_TYPESAFE_BY_RCU allocations. Please read the basics in Documentation/RCU/listRCU.txt @@ -7,7 +7,7 @@ Using special makers (called 'nulls') is a convenient way to solve following problem : A typical RCU linked list managing objects which are -allocated with SLAB_DESTROY_BY_RCU kmem_cache can +allocated with SLAB_TYPESAFE_BY_RCU kmem_cache can use following algos : 1) Lookup algo @@ -96,7 +96,7 @@ unlock_chain(); // typically a spin_unlock() 3) Remove algo -------------- Nothing special here, we can use a standard RCU hlist deletion. -But thanks to SLAB_DESTROY_BY_RCU, beware a deleted object can be reused +But thanks to SLAB_TYPESAFE_BY_RCU, beware a deleted object can be reused very very fast (before the end of RCU grace period) if (put_last_reference_on(obj) { diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index e93d04133fe7..96a3d81837e1 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -1,9 +1,102 @@ Using RCU's CPU Stall Detector -The rcu_cpu_stall_suppress module parameter enables RCU's CPU stall -detector, which detects conditions that unduly delay RCU grace periods. -This module parameter enables CPU stall detection by default, but -may be overridden via boot-time parameter or at runtime via sysfs. +This document first discusses what sorts of issues RCU's CPU stall +detector can locate, and then discusses kernel parameters and Kconfig +options that can be used to fine-tune the detector's operation. Finally, +this document explains the stall detector's "splat" format. + + +What Causes RCU CPU Stall Warnings? + +So your kernel printed an RCU CPU stall warning. The next question is +"What caused it?" The following problems can result in RCU CPU stall +warnings: + +o A CPU looping in an RCU read-side critical section. + +o A CPU looping with interrupts disabled. + +o A CPU looping with preemption disabled. This condition can + result in RCU-sched stalls and, if ksoftirqd is in use, RCU-bh + stalls. + +o A CPU looping with bottom halves disabled. This condition can + result in RCU-sched and RCU-bh stalls. + +o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the + kernel without invoking schedule(). Note that cond_resched() + does not necessarily prevent RCU CPU stall warnings. Therefore, + if the looping in the kernel is really expected and desirable + behavior, you might need to replace some of the cond_resched() + calls with calls to cond_resched_rcu_qs(). + +o Booting Linux using a console connection that is too slow to + keep up with the boot-time console-message rate. For example, + a 115Kbaud serial console can be -way- too slow to keep up + with boot-time message rates, and will frequently result in + RCU CPU stall warning messages. Especially if you have added + debug printk()s. + +o Anything that prevents RCU's grace-period kthreads from running. + This can result in the "All QSes seen" console-log message. + This message will include information on when the kthread last + ran and how often it should be expected to run. + +o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might + happen to preempt a low-priority task in the middle of an RCU + read-side critical section. This is especially damaging if + that low-priority task is not permitted to run on any other CPU, + in which case the next RCU grace period can never complete, which + will eventually cause the system to run out of memory and hang. + While the system is in the process of running itself out of + memory, you might see stall-warning messages. + +o A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that + is running at a higher priority than the RCU softirq threads. + This will prevent RCU callbacks from ever being invoked, + and in a CONFIG_PREEMPT_RCU kernel will further prevent + RCU grace periods from ever completing. Either way, the + system will eventually run out of memory and hang. In the + CONFIG_PREEMPT_RCU case, you might see stall-warning + messages. + +o A hardware or software issue shuts off the scheduler-clock + interrupt on a CPU that is not in dyntick-idle mode. This + problem really has happened, and seems to be most likely to + result in RCU CPU stall warnings for CONFIG_NO_HZ_COMMON=n kernels. + +o A bug in the RCU implementation. + +o A hardware failure. This is quite unlikely, but has occurred + at least once in real life. A CPU failed in a running system, + becoming unresponsive, but not causing an immediate crash. + This resulted in a series of RCU CPU stall warnings, eventually + leading the realization that the CPU had failed. + +The RCU, RCU-sched, RCU-bh, and RCU-tasks implementations have CPU stall +warning. Note that SRCU does -not- have CPU stall warnings. Please note +that RCU only detects CPU stalls when there is a grace period in progress. +No grace period, no CPU stall warnings. + +To diagnose the cause of the stall, inspect the stack traces. +The offending function will usually be near the top of the stack. +If you have a series of stall warnings from a single extended stall, +comparing the stack traces can often help determine where the stall +is occurring, which will usually be in the function nearest the top of +that portion of the stack which remains the same from trace to trace. +If you can reliably trigger the stall, ftrace can be quite helpful. + +RCU bugs can often be debugged with the help of CONFIG_RCU_TRACE +and with RCU's event tracing. For information on RCU's event tracing, +see include/trace/events/rcu.h. + + +Fine-Tuning the RCU CPU Stall Detector + +The rcuupdate.rcu_cpu_stall_suppress module parameter disables RCU's +CPU stall detector, which detects conditions that unduly delay RCU grace +periods. This module parameter enables CPU stall detection by default, +but may be overridden via boot-time parameter or at runtime via sysfs. The stall detector's idea of what constitutes "unduly delayed" is controlled by a set of kernel configuration variables and cpp macros: @@ -56,6 +149,9 @@ rcupdate.rcu_task_stall_timeout And continues with the output of sched_show_task() for each task stalling the current RCU-tasks grace period. + +Interpreting RCU's CPU Stall-Detector "Splats" + For non-RCU-tasks flavors of RCU, when a CPU detects that it is stalling, it will print a message similar to the following: @@ -178,89 +274,3 @@ grace period is in flight. It is entirely possible to see stall warnings from normal and from expedited grace periods at about the same time from the same run. - - -What Causes RCU CPU Stall Warnings? - -So your kernel printed an RCU CPU stall warning. The next question is -"What caused it?" The following problems can result in RCU CPU stall -warnings: - -o A CPU looping in an RCU read-side critical section. - -o A CPU looping with interrupts disabled. This condition can - result in RCU-sched and RCU-bh stalls. - -o A CPU looping with preemption disabled. This condition can - result in RCU-sched stalls and, if ksoftirqd is in use, RCU-bh - stalls. - -o A CPU looping with bottom halves disabled. This condition can - result in RCU-sched and RCU-bh stalls. - -o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the - kernel without invoking schedule(). Note that cond_resched() - does not necessarily prevent RCU CPU stall warnings. Therefore, - if the looping in the kernel is really expected and desirable - behavior, you might need to replace some of the cond_resched() - calls with calls to cond_resched_rcu_qs(). - -o Booting Linux using a console connection that is too slow to - keep up with the boot-time console-message rate. For example, - a 115Kbaud serial console can be -way- too slow to keep up - with boot-time message rates, and will frequently result in - RCU CPU stall warning messages. Especially if you have added - debug printk()s. - -o Anything that prevents RCU's grace-period kthreads from running. - This can result in the "All QSes seen" console-log message. - This message will include information on when the kthread last - ran and how often it should be expected to run. - -o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might - happen to preempt a low-priority task in the middle of an RCU - read-side critical section. This is especially damaging if - that low-priority task is not permitted to run on any other CPU, - in which case the next RCU grace period can never complete, which - will eventually cause the system to run out of memory and hang. - While the system is in the process of running itself out of - memory, you might see stall-warning messages. - -o A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that - is running at a higher priority than the RCU softirq threads. - This will prevent RCU callbacks from ever being invoked, - and in a CONFIG_PREEMPT_RCU kernel will further prevent - RCU grace periods from ever completing. Either way, the - system will eventually run out of memory and hang. In the - CONFIG_PREEMPT_RCU case, you might see stall-warning - messages. - -o A hardware or software issue shuts off the scheduler-clock - interrupt on a CPU that is not in dyntick-idle mode. This - problem really has happened, and seems to be most likely to - result in RCU CPU stall warnings for CONFIG_NO_HZ_COMMON=n kernels. - -o A bug in the RCU implementation. - -o A hardware failure. This is quite unlikely, but has occurred - at least once in real life. A CPU failed in a running system, - becoming unresponsive, but not causing an immediate crash. - This resulted in a series of RCU CPU stall warnings, eventually - leading the realization that the CPU had failed. - -The RCU, RCU-sched, RCU-bh, and RCU-tasks implementations have CPU stall -warning. Note that SRCU does -not- have CPU stall warnings. Please note -that RCU only detects CPU stalls when there is a grace period in progress. -No grace period, no CPU stall warnings. - -To diagnose the cause of the stall, inspect the stack traces. -The offending function will usually be near the top of the stack. -If you have a series of stall warnings from a single extended stall, -comparing the stack traces can often help determine where the stall -is occurring, which will usually be in the function nearest the top of -that portion of the stack which remains the same from trace to trace. -If you can reliably trigger the stall, ftrace can be quite helpful. - -RCU bugs can often be debugged with the help of CONFIG_RCU_TRACE -and with RCU's event tracing. For information on RCU's event tracing, -see include/trace/events/rcu.h. diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 5cbd8b2395b8..8ed6c9f6133c 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -562,7 +562,9 @@ This section presents a "toy" RCU implementation that is based on familiar locking primitives. Its overhead makes it a non-starter for real-life use, as does its lack of scalability. It is also unsuitable for realtime use, since it allows scheduling latency to "bleed" from -one read-side critical section to another. +one read-side critical section to another. It also assumes recursive +reader-writer locks: If you try this with non-recursive locks, and +you allow nested rcu_read_lock() calls, you can deadlock. However, it is probably the easiest implementation to relate to, so is a good starting point. @@ -587,20 +589,21 @@ It is extremely simple: write_unlock(&rcu_gp_mutex); } -[You can ignore rcu_assign_pointer() and rcu_dereference() without -missing much. But here they are anyway. And whatever you do, don't -forget about them when submitting patches making use of RCU!] +[You can ignore rcu_assign_pointer() and rcu_dereference() without missing +much. But here are simplified versions anyway. And whatever you do, +don't forget about them when submitting patches making use of RCU!] - #define rcu_assign_pointer(p, v) ({ \ - smp_wmb(); \ - (p) = (v); \ - }) + #define rcu_assign_pointer(p, v) \ + ({ \ + smp_store_release(&(p), (v)); \ + }) - #define rcu_dereference(p) ({ \ - typeof(p) _________p1 = p; \ - smp_read_barrier_depends(); \ - (_________p1); \ - }) + #define rcu_dereference(p) \ + ({ \ + typeof(p) _________p1 = p; \ + smp_read_barrier_depends(); \ + (_________p1); \ + }) The rcu_read_lock() and rcu_read_unlock() primitive read-acquire @@ -925,7 +928,8 @@ d. Do you need RCU grace periods to complete even in the face e. Is your workload too update-intensive for normal use of RCU, but inappropriate for other synchronization mechanisms? - If so, consider SLAB_DESTROY_BY_RCU. But please be careful! + If so, consider SLAB_TYPESAFE_BY_RCU (which was originally + named SLAB_DESTROY_BY_RCU). But please be careful! f. Do you need read-side critical sections that are respected even though they are in the middle of the idle loop, during diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index e4c9e0e46b95..4e0654b56aef 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1578,6 +1578,15 @@ extended tables themselves, and also PASID support. With this option set, extended tables will not be used even on hardware which claims to support them. + tboot_noforce [Default Off] + Do not force the Intel IOMMU enabled under tboot. + By default, tboot will force Intel IOMMU on, which + could harm performance of some high-throughput + devices like 40GBit network cards, even if identity + mapping is enabled. + Note that using this option lowers the security + provided by tboot because it makes the system + vulnerable to DMA attacks. intel_idle.max_cstate= [KNL,HW,ACPI,X86] 0 disables intel_idle and fall back on acpi_idle. @@ -1644,6 +1653,12 @@ nobypass [PPC/POWERNV] Disable IOMMU bypass, using IOMMU for PCI devices. + iommu.passthrough= + [ARM64] Configure DMA to bypass the IOMMU by default. + Format: { "0" | "1" } + 0 - Use IOMMU translation for DMA. + 1 - Bypass the IOMMU for DMA. + unset - Use IOMMU translation for DMA. io7= [HW] IO7 for Marvel based alpha systems See comment before marvel_specify_io7 in @@ -3785,6 +3800,14 @@ spia_pedr= spia_peddr= + srcutree.exp_holdoff [KNL] + Specifies how many nanoseconds must elapse + since the end of the last SRCU grace period for + a given srcu_struct until the next normal SRCU + grace period will be considered for automatic + expediting. Set to zero to disable automatic + expediting. + stacktrace [FTRACE] Enabled the stack tracer on boot up. diff --git a/Documentation/arm/stm32/stm32h743-overview.txt b/Documentation/arm/stm32/stm32h743-overview.txt new file mode 100644 index 000000000000..3031cbae31a5 --- /dev/null +++ b/Documentation/arm/stm32/stm32h743-overview.txt @@ -0,0 +1,30 @@ + STM32H743 Overview + ================== + + Introduction + ------------ + The STM32H743 is a Cortex-M7 MCU aimed at various applications. + It features: + - Cortex-M7 core running up to @400MHz + - 2MB internal flash, 1MBytes internal RAM + - FMC controller to connect SDRAM, NOR and NAND memories + - Dual mode QSPI + - SD/MMC/SDIO support + - Ethernet controller + - USB OTFG FS & HS controllers + - I2C, SPI, CAN busses support + - Several 16 & 32 bits general purpose timers + - Serial Audio interface + - LCD controller + - HDMI-CEC + - SPDIFRX + - DFSDM + + Resources + --------- + Datasheet and reference manual are publicly available on ST website: + - http://www.st.com/en/microcontrollers/stm32h7x3.html?querycriteria=productId=LN2033 + + Document Author + --------------- + Alexandre Torgue <alexandre.torgue@st.com> diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt index c246cd2730d9..bfd5b558477d 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.txt +++ b/Documentation/devicetree/bindings/arm/amlogic.txt @@ -43,8 +43,11 @@ Board compatible values: - "wetek,hub" (Meson gxbb) - "wetek,play2" (Meson gxbb) - "amlogic,p212" (Meson gxl s905x) + - "khadas,vim" (Meson gxl s905x) + - "amlogic,p230" (Meson gxl s905d) - "amlogic,p231" (Meson gxl s905d) + - "hwacom,amazetv" (Meson gxl s905x) - "amlogic,q200" (Meson gxm s912) - "amlogic,q201" (Meson gxm s912) - "nexbox,a95x" (Meson gxbb or Meson gxl s905x) diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 29737b9b616e..799af90dd75b 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -217,7 +217,8 @@ memory, bridge implementations, processor and other functionality not controlled elsewhere. required properties: -- compatible: Should be "atmel,<chip>-sfr", "syscon". +- compatible: Should be "atmel,<chip>-sfr", "syscon" or + "atmel,<chip>-sfrbu", "syscon" <chip> can be "sama5d3", "sama5d4" or "sama5d2". - reg: Should contain registers location and length diff --git a/Documentation/devicetree/bindings/arm/cavium-thunder2.txt b/Documentation/devicetree/bindings/arm/cavium-thunder2.txt new file mode 100644 index 000000000000..dc5dd65cbce7 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/cavium-thunder2.txt @@ -0,0 +1,8 @@ +Cavium ThunderX2 CN99XX platform tree bindings +---------------------------------------------- + +Boards with Cavium ThunderX2 CN99XX SoC shall have the root property: + compatible = "cavium,thunderx2-cn9900", "brcm,vulcan-soc"; + +These SoC uses the "cavium,thunder2" core which will be compatible +with "brcm,vulcan". diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index 698ad1f097fa..1030f5f50207 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -170,6 +170,7 @@ nodes to be present and contain the properties described below. "brcm,brahma-b15" "brcm,vulcan" "cavium,thunder" + "cavium,thunder2" "faraday,fa526" "intel,sa110" "intel,sa1100" diff --git a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt new file mode 100644 index 000000000000..d38834c67dff --- /dev/null +++ b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt @@ -0,0 +1,31 @@ +OP-TEE Device Tree Bindings + +OP-TEE is a piece of software using hardware features to provide a Trusted +Execution Environment. The security can be provided with ARM TrustZone, but +also by virtualization or a separate chip. + +We're using "linaro" as the first part of the compatible property for +the reference implementation maintained by Linaro. + +* OP-TEE based on ARM TrustZone required properties: + +- compatible : should contain "linaro,optee-tz" + +- method : The method of calling the OP-TEE Trusted OS. Permitted + values are: + + "smc" : SMC #0, with the register assignments specified + in drivers/tee/optee/optee_smc.h + + "hvc" : HVC #0, with the register assignments specified + in drivers/tee/optee/optee_smc.h + + + +Example: + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index c9c567ae227f..cdb9dd705754 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -179,6 +179,18 @@ LS1046A ARMv8 based RDB Board Required root node properties: - compatible = "fsl,ls1046a-rdb", "fsl,ls1046a"; +LS1088A SoC +Required root node properties: + - compatible = "fsl,ls1088a"; + +LS1088A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls1088a-qds", "fsl,ls1088a"; + +LS1088A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls1088a-rdb", "fsl,ls1088a"; + LS2080A SoC Required root node properties: - compatible = "fsl,ls2080a"; @@ -195,3 +207,14 @@ LS2080A ARMv8 based RDB Board Required root node properties: - compatible = "fsl,ls2080a-rdb", "fsl,ls2080a"; +LS2088A SoC +Required root node properties: + - compatible = "fsl,ls2088a"; + +LS2088A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls2088a-qds", "fsl,ls2088a"; + +LS2088A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls2088a-rdb", "fsl,ls2088a"; diff --git a/Documentation/devicetree/bindings/arm/gemini.txt b/Documentation/devicetree/bindings/arm/gemini.txt new file mode 100644 index 000000000000..0041eb031116 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/gemini.txt @@ -0,0 +1,86 @@ +Cortina systems Gemini platforms + +The Gemini SoC is the project name for an ARMv4 FA525-based SoC originally +produced by Storlink Semiconductor around 2005. The company was renamed +later renamed Storm Semiconductor. The chip product name is Storlink SL3516. +It was derived from earlier products from Storm named SL3316 (Centroid) and +SL3512 (Bulverde). + +Storm Semiconductor was acquired by Cortina Systems in 2008 and the SoC was +produced and used for NAS and similar usecases. In 2014 Cortina Systems was +in turn acquired by Inphi, who seem to have discontinued this product family. + +Many of the IP blocks used in the SoC comes from Faraday Technology. + +Required properties (in root node): + compatible = "cortina,gemini"; + +Required nodes: + +- soc: the SoC should be represented by a simple bus encompassing all the + onchip devices, this is referred to as the soc bus node. + +- syscon: the soc bus node must have a system controller node pointing to the + global control registers, with the compatible string + "cortina,gemini-syscon", "syscon"; + +- timer: the soc bus node must have a timer node pointing to the SoC timer + block, with the compatible string "cortina,gemini-timer" + See: clocksource/cortina,gemini-timer.txt + +- interrupt-controller: the sob bus node must have an interrupt controller + node pointing to the SoC interrupt controller block, with the compatible + string "cortina,gemini-interrupt-controller" + See interrupt-controller/cortina,gemini-interrupt-controller.txt + +Example: + +/ { + model = "Foo Gemini Machine"; + compatible = "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "simple-bus"; + interrupt-parent = <&intcon>; + + syscon: syscon@40000000 { + compatible = "cortina,gemini-syscon", "syscon"; + reg = <0x40000000 0x1000>; + }; + + uart0: serial@42000000 { + compatible = "ns16550a"; + reg = <0x42000000 0x100>; + clock-frequency = <48000000>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + }; + + timer@43000000 { + compatible = "cortina,gemini-timer"; + reg = <0x43000000 0x1000>; + interrupt-parent = <&intcon>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>, /* Timer 1 */ + <15 IRQ_TYPE_EDGE_FALLING>, /* Timer 2 */ + <16 IRQ_TYPE_EDGE_FALLING>; /* Timer 3 */ + syscon = <&syscon>; + }; + + intcon: interrupt-controller@48000000 { + compatible = "cortina,gemini-interrupt-controller"; + reg = <0x48000000 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt index f1c1e21a8110..2e732152064b 100644 --- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt @@ -4,6 +4,14 @@ Hi3660 SoC Required root node properties: - compatible = "hisilicon,hi3660"; +Hi3798cv200 SoC +Required root node properties: + - compatible = "hisilicon,hi3798cv200"; + +Hi3798cv200 Poplar Board +Required root node properties: + - compatible = "hisilicon,hi3798cv200-poplar", "hisilicon,hi3798cv200"; + Hi4511 Board Required root node properties: - compatible = "hisilicon,hi3620-hi4511"; diff --git a/Documentation/devicetree/bindings/arm/i2se.txt b/Documentation/devicetree/bindings/arm/i2se.txt new file mode 100644 index 000000000000..dbd54a3aa07d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/i2se.txt @@ -0,0 +1,22 @@ +I2SE Device Tree Bindings +------------------------- + +Duckbill Board +Required root node properties: + - compatible = "i2se,duckbill", "fsl,imx28"; + +Duckbill 2 Board +Required root node properties: + - compatible = "i2se,duckbill-2", "fsl,imx28"; + +Duckbill 2 485 Board +Required root node properties: + - compatible = "i2se,duckbill-2-485", "i2se,duckbill-2", "fsl,imx28"; + +Duckbill 2 EnOcean Board +Required root node properties: + - compatible = "i2se,duckbill-2-enocean", "i2se,duckbill-2", "fsl,imx28"; + +Duckbill 2 SPI Board +Required root node properties: + - compatible = "i2se,duckbill-2-spi", "i2se,duckbill-2", "fsl,imx28"; diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt index cc4ace6397ab..c965d99e86c2 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.txt +++ b/Documentation/devicetree/bindings/arm/rockchip.txt @@ -1,5 +1,8 @@ Rockchip platforms device tree bindings --------------------------------------- +- Asus Tinker board + Required root node properties: + - compatible = "asus,rk3288-tinker", "rockchip,rk3288"; - Kylin RK3036 board: Required root node properties: @@ -56,6 +59,17 @@ Rockchip platforms device tree bindings - compatible = "google,veyron-brain-rev0", "google,veyron-brain", "google,veyron", "rockchip,rk3288"; +- Google Gru (dev-board): + Required root node properties: + - compatible = "google,gru-rev15", "google,gru-rev14", + "google,gru-rev13", "google,gru-rev12", + "google,gru-rev11", "google,gru-rev10", + "google,gru-rev9", "google,gru-rev8", + "google,gru-rev7", "google,gru-rev6", + "google,gru-rev5", "google,gru-rev4", + "google,gru-rev3", "google,gru-rev2", + "google,gru", "rockchip,rk3399"; + - Google Jaq (Haier Chromebook 11 and more): Required root node properties: - compatible = "google,veyron-jaq-rev5", "google,veyron-jaq-rev4", @@ -70,6 +84,15 @@ Rockchip platforms device tree bindings "google,veyron-jerry-rev3", "google,veyron-jerry", "google,veyron", "rockchip,rk3288"; +- Google Kevin (Samsung Chromebook Plus): + Required root node properties: + - compatible = "google,kevin-rev15", "google,kevin-rev14", + "google,kevin-rev13", "google,kevin-rev12", + "google,kevin-rev11", "google,kevin-rev10", + "google,kevin-rev9", "google,kevin-rev8", + "google,kevin-rev7", "google,kevin-rev6", + "google,kevin", "google,gru", "rockchip,rk3399"; + - Google Mickey (Asus Chromebit CS10): Required root node properties: - compatible = "google,veyron-mickey-rev8", "google,veyron-mickey-rev7", @@ -103,6 +126,10 @@ Rockchip platforms device tree bindings Required root node properties: - compatible = "mqmaker,miqi", "rockchip,rk3288"; +- Phytec phyCORE-RK3288: Rapid Development Kit + Required root node properties: + - compatible = "phytec,rk3288-pcm-947", "phytec,rk3288-phycore-som", "rockchip,rk3288"; + - Rockchip PX3 Evaluation board: Required root node properties: - compatible = "rockchip,px3-evb", "rockchip,px3", "rockchip,rk3188"; @@ -134,6 +161,10 @@ Rockchip platforms device tree bindings Required root node properties: - compatible = "rockchip,rk3288-fennec", "rockchip,rk3288"; +- Rockchip RK3328 evb: + Required root node properties: + - compatible = "rockchip,rk3328-evb", "rockchip,rk3328"; + - Rockchip RK3399 evb: Required root node properties: - compatible = "rockchip,rk3399-evb", "rockchip,rk3399"; diff --git a/Documentation/devicetree/bindings/arm/shmobile.txt b/Documentation/devicetree/bindings/arm/shmobile.txt index c9502634316d..170fe0562c63 100644 --- a/Documentation/devicetree/bindings/arm/shmobile.txt +++ b/Documentation/devicetree/bindings/arm/shmobile.txt @@ -13,8 +13,12 @@ SoCs: compatible = "renesas,r8a73a4" - R-Mobile A1 (R8A77400) compatible = "renesas,r8a7740" + - RZ/G1H (R8A77420) + compatible = "renesas,r8a7742" - RZ/G1M (R8A77430) compatible = "renesas,r8a7743" + - RZ/G1N (R8A77440) + compatible = "renesas,r8a7744" - RZ/G1E (R8A77450) compatible = "renesas,r8a7745" - R-Car M1A (R8A77781) diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt new file mode 100644 index 000000000000..078a58b0302f --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt @@ -0,0 +1,34 @@ +NVIDIA Tegra Power Management Controller (PMC) + +Required properties: +- compatible: Should contain one of the following: + - "nvidia,tegra186-pmc": for Tegra186 +- reg: Must contain an (offset, length) pair of the register set for each + entry in reg-names. +- reg-names: Must include the following entries: + - "pmc" + - "wake" + - "aotag" + - "scratch" + +Optional properties: +- nvidia,invert-interrupt: If present, inverts the PMU interrupt signal. + +Example: + +SoC DTSI: + + pmc@c3600000 { + compatible = "nvidia,tegra186-pmc"; + reg = <0 0x0c360000 0 0x10000>, + <0 0x0c370000 0 0x10000>, + <0 0x0c380000 0 0x10000>, + <0 0x0c390000 0 0x10000>; + reg-names = "pmc", "wake", "aotag", "scratch"; + }; + +Board DTS: + + pmc@c360000 { + nvidia,invert-interrupt; + }; diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-flowctrl.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-flowctrl.txt index ccf0adddc820..a855c1bffc0f 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-flowctrl.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-flowctrl.txt @@ -1,7 +1,13 @@ NVIDIA Tegra Flow Controller Required properties: -- compatible: Should be "nvidia,tegra<chip>-flowctrl" +- compatible: Should contain one of the following: + - "nvidia,tegra20-flowctrl": for Tegra20 + - "nvidia,tegra30-flowctrl": for Tegra30 + - "nvidia,tegra114-flowctrl": for Tegra114 + - "nvidia,tegra124-flowctrl": for Tegra124 + - "nvidia,tegra132-flowctrl", "nvidia,tegra124-flowctrl": for Tegra132 + - "nvidia,tegra210-flowctrl": for Tegra210 - reg: Should contain one register range (address and length) Example: diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt index ce06435d28ed..a09d627b5508 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt @@ -5,7 +5,8 @@ controllers within the SoC. Required Properties: -- compatible: should be "amlogic,gxbb-clkc" +- compatible: should be "amlogic,gxbb-clkc" for GXBB SoC, + or "amlogic,gxl-clkc" for GXL and GXM SoC. - reg: physical base address of the clock controller and length of memory mapped region. diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt index eb985a633d59..796c260c183d 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt @@ -31,6 +31,12 @@ The following is a list of provided IDs and clock names on Armada 39x: 4 = dclk (SDRAM Interface Clock) 5 = refclk (Reference Clock) +The following is a list of provided IDs and clock names on 98dx3236: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU clock) + 2 = ddrclk (DDR clock) + 3 = mpll (MPLL Clock) + The following is a list of provided IDs and clock names on Kirkwood and Dove: 0 = tclk (Internal Bus clock) 1 = cpuclk (CPU0 clock) @@ -49,6 +55,7 @@ Required properties: "marvell,armada-380-core-clock" - For Armada 380/385 SoC core clocks "marvell,armada-390-core-clock" - For Armada 39x SoC core clocks "marvell,armada-xp-core-clock" - For Armada XP SoC core clocks + "marvell,mv98dx3236-core-clock" - For 98dx3236 family SoC core clocks "marvell,dove-core-clock" - for Dove SoC core clocks "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180) "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC diff --git a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt index 5142efc8099d..de562da2ae77 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt @@ -119,6 +119,16 @@ ID Clock Peripheral 29 sata1lnk 30 sata1 SATA Host 1 +The following is a list of provided IDs for 98dx3236: +ID Clock Peripheral +----------------------------------- +3 ge1 Gigabit Ethernet 1 +4 ge0 Gigabit Ethernet 0 +5 pex0 PCIe Cntrl 0 +17 sdio SDHCI Host +18 usb0 USB Host 0 +22 xor0 XOR DMA 0 + The following is a list of provided IDs for Dove: ID Clock Peripheral ----------------------------------- @@ -169,6 +179,7 @@ Required properties: "marvell,armada-380-gating-clock" - for Armada 380/385 SoC clock gating "marvell,armada-390-gating-clock" - for Armada 39x SoC clock gating "marvell,armada-xp-gating-clock" - for Armada XP SoC clock gating + "marvell,mv98dx3236-gating-clock" - for 98dx3236 SoC clock gating "marvell,dove-gating-clock" - for Dove SoC clock gating "marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating - reg : shall be the register address of the Clock Gating Control register diff --git a/Documentation/devicetree/bindings/clock/qoriq-clock.txt b/Documentation/devicetree/bindings/clock/qoriq-clock.txt index aa3526f229a7..6ed469c66b32 100644 --- a/Documentation/devicetree/bindings/clock/qoriq-clock.txt +++ b/Documentation/devicetree/bindings/clock/qoriq-clock.txt @@ -35,6 +35,7 @@ Required properties: * "fsl,ls1021a-clockgen" * "fsl,ls1043a-clockgen" * "fsl,ls1046a-clockgen" + * "fsl,ls1088a-clockgen" * "fsl,ls2080a-clockgen" Chassis-version clock strings include: * "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks diff --git a/Documentation/devicetree/bindings/devfreq/exynos-bus.txt b/Documentation/devicetree/bindings/devfreq/exynos-bus.txt index d085ef90d27c..f8e946471a58 100644 --- a/Documentation/devicetree/bindings/devfreq/exynos-bus.txt +++ b/Documentation/devicetree/bindings/devfreq/exynos-bus.txt @@ -202,23 +202,23 @@ Example2 : compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; opp-microvolt = <800000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <800000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <800000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <825000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <875000>; }; @@ -292,23 +292,23 @@ Example2 : compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; opp-microvolt = <900000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; opp-microvolt = <900000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <1000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <1000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <1000000>; }; @@ -318,19 +318,19 @@ Example2 : compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; }; }; @@ -339,19 +339,19 @@ Example2 : compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; }; }; @@ -360,13 +360,13 @@ Example2 : compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; }; diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index b82c00449468..57a8d0610062 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -94,6 +94,7 @@ Required properties: * allwinner,sun6i-a31-display-backend * allwinner,sun8i-a33-display-backend - reg: base address and size of the memory-mapped region. + - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the frontend and backend * ahb: the backend interface clock * mod: the backend module clock @@ -265,6 +266,7 @@ fe0: display-frontend@1e00000 { be0: display-backend@1e60000 { compatible = "allwinner,sun5i-a13-display-backend"; reg = <0x01e60000 0x10000>; + interrupts = <47>; clocks = <&ahb_gates 44>, <&de_be_clk>, <&dram_gates 26>; clock-names = "ahb", "mod", diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt index 476f5ea6c627..2b6243e730f6 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt +++ b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt @@ -35,6 +35,14 @@ Optional properties: - interrupt-names and interrupts: * pmu: Power Management Unit interrupt, if implemented in hardware + - memory-region: + Memory region to allocate from, as defined in + Documentation/devicetree/bindi/reserved-memory/reserved-memory.txt + + - operating-points-v2: + Operating Points for the GPU, as defined in + Documentation/devicetree/bindings/opp/opp.txt + Vendor-specific bindings ------------------------ diff --git a/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt b/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt index ff3db65e50de..b7e4c7444510 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt @@ -5,6 +5,7 @@ Required properties: Currently recognized values: - nvidia,gk20a - nvidia,gm20b + - nvidia,gp10b - reg: Physical base address and length of the controller's registers. Must contain two entries: - first entry for bar0 @@ -14,7 +15,8 @@ Required properties: - interrupt-names: Must include the following entries: - stall - nonstall -- vdd-supply: regulator for supply voltage. +- vdd-supply: regulator for supply voltage. Only required for GPUs not using + power domains. - clocks: Must contain an entry for each entry in clock-names. See ../clocks/clock-bindings.txt for details. - clock-names: Must include the following entries: @@ -27,6 +29,8 @@ is also required: See ../reset/reset.txt for details. - reset-names: Must include the following entries: - gpu +- power-domains: GPUs that make use of power domains can define this property + instead of vdd-supply. Currently "nvidia,gp10b" makes use of this. Optional properties: - iommus: A reference to the IOMMU. See ../iommu/iommu.txt for details. @@ -68,3 +72,22 @@ Example for GM20B: iommus = <&mc TEGRA_SWGROUP_GPU>; status = "disabled"; }; + +Example for GP10B: + + gpu@17000000 { + compatible = "nvidia,gp10b"; + reg = <0x0 0x17000000 0x0 0x1000000>, + <0x0 0x18000000 0x0 0x1000000>; + interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH + GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "stall", "nonstall"; + clocks = <&bpmp TEGRA186_CLK_GPCCLK>, + <&bpmp TEGRA186_CLK_GPU>; + clock-names = "gpu", "pwr"; + resets = <&bpmp TEGRA186_RESET_GPU>; + reset-names = "gpu"; + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_GPU>; + iommus = <&smmu TEGRA186_SID_GPU>; + status = "disabled"; + }; diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 6cdf32d037fc..8a6ffce12af5 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -60,6 +60,17 @@ conditions. aliases of secure registers have to be used during SMMU configuration. +- stream-match-mask : For SMMUs supporting stream matching and using + #iommu-cells = <1>, specifies a mask of bits to ignore + when matching stream IDs (e.g. this may be programmed + into the SMRn.MASK field of every stream match register + used). For cases where it is desirable to ignore some + portion of every Stream ID (e.g. for certain MMU-500 + configurations given globally unique input IDs). This + property is not valid for SMMUs using stream indexing, + or using stream matching with #iommu-cells = <2>, and + may be ignored if present in such cases. + ** Deprecated properties: - mmu-masters (deprecated in favour of the generic "iommus" binding) : @@ -109,3 +120,20 @@ conditions. master3 { iommus = <&smmu2 1 0x30>; }; + + + /* ARM MMU-500 with 10-bit stream ID input configuration */ + smmu3: iommu { + compatible = "arm,mmu-500", "arm,smmu-v2"; + ... + #iommu-cells = <1>; + /* always ignore appended 5-bit TBU number */ + stream-match-mask = 0x7c00; + }; + + bus { + /* bus whose child devices emit one unique 10-bit stream + ID each, but may master through multiple SMMU TBUs */ + iommu-map = <0 &smmu3 0 0x400>; + ... + }; diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt index 3e920ec5c4d3..9ce35af8507c 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt @@ -40,6 +40,7 @@ Required properties: w25x80 w25x32 w25q32 + w25q64 w25q32dw w25q80bl w25q128 diff --git a/Documentation/devicetree/bindings/net/marvell,prestera.txt b/Documentation/devicetree/bindings/net/marvell,prestera.txt index 5fbab29718e8..c329608fa887 100644 --- a/Documentation/devicetree/bindings/net/marvell,prestera.txt +++ b/Documentation/devicetree/bindings/net/marvell,prestera.txt @@ -32,19 +32,16 @@ DFX Server bindings ------------------- Required properties: -- compatible: must be "marvell,dfx-server" +- compatible: must be "marvell,dfx-server", "simple-bus" +- ranges: describes the address mapping of a memory-mapped bus. - reg: address and length of the register set for the device. Example: -dfx-registers { - compatible = "simple-bus"; +dfx-server { + compatible = "marvell,dfx-server", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; - - dfx: dfx@0 { - compatible = "marvell,dfx-server"; - reg = <0 0x100000>; - }; + reg = <MBUS_ID(0x08, 0x00) 0 0x100000>; }; diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt index 65cc0345747d..6c1498958d48 100644 --- a/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt @@ -1,22 +1,42 @@ Freescale i.MX General Power Controller ======================================= -The i.MX6Q General Power Control (GPC) block contains DVFS load tracking -counters and Power Gating Control (PGC) for the CPU and PU (GPU/VPU) power -domains. +The i.MX6 General Power Control (GPC) block contains DVFS load tracking +counters and Power Gating Control (PGC). Required properties: -- compatible: Should be "fsl,imx6q-gpc" or "fsl,imx6sl-gpc" +- compatible: Should be one of the following: + - fsl,imx6q-gpc + - fsl,imx6qp-gpc + - fsl,imx6sl-gpc - reg: should be register base and length as documented in the datasheet -- interrupts: Should contain GPC interrupt request 1 -- pu-supply: Link to the LDO regulator powering the PU power domain -- clocks: Clock phandles to devices in the PU power domain that need - to be enabled during domain power-up for reset propagation. -- #power-domain-cells: Should be 1, see below: +- interrupts: Should contain one interrupt specifier for the GPC interrupt +- clocks: Must contain an entry for each entry in clock-names. + See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - ipg -The gpc node is a power-controller as documented by the generic power domain -bindings in Documentation/devicetree/bindings/power/power_domain.txt. +The power domains are generic power domain providers as documented in +Documentation/devicetree/bindings/power/power_domain.txt. They are described as +subnodes of the power gating controller 'pgc' node of the GPC and should +contain the following: + +Required properties: +- reg: Must contain the DOMAIN_INDEX of this power domain + The following DOMAIN_INDEX values are valid for i.MX6Q: + ARM_DOMAIN 0 + PU_DOMAIN 1 + The following additional DOMAIN_INDEX value is valid for i.MX6SL: + DISPLAY_DOMAIN 2 + +- #power-domain-cells: Should be 0 + +Optional properties: +- clocks: a number of phandles to clocks that need to be enabled during domain + power-up sequencing to ensure reset propagation into devices located inside + this power domain +- power-supply: a phandle to the regulator powering this domain Example: @@ -25,14 +45,30 @@ Example: reg = <0x020dc000 0x4000>; interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>, <0 90 IRQ_TYPE_LEVEL_HIGH>; - pu-supply = <®_pu>; - clocks = <&clks IMX6QDL_CLK_GPU3D_CORE>, - <&clks IMX6QDL_CLK_GPU3D_SHADER>, - <&clks IMX6QDL_CLK_GPU2D_CORE>, - <&clks IMX6QDL_CLK_GPU2D_AXI>, - <&clks IMX6QDL_CLK_OPENVG_AXI>, - <&clks IMX6QDL_CLK_VPU_AXI>; - #power-domain-cells = <1>; + clocks = <&clks IMX6QDL_CLK_IPG>; + clock-names = "ipg"; + + pgc { + #address-cells = <1>; + #size-cells = <0>; + + power-domain@0 { + reg = <0>; + #power-domain-cells = <0>; + }; + + pd_pu: power-domain@1 { + reg = <1>; + #power-domain-cells = <0>; + power-supply = <®_pu>; + clocks = <&clks IMX6QDL_CLK_GPU3D_CORE>, + <&clks IMX6QDL_CLK_GPU3D_SHADER>, + <&clks IMX6QDL_CLK_GPU2D_CORE>, + <&clks IMX6QDL_CLK_GPU2D_AXI>, + <&clks IMX6QDL_CLK_OPENVG_AXI>, + <&clks IMX6QDL_CLK_VPU_AXI>; + }; + }; }; @@ -40,20 +76,13 @@ Specifying power domain for IP modules ====================================== IP cores belonging to a power domain should contain a 'power-domains' property -that is a phandle pointing to the gpc device node and a DOMAIN_INDEX specifying -the power domain the device belongs to. +that is a phandle pointing to the power domain the device belongs to. Example of a device that is part of the PU power domain: vpu: vpu@02040000 { reg = <0x02040000 0x3c000>; /* ... */ - power-domains = <&gpc 1>; + power-domains = <&pd_pu>; /* ... */ }; - -The following DOMAIN_INDEX values are valid for i.MX6Q: -ARM_DOMAIN 0 -PU_DOMAIN 1 -The following additional DOMAIN_INDEX value is valid for i.MX6SL: -DISPLAY_DOMAIN 2 diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt new file mode 100644 index 000000000000..02f45c65fd87 --- /dev/null +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt @@ -0,0 +1,71 @@ +Freescale i.MX General Power Controller v2 +========================================== + +The i.MX7S/D General Power Control (GPC) block contains Power Gating +Control (PGC) for various power domains. + +Required properties: + +- compatible: Should be "fsl,imx7d-gpc" + +- reg: should be register base and length as documented in the + datasheet + +- interrupts: Should contain GPC interrupt request 1 + +Power domains contained within GPC node are generic power domain +providers, documented in +Documentation/devicetree/bindings/power/power_domain.txt, which are +described as subnodes of the power gating controller 'pgc' node, +which, in turn, is expected to contain the following: + +Required properties: + +- reg: Power domain index. Valid values are defined in + include/dt-bindings/power/imx7-power.h + +- #power-domain-cells: Should be 0 + +Optional properties: + +- power-supply: Power supply used to power the domain + +Example: + + gpc: gpc@303a0000 { + compatible = "fsl,imx7d-gpc"; + reg = <0x303a0000 0x1000>; + interrupt-controller; + interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + + pgc { + #address-cells = <1>; + #size-cells = <0>; + + pgc_pcie_phy: power-domain@3 { + #power-domain-cells = <0>; + + reg = <IMX7_POWER_DOMAIN_PCIE_PHY>; + power-supply = <®_1p0d>; + }; + }; + }; + + +Specifying power domain for IP modules +====================================== + +IP cores belonging to a power domain should contain a 'power-domains' +property that is a phandle for PGC node representing the domain. + +Example of a device that is part of the PCIE_PHY power domain: + + pcie: pcie@33800000 { + reg = <0x33800000 0x4000>, + <0x4ff00000 0x80000>; + /* ... */ + power-domains = <&pgc_pcie_phy>; + /* ... */ + }; diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 940707d095cc..14bd9e945ff6 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -81,7 +81,7 @@ Example 3: child: power-controller@12341000 { compatible = "foo,power-controller"; reg = <0x12341000 0x1000>; - power-domains = <&parent 0>; + power-domains = <&parent>; #power-domain-cells = <0>; domain-idle-states = <&DOMAIN_PWR_DN>; }; diff --git a/Documentation/devicetree/bindings/pwm/atmel-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt index 02331b904d4e..c8c831d7b0d1 100644 --- a/Documentation/devicetree/bindings/pwm/atmel-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt @@ -4,6 +4,7 @@ Required properties: - compatible: should be one of: - "atmel,at91sam9rl-pwm" - "atmel,sama5d3-pwm" + - "atmel,sama5d2-pwm" - reg: physical base address and length of the controller's registers - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of the cells format. diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt index b4e73778dda3..c57e11b8d937 100644 --- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt @@ -19,6 +19,19 @@ Required properties: - reset-names: Must include the following entries: - pwm +Optional properties: +============================ +In some of the interface like PWM based regulator device, it is required +to configure the pins differently in different states, especially in suspend +state of the system. The configuration of pin is provided via the pinctrl +DT node as detailed in the pinctrl DT binding document + Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +The PWM node will have following optional properties. +pinctrl-names: Pin state names. Must be "default" and "sleep". +pinctrl-0: phandle for the default/active state of pin configurations. +pinctrl-1: phandle for the sleep state of pin configurations. + Example: pwm: pwm@7000a000 { @@ -29,3 +42,35 @@ Example: resets = <&tegra_car 17>; reset-names = "pwm"; }; + + +Example with the pin configuration for suspend and resume: +========================================================= +Suppose pin PE7 (On Tegra210) interfaced with the regulator device and +it requires PWM output to be tristated when system enters suspend. +Following will be DT binding to achieve this: + +#include <dt-bindings/pinctrl/pinctrl-tegra.h> + + pinmux@700008d4 { + pwm_active_state: pwm_active_state { + pe7 { + nvidia,pins = "pe7"; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + }; + }; + + pwm_sleep_state: pwm_sleep_state { + pe7 { + nvidia,pins = "pe7"; + nvidia,tristate = <TEGRA_PIN_ENABLE>; + }; + }; + }; + + pwm@7000a000 { + /* Mandatory PWM properties */ + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pwm_active_state>; + pinctrl-1 = <&pwm_sleep_state>; + }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-mediatek.txt b/Documentation/devicetree/bindings/pwm/pwm-mediatek.txt new file mode 100644 index 000000000000..54c59b0560ad --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-mediatek.txt @@ -0,0 +1,34 @@ +MediaTek PWM controller + +Required properties: + - compatible: should be "mediatek,<name>-pwm": + - "mediatek,mt7623-pwm": found on mt7623 SoC. + - reg: physical base address and length of the controller's registers. + - #pwm-cells: must be 2. See pwm.txt in this directory for a description of + the cell format. + - clocks: phandle and clock specifier of the PWM reference clock. + - clock-names: must contain the following: + - "top": the top clock generator + - "main": clock used by the PWM core + - "pwm1-5": the five per PWM clocks + - pinctrl-names: Must contain a "default" entry. + - pinctrl-0: One property must exist for each entry in pinctrl-names. + See pinctrl/pinctrl-bindings.txt for details of the property values. + +Example: + pwm0: pwm@11006000 { + compatible = "mediatek,mt7623-pwm"; + reg = <0 0x11006000 0 0x1000>; + #pwm-cells = <2>; + clocks = <&topckgen CLK_TOP_PWM_SEL>, + <&pericfg CLK_PERI_PWM>, + <&pericfg CLK_PERI_PWM1>, + <&pericfg CLK_PERI_PWM2>, + <&pericfg CLK_PERI_PWM3>, + <&pericfg CLK_PERI_PWM4>, + <&pericfg CLK_PERI_PWM5>; + clock-names = "top", "main", "pwm1", "pwm2", + "pwm3", "pwm4", "pwm5"; + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pins>; + }; diff --git a/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt b/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt new file mode 100644 index 000000000000..5e1afc3d8480 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt @@ -0,0 +1,47 @@ +Freescale i.MX7 System Reset Controller +====================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "fsl,imx7-src", "syscon" +- reg: should be register base and length as documented in the + datasheet +- interrupts: Should contain SRC interrupt +- #reset-cells: 1, see below + +example: + +src: reset-controller@30390000 { + compatible = "fsl,imx7d-src", "syscon"; + reg = <0x30390000 0x2000>; + interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; + #reset-cells = <1>; +}; + + +Specifying reset lines connected to IP modules +============================================== + +The system reset controller can be used to reset various set of +peripherals. Device nodes that need access to reset lines should +specify them as a reset phandle in their corresponding node as +specified in reset.txt. + +Example: + + pcie: pcie@33800000 { + + ... + + resets = <&src IMX7_RESET_PCIEPHY>, + <&src IMX7_RESET_PCIE_CTRL_APPS_EN>; + reset-names = "pciephy", "apps"; + + ... + }; + + +For list of all valid reset indicies see +<dt-bindings/reset/imx7-reset.h> diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.txt b/Documentation/devicetree/bindings/soc/rockchip/grf.txt index 13ec0992de0f..cc9f05d3cbc1 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.txt +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.txt @@ -18,6 +18,7 @@ Required Properties: - "rockchip,rk3188-grf", "syscon": for rk3188 - "rockchip,rk3228-grf", "syscon": for rk3228 - "rockchip,rk3288-grf", "syscon": for rk3288 + - "rockchip,rk3328-grf", "syscon": for rk3328 - "rockchip,rk3368-grf", "syscon": for rk3368 - "rockchip,rk3399-grf", "syscon": for rk3399 - compatible: PMUGRF should be one of the following: diff --git a/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt new file mode 100644 index 000000000000..c705db07d820 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt @@ -0,0 +1,57 @@ +Texas Instruments TI-SCI Generic Power Domain +--------------------------------------------- + +Some TI SoCs contain a system controller (like the PMMC, etc...) that is +responsible for controlling the state of the IPs that are present. +Communication between the host processor running an OS and the system +controller happens through a protocol known as TI-SCI [1]. + +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt + +PM Domain Node +============== +The PM domain node represents the global PM domain managed by the PMMC, which +in this case is the implementation as documented by the generic PM domain +bindings in Documentation/devicetree/bindings/power/power_domain.txt. Because +this relies on the TI SCI protocol to communicate with the PMMC it must be a +child of the pmmc node. + +Required Properties: +-------------------- +- compatible: should be "ti,sci-pm-domain" +- #power-domain-cells: Must be 1 so that an id can be provided in each + device node. + +Example (K2G): +------------- + pmmc: pmmc { + compatible = "ti,k2g-sci"; + ... + + k2g_pds: power-controller { + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <1>; + }; + }; + +PM Domain Consumers +=================== +Hardware blocks belonging to a PM domain should contain a "power-domains" +property that is a phandle pointing to the corresponding PM domain node +along with an index representing the device id to be passed to the PMMC +for device control. + +Required Properties: +-------------------- +- power-domains: phandle pointing to the corresponding PM domain node + and an ID representing the device. + +See dt-bindings/genpd/k2g.h for the list of valid identifiers for k2g. + +Example (K2G): +-------------------- + uart0: serial@02530c00 { + compatible = "ns16550a"; + ... + power-domains = <&k2g_pds K2G_DEV_UART0>; + }; diff --git a/Documentation/devicetree/bindings/usb/da8xx-usb.txt b/Documentation/devicetree/bindings/usb/da8xx-usb.txt index ccb844aba7d4..717c5f656237 100644 --- a/Documentation/devicetree/bindings/usb/da8xx-usb.txt +++ b/Documentation/devicetree/bindings/usb/da8xx-usb.txt @@ -18,10 +18,26 @@ Required properties: - phy-names: Should be "usb-phy" + - dmas: specifies the dma channels + + - dma-names: specifies the names of the channels. Use "rxN" for receive + and "txN" for transmit endpoints. N specifies the endpoint number. + Optional properties: ~~~~~~~~~~~~~~~~~~~~ - vbus-supply: Phandle to a regulator providing the USB bus power. +DMA +~~~ +- compatible: ti,da830-cppi41 +- reg: offset and length of the following register spaces: CPPI DMA Controller, + CPPI DMA Scheduler, Queue Manager +- reg-names: "controller", "scheduler", "queuemgr" +- #dma-cells: should be set to 2. The first number represents the + channel number (0 … 3 for endpoints 1 … 4). + The second number is 0 for RX and 1 for TX transfers. +- #dma-channels: should be set to 4 representing the 4 endpoints. + Example: usb_phy: usb-phy { compatible = "ti,da830-usb-phy"; @@ -30,7 +46,10 @@ Example: }; usb0: usb@200000 { compatible = "ti,da830-musb"; - reg = <0x00200000 0x10000>; + reg = <0x00200000 0x1000>; + ranges; + #address-cells = <1>; + #size-cells = <1>; interrupts = <58>; interrupt-names = "mc"; @@ -39,5 +58,25 @@ Example: phys = <&usb_phy 0>; phy-names = "usb-phy"; + dmas = <&cppi41dma 0 0 &cppi41dma 1 0 + &cppi41dma 2 0 &cppi41dma 3 0 + &cppi41dma 0 1 &cppi41dma 1 1 + &cppi41dma 2 1 &cppi41dma 3 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", + "tx1", "tx2", "tx3", "tx4"; + status = "okay"; + + cppi41dma: dma-controller@201000 { + compatible = "ti,da830-cppi41"; + reg = <0x201000 0x1000 + 0x202000 0x1000 + 0x204000 0x4000>; + reg-names = "controller", "scheduler", "queuemgr"; + interrupts = <58>; + #dma-cells = <2>; + #dma-channels = <4>; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt index 6c7c2bce6d0c..00bea038639e 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.txt +++ b/Documentation/devicetree/bindings/usb/dwc2.txt @@ -14,6 +14,10 @@ Required properties: - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs; - "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs; - snps,dwc2: A generic DWC2 USB controller with default parameters. + - "st,stm32f4x9-fsotg": The DWC2 USB FS/HS controller instance in STM32F4x9 SoCs + configured in FS mode; + - "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs + configured in HS mode; - reg : Should contain 1 register range (address and length) - interrupts : Should contain 1 interrupt - clocks: clock provider specifier diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ee558477e164..12e27844bb7b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -139,6 +139,7 @@ holt Holt Integrated Circuits, Inc. honeywell Honeywell hp Hewlett Packard holtek Holtek Semiconductor, Inc. +hwacom HwaCom Systems Inc. i2se I2SE GmbH ibm International Business Machines (IBM) idt Integrated Device Technologies, Inc. @@ -162,6 +163,7 @@ jedec JEDEC Solid State Technology Association karo Ka-Ro electronics GmbH keithkoep Keith & Koep GmbH keymile Keymile GmbH +khadas Khadas kinetic Kinetic Technologies kosagi Sutajio Ko-Usagi PTE Ltd. kyo Kyocera Corporation @@ -171,6 +173,7 @@ lego LEGO Systems A/S lenovo Lenovo Group Ltd. lg LG Corporation licheepi Lichee Pi +linaro Linaro Limited linux Linux-specific binding lltc Linear Technology Corporation lsi LSI Corp. (LSI Logic) diff --git a/Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt b/Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt new file mode 100644 index 000000000000..bc4b865d178b --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt @@ -0,0 +1,17 @@ +Cortina Systems Gemini SoC Watchdog + +Required properties: +- compatible : must be "cortina,gemini-watchdog" +- reg : shall contain base register location and length +- interrupts : shall contain the interrupt for the watchdog + +Optional properties: +- timeout-sec : the default watchdog timeout in seconds. + +Example: + +watchdog@41000000 { + compatible = "cortina,gemini-watchdog"; + reg = <0x41000000 0x1000>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; +}; diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt index 634d03e20c2d..c9e884b52698 100644 --- a/Documentation/filesystems/overlayfs.txt +++ b/Documentation/filesystems/overlayfs.txt @@ -21,12 +21,19 @@ from accessing the corresponding object from the original filesystem. This is most obvious from the 'st_dev' field returned by stat(2). While directories will report an st_dev from the overlay-filesystem, -all non-directory objects will report an st_dev from the lower or +non-directory objects may report an st_dev from the lower filesystem or upper filesystem that is providing the object. Similarly st_ino will only be unique when combined with st_dev, and both of these can change over the lifetime of a non-directory object. Many applications and tools ignore these values and will not be affected. +In the special case of all overlay layers on the same underlying +filesystem, all objects will report an st_dev from the overlay +filesystem and st_ino from the underlying filesystem. This will +make the overlay mount more compliant with filesystem scanners and +overlay objects will be distinguishable from the corresponding +objects in the original filesystem. + Upper and Lower --------------- diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index eccb675a2852..1e9fcb4d0ec8 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -309,6 +309,7 @@ Code Seq#(hex) Include File Comments 0xA3 80-8F Port ACL in development: <mailto:tlewis@mindspring.com> 0xA3 90-9F linux/dtlk.h +0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem 0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index d2b0a8d81258..08329cb857ed 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -768,7 +768,7 @@ equal to zero, in which case the compiler is within its rights to transform the above code into the following: q = READ_ONCE(a); - WRITE_ONCE(b, 1); + WRITE_ONCE(b, 2); do_something_else(); Given this transformation, the CPU is not required to respect the ordering diff --git a/Documentation/tee.txt b/Documentation/tee.txt new file mode 100644 index 000000000000..718599357596 --- /dev/null +++ b/Documentation/tee.txt @@ -0,0 +1,118 @@ +TEE subsystem +This document describes the TEE subsystem in Linux. + +A TEE (Trusted Execution Environment) is a trusted OS running in some +secure environment, for example, TrustZone on ARM CPUs, or a separate +secure co-processor etc. A TEE driver handles the details needed to +communicate with the TEE. + +This subsystem deals with: + +- Registration of TEE drivers + +- Managing shared memory between Linux and the TEE + +- Providing a generic API to the TEE + +The TEE interface +================= + +include/uapi/linux/tee.h defines the generic interface to a TEE. + +User space (the client) connects to the driver by opening /dev/tee[0-9]* or +/dev/teepriv[0-9]*. + +- TEE_IOC_SHM_ALLOC allocates shared memory and returns a file descriptor + which user space can mmap. When user space doesn't need the file + descriptor any more, it should be closed. When shared memory isn't needed + any longer it should be unmapped with munmap() to allow the reuse of + memory. + +- TEE_IOC_VERSION lets user space know which TEE this driver handles and + the its capabilities. + +- TEE_IOC_OPEN_SESSION opens a new session to a Trusted Application. + +- TEE_IOC_INVOKE invokes a function in a Trusted Application. + +- TEE_IOC_CANCEL may cancel an ongoing TEE_IOC_OPEN_SESSION or TEE_IOC_INVOKE. + +- TEE_IOC_CLOSE_SESSION closes a session to a Trusted Application. + +There are two classes of clients, normal clients and supplicants. The latter is +a helper process for the TEE to access resources in Linux, for example file +system access. A normal client opens /dev/tee[0-9]* and a supplicant opens +/dev/teepriv[0-9]. + +Much of the communication between clients and the TEE is opaque to the +driver. The main job for the driver is to receive requests from the +clients, forward them to the TEE and send back the results. In the case of +supplicants the communication goes in the other direction, the TEE sends +requests to the supplicant which then sends back the result. + +OP-TEE driver +============= + +The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM +TrustZone based OP-TEE solution that is supported. + +Lowest level of communication with OP-TEE builds on ARM SMC Calling +Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface +[3] used internally by the driver. Stacked on top of that is OP-TEE Message +Protocol [4]. + +OP-TEE SMC interface provides the basic functions required by SMCCC and some +additional functions specific for OP-TEE. The most interesting functions are: + +- OPTEE_SMC_FUNCID_CALLS_UID (part of SMCCC) returns the version information + which is then returned by TEE_IOC_VERSION + +- OPTEE_SMC_CALL_GET_OS_UUID returns the particular OP-TEE implementation, used + to tell, for instance, a TrustZone OP-TEE apart from an OP-TEE running on a + separate secure co-processor. + +- OPTEE_SMC_CALL_WITH_ARG drives the OP-TEE message protocol + +- OPTEE_SMC_GET_SHM_CONFIG lets the driver and OP-TEE agree on which memory + range to used for shared memory between Linux and OP-TEE. + +The GlobalPlatform TEE Client API [5] is implemented on top of the generic +TEE API. + +Picture of the relationship between the different components in the +OP-TEE architecture. + + User space Kernel Secure world + ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~ + +--------+ +-------------+ + | Client | | Trusted | + +--------+ | Application | + /\ +-------------+ + || +----------+ /\ + || |tee- | || + || |supplicant| \/ + || +----------+ +-------------+ + \/ /\ | TEE Internal| + +-------+ || | API | + + TEE | || +--------+--------+ +-------------+ + | Client| || | TEE | OP-TEE | | OP-TEE | + | API | \/ | subsys | driver | | Trusted OS | + +-------+----------------+----+-------+----+-----------+-------------+ + | Generic TEE API | | OP-TEE MSG | + | IOCTL (TEE_IOC_*) | | SMCCC (OPTEE_SMC_CALL_*) | + +-----------------------------+ +------------------------------+ + +RPC (Remote Procedure Call) are requests from secure world to kernel driver +or tee-supplicant. An RPC is identified by a special range of SMCCC return +values from OPTEE_SMC_CALL_WITH_ARG. RPC messages which are intended for the +kernel are handled by the kernel driver. Other RPC messages will be forwarded to +tee-supplicant without further involvement of the driver, except switching +shared memory buffer representation. + +References: +[1] https://github.com/OP-TEE/optee_os +[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html +[3] drivers/tee/optee/optee_smc.h +[4] drivers/tee/optee/optee_msg.h +[5] http://www.globalplatform.org/specificationsdevice.asp look for + "TEE Client API Specification v1.0" and click download. diff --git a/MAINTAINERS b/MAINTAINERS index a4a9e31fed72..2decf40d28e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -653,7 +653,9 @@ M: Thor Thayer <thor.thayer@linux.intel.com> S: Maintained F: drivers/gpio/gpio-altera-a10sr.c F: drivers/mfd/altera-a10sr.c +F: drivers/reset/reset-a10sr.c F: include/linux/mfd/altera-a10sr.h +F: include/dt-bindings/reset/altr,rst-mgr-a10sr.h ALTERA TRIPLE SPEED ETHERNET DRIVER M: Vince Bridgers <vbridger@opensource.altera.com> @@ -1056,8 +1058,13 @@ M: Chen-Yu Tsai <wens@csie.org> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained N: sun[x456789]i -F: arch/arm/boot/dts/ntc-gr8* +N: sun50i +F: arch/arm/mach-sunxi/ F: arch/arm64/boot/dts/allwinner/ +F: drivers/clk/sunxi-ng/ +F: drivers/pinctrl/sunxi/ +F: drivers/soc/sunxi/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git ARM/Allwinner SoC Clock Support M: Emilio López <emilio@elopez.com.ar> @@ -1110,7 +1117,6 @@ F: drivers/*/*aspeed* ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT M: Nicolas Ferre <nicolas.ferre@microchip.com> M: Alexandre Belloni <alexandre.belloni@free-electrons.com> -M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.linux4sam.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git @@ -1122,6 +1128,7 @@ F: arch/arm/boot/dts/at91*.dtsi F: arch/arm/boot/dts/sama*.dts F: arch/arm/boot/dts/sama*.dtsi F: arch/arm/include/debug/at91.S +F: drivers/memory/atmel* ARM/ATMEL AT91 Clock Support M: Boris Brezillon <boris.brezillon@free-electrons.com> @@ -1277,6 +1284,7 @@ F: arch/arm/mach-mxs/ F: arch/arm/boot/dts/imx* F: arch/arm/configs/imx*_defconfig F: drivers/clk/imx/ +F: drivers/soc/imx/ F: include/soc/imx/ ARM/FREESCALE VYBRID ARM ARCHITECTURE @@ -1497,6 +1505,7 @@ M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> M: Gregory Clement <gregory.clement@free-electrons.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/soc/dove/ F: arch/arm/mach-dove/ F: arch/arm/mach-mv78xx0/ F: arch/arm/mach-orion5x/ @@ -2667,9 +2676,9 @@ N: kona F: arch/arm/mach-bcm/ BROADCOM BCM2835 ARM ARCHITECTURE -M: Stephen Warren <swarren@wwwdotorg.org> M: Lee Jones <lee@kernel.org> M: Eric Anholt <eric@anholt.net> +M: Stefan Wahren <stefan.wahren@i2se.com> L: linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) T: git git://github.com/anholt/linux @@ -2689,12 +2698,14 @@ F: arch/mips/include/asm/mach-bcm47xx/* BROADCOM BCM5301X ARM ARCHITECTURE M: Hauke Mehrtens <hauke@hauke-m.de> M: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +M: Jon Mason <jonmason@broadcom.com> M: bcm-kernel-feedback-list@broadcom.com L: linux-arm-kernel@lists.infradead.org S: Maintained F: arch/arm/mach-bcm/bcm_5301x.c F: arch/arm/boot/dts/bcm5301x*.dtsi F: arch/arm/boot/dts/bcm470* +F: arch/arm/boot/dts/bcm953012* BROADCOM BCM53573 ARM ARCHITECTURE M: RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> @@ -2856,13 +2867,6 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/broadcom/bcmsysport.* -BROADCOM VULCAN ARM64 SOC -M: Jayachandran C. <c.jayachandran@gmail.com> -M: bcm-kernel-feedback-list@broadcom.com -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -F: arch/arm64/boot/dts/broadcom/vulcan* - BROADCOM NETXTREME-E ROCE DRIVER M: Selvin Xavier <selvin.xavier@broadcom.com> M: Devesh Sharma <devesh.sharma@broadcom.com> @@ -2922,6 +2926,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git S: Maintained F: Documentation/filesystems/btrfs.txt F: fs/btrfs/ +F: include/linux/btrfs* +F: include/uapi/linux/btrfs* BTTV VIDEO4LINUX DRIVER M: Mauro Carvalho Chehab <mchehab@s-opensource.com> @@ -3056,7 +3062,7 @@ CAVIUM THUNDERX2 ARM64 SOC M: Jayachandran C <jnair@caviumnetworks.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: arch/arm64/boot/dts/cavium/thunder-99xx* +F: arch/arm64/boot/dts/cavium/thunder2-99xx* F: Documentation/devicetree/bindings/arm/cavium-thunder2.txt CAVIUM I2C DRIVER @@ -5584,6 +5590,7 @@ L: linux-pm@vger.kernel.org S: Supported F: drivers/base/power/domain*.c F: include/linux/pm_domain.h +F: Documentation/devicetree/bindings/power/power_domain.txt GENERIC UIO DRIVER FOR PCI DEVICES M: "Michael S. Tsirkin" <mst@redhat.com> @@ -9511,6 +9518,11 @@ F: arch/*/oprofile/ F: drivers/oprofile/ F: include/linux/oprofile.h +OP-TEE DRIVER +M: Jens Wiklander <jens.wiklander@linaro.org> +S: Maintained +F: drivers/tee/optee/ + ORACLE CLUSTER FILESYSTEM 2 (OCFS2) M: Mark Fasheh <mfasheh@versity.com> M: Joel Becker <jlbec@evilplan.org> @@ -11292,6 +11304,14 @@ F: drivers/hwtracing/stm/ F: include/linux/stm.h F: include/uapi/linux/stm.h +TEE SUBSYSTEM +M: Jens Wiklander <jens.wiklander@linaro.org> +S: Maintained +F: include/linux/tee_drv.h +F: include/uapi/linux/tee.h +F: drivers/tee/ +F: Documentation/tee.txt + THUNDERBOLT DRIVER M: Andreas Noever <andreas.noever@gmail.com> S: Maintained @@ -12516,9 +12536,8 @@ S: Maintained F: drivers/media/rc/ttusbir.c TEGRA ARCHITECTURE SUPPORT -M: Stephen Warren <swarren@wwwdotorg.org> M: Thierry Reding <thierry.reding@gmail.com> -M: Alexandre Courbot <gnurou@gmail.com> +M: Jonathan Hunter <jonathanh@nvidia.com> L: linux-tegra@vger.kernel.org Q: http://patchwork.ozlabs.org/project/linux-tegra/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git @@ -12597,6 +12616,9 @@ S: Maintained F: Documentation/devicetree/bindings/arm/keystone/ti,sci.txt F: drivers/firmware/ti_sci* F: include/linux/soc/ti/ti_sci_protocol.h +F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt +F: include/dt-bindings/genpd/k2g.h +F: drivers/soc/ti/ti_sci_pm_domains.c THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER M: Hans Verkuil <hverkuil@xs4all.nl> diff --git a/arch/Kconfig b/arch/Kconfig index dcbd462b68b1..6c00e5b00f8b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -324,6 +324,9 @@ config HAVE_CMPXCHG_LOCAL config HAVE_CMPXCHG_DOUBLE bool +config ARCH_WEAK_RELEASE_ACQUIRE + bool + config ARCH_WANT_IPC_PARSE_VERSION bool diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 5d7fb3e7cb97..a5459698f0ee 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -444,6 +444,7 @@ config ARC_HAS_PAE40 bool "Support for the 40-bit Physical Address Extension" default n depends on ISA_ARCV2 + select HIGHMEM help Enable access to physical memory beyond 4G, only supported on ARC cores with 40 bit Physical Addressing support diff --git a/arch/arc/boot/dts/axs10x_mb.dtsi b/arch/arc/boot/dts/axs10x_mb.dtsi index d6c1bbc98ac3..41cfb29b62c1 100644 --- a/arch/arc/boot/dts/axs10x_mb.dtsi +++ b/arch/arc/boot/dts/axs10x_mb.dtsi @@ -51,7 +51,7 @@ pguclk: pguclk { #clock-cells = <0>; compatible = "fixed-clock"; - clock-frequency = <74440000>; + clock-frequency = <74250000>; }; }; @@ -149,12 +149,13 @@ interrupts = <14>; }; - i2c@0x1e000 { - compatible = "snps,designware-i2c"; + i2s: i2s@1e000 { + compatible = "snps,designware-i2s"; reg = <0x1e000 0x100>; - clock-frequency = <400000>; - clocks = <&i2cclk>; + clocks = <&i2sclk 0>; + clock-names = "i2sclk"; interrupts = <15>; + #sound-dai-cells = <0>; }; i2c@0x1f000 { @@ -174,6 +175,7 @@ adi,input-colorspace = "rgb"; adi,input-clock = "1x"; adi,clock-delay = <0x03>; + #sound-dai-cells = <0>; ports { #address-cells = <1>; @@ -295,5 +297,17 @@ }; }; }; + + sound_playback { + compatible = "simple-audio-card"; + simple-audio-card,name = "AXS10x HDMI Audio"; + simple-audio-card,format = "i2s"; + simple-audio-card,cpu { + sound-dai = <&i2s>; + }; + simple-audio-card,codec { + sound-dai = <&adv7511>; + }; + }; }; }; diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h index 5008021fba98..19ebddffb279 100644 --- a/arch/arc/include/asm/cache.h +++ b/arch/arc/include/asm/cache.h @@ -62,6 +62,8 @@ extern unsigned long perip_base, perip_end; #define ARC_REG_IC_BCR 0x77 /* Build Config reg */ #define ARC_REG_IC_IVIC 0x10 #define ARC_REG_IC_CTRL 0x11 +#define ARC_REG_IC_IVIR 0x16 +#define ARC_REG_IC_ENDR 0x17 #define ARC_REG_IC_IVIL 0x19 #define ARC_REG_IC_PTAG 0x1E #define ARC_REG_IC_PTAG_HI 0x1F @@ -76,6 +78,8 @@ extern unsigned long perip_base, perip_end; #define ARC_REG_DC_IVDL 0x4A #define ARC_REG_DC_FLSH 0x4B #define ARC_REG_DC_FLDL 0x4C +#define ARC_REG_DC_STARTR 0x4D +#define ARC_REG_DC_ENDR 0x4E #define ARC_REG_DC_PTAG 0x5C #define ARC_REG_DC_PTAG_HI 0x5F @@ -83,6 +87,8 @@ extern unsigned long perip_base, perip_end; #define DC_CTRL_DIS 0x001 #define DC_CTRL_INV_MODE_FLUSH 0x040 #define DC_CTRL_FLUSH_STATUS 0x100 +#define DC_CTRL_RGN_OP_INV 0x200 +#define DC_CTRL_RGN_OP_MSK 0x200 /*System-level cache (L2 cache) related Auxiliary registers */ #define ARC_REG_SLC_CFG 0x901 diff --git a/arch/arc/include/asm/mmu.h b/arch/arc/include/asm/mmu.h index b144d7ca7d20..db7319e9b506 100644 --- a/arch/arc/include/asm/mmu.h +++ b/arch/arc/include/asm/mmu.h @@ -9,6 +9,10 @@ #ifndef _ASM_ARC_MMU_H #define _ASM_ARC_MMU_H +#ifndef __ASSEMBLY__ +#include <linux/threads.h> /* NR_CPUS */ +#endif + #if defined(CONFIG_ARC_MMU_V1) #define CONFIG_ARC_MMU_VER 1 #elif defined(CONFIG_ARC_MMU_V2) diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index ee22d40afef4..08fe33830d4b 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -35,11 +35,11 @@ #ifndef _ASM_ARC_PGTABLE_H #define _ASM_ARC_PGTABLE_H -#include <asm/page.h> -#include <asm/mmu.h> +#include <linux/const.h> #define __ARCH_USE_5LEVEL_HACK #include <asm-generic/pgtable-nopmd.h> -#include <linux/const.h> +#include <asm/page.h> +#include <asm/mmu.h> /* to propagate CONFIG_ARC_MMU_VER <n> */ /************************************************************************** * Page Table Flags diff --git a/arch/arc/include/uapi/asm/elf.h b/arch/arc/include/uapi/asm/elf.h index 0037a587320d..06d95e611616 100644 --- a/arch/arc/include/uapi/asm/elf.h +++ b/arch/arc/include/uapi/asm/elf.h @@ -27,6 +27,7 @@ typedef unsigned long elf_greg_t; typedef unsigned long elf_fpregset_t; #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) +#define ELF_ARCV2REG (sizeof(struct user_regs_arcv2) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h index 0b3ef63d4a03..dd206e6b482c 100644 --- a/arch/arc/include/uapi/asm/ptrace.h +++ b/arch/arc/include/uapi/asm/ptrace.h @@ -47,6 +47,11 @@ struct user_regs_struct { unsigned long efa; /* break pt addr, for break points in delay slots */ unsigned long stop_pc; /* give dbg stop_pc after ensuring brkpt trap */ }; + +struct user_regs_arcv2 { + unsigned long r30, r58, r59; +}; + #endif /* !__ASSEMBLY__ */ #endif /* _UAPI__ASM_ARC_PTRACE_H */ diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c index 31150060d38b..5ee4676f135d 100644 --- a/arch/arc/kernel/ptrace.c +++ b/arch/arc/kernel/ptrace.c @@ -184,19 +184,75 @@ static int genregs_set(struct task_struct *target, return ret; } +#ifdef CONFIG_ISA_ARCV2 +static int arcv2regs_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const struct pt_regs *regs = task_pt_regs(target); + int ret, copy_sz; + + if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS)) + copy_sz = sizeof(struct user_regs_arcv2); + else + copy_sz = 4; /* r30 only */ + + /* + * itemized copy not needed like above as layout of regs (r30,r58,r59) + * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2) + */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->r30, + 0, copy_sz); + + return ret; +} + +static int arcv2regs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + const struct pt_regs *regs = task_pt_regs(target); + int ret, copy_sz; + + if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS)) + copy_sz = sizeof(struct user_regs_arcv2); + else + copy_sz = 4; /* r30 only */ + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, (void *)®s->r30, + 0, copy_sz); + + return ret; +} + +#endif + enum arc_getset { - REGSET_GENERAL, + REGSET_CMN, + REGSET_ARCV2, }; static const struct user_regset arc_regsets[] = { - [REGSET_GENERAL] = { + [REGSET_CMN] = { .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .size = sizeof(unsigned long), .align = sizeof(unsigned long), .get = genregs_get, .set = genregs_set, - } + }, +#ifdef CONFIG_ISA_ARCV2 + [REGSET_ARCV2] = { + .core_note_type = NT_ARC_V2, + .n = ELF_ARCV2REG, + .size = sizeof(unsigned long), + .align = sizeof(unsigned long), + .get = arcv2regs_get, + .set = arcv2regs_set, + }, +#endif }; static const struct user_regset_view user_arc_view = { diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 928562967f3c..a867575a758b 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -21,6 +21,10 @@ #include <asm/cachectl.h> #include <asm/setup.h> +#ifdef CONFIG_ISA_ARCV2 +#define USE_RGN_FLSH 1 +#endif + static int l2_line_sz; static int ioc_exists; int slc_enable = 1, ioc_enable = 1; @@ -28,7 +32,7 @@ unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE; /* legacy value for boot */ unsigned long perip_end = 0xFFFFFFFF; /* legacy value */ void (*_cache_line_loop_ic_fn)(phys_addr_t paddr, unsigned long vaddr, - unsigned long sz, const int cacheop); + unsigned long sz, const int op, const int full_page); void (*__dma_cache_wback_inv)(phys_addr_t start, unsigned long sz); void (*__dma_cache_inv)(phys_addr_t start, unsigned long sz); @@ -233,11 +237,10 @@ slc_chk: static inline void __cache_line_loop_v2(phys_addr_t paddr, unsigned long vaddr, - unsigned long sz, const int op) + unsigned long sz, const int op, const int full_page) { unsigned int aux_cmd; int num_lines; - const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE; if (op == OP_INV_IC) { aux_cmd = ARC_REG_IC_IVIL; @@ -279,11 +282,10 @@ void __cache_line_loop_v2(phys_addr_t paddr, unsigned long vaddr, */ static inline void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr, - unsigned long sz, const int op) + unsigned long sz, const int op, const int full_page) { unsigned int aux_cmd, aux_tag; int num_lines; - const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE; if (op == OP_INV_IC) { aux_cmd = ARC_REG_IC_IVIL; @@ -334,6 +336,8 @@ void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr, } } +#ifndef USE_RGN_FLSH + /* * In HS38x (MMU v4), I-cache is VIPT (can alias), D-cache is PIPT * Here's how cache ops are implemented @@ -349,17 +353,16 @@ void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr, */ static inline void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr, - unsigned long sz, const int cacheop) + unsigned long sz, const int op, const int full_page) { unsigned int aux_cmd; int num_lines; - const int full_page_op = __builtin_constant_p(sz) && sz == PAGE_SIZE; - if (cacheop == OP_INV_IC) { + if (op == OP_INV_IC) { aux_cmd = ARC_REG_IC_IVIL; } else { /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ - aux_cmd = cacheop & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL; + aux_cmd = op & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL; } /* Ensure we properly floor/ceil the non-line aligned/sized requests @@ -368,7 +371,7 @@ void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr, * -@paddr will be cache-line aligned already (being page aligned) * -@sz will be integral multiple of line size (being page sized). */ - if (!full_page_op) { + if (!full_page) { sz += paddr & ~CACHE_LINE_MASK; paddr &= CACHE_LINE_MASK; } @@ -381,7 +384,7 @@ void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr, * - (and needs to be written before the lower 32 bits) */ if (is_pae40_enabled()) { - if (cacheop == OP_INV_IC) + if (op == OP_INV_IC) /* * Non aliasing I-cache in HS38, * aliasing I-cache handled in __cache_line_loop_v3() @@ -397,6 +400,55 @@ void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr, } } +#else + +/* + * optimized flush operation which takes a region as opposed to iterating per line + */ +static inline +void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr, + unsigned long sz, const int op, const int full_page) +{ + unsigned int s, e; + + /* Only for Non aliasing I-cache in HS38 */ + if (op == OP_INV_IC) { + s = ARC_REG_IC_IVIR; + e = ARC_REG_IC_ENDR; + } else { + s = ARC_REG_DC_STARTR; + e = ARC_REG_DC_ENDR; + } + + if (!full_page) { + /* for any leading gap between @paddr and start of cache line */ + sz += paddr & ~CACHE_LINE_MASK; + paddr &= CACHE_LINE_MASK; + + /* + * account for any trailing gap to end of cache line + * this is equivalent to DIV_ROUND_UP() in line ops above + */ + sz += L1_CACHE_BYTES - 1; + } + + if (is_pae40_enabled()) { + /* TBD: check if crossing 4TB boundary */ + if (op == OP_INV_IC) + write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32); + else + write_aux_reg(ARC_REG_DC_PTAG_HI, (u64)paddr >> 32); + } + + /* ENDR needs to be set ahead of START */ + write_aux_reg(e, paddr + sz); /* ENDR is exclusive */ + write_aux_reg(s, paddr); + + /* caller waits on DC_CTRL.FS */ +} + +#endif + #if (CONFIG_ARC_MMU_VER < 3) #define __cache_line_loop __cache_line_loop_v2 #elif (CONFIG_ARC_MMU_VER == 3) @@ -411,6 +463,11 @@ void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr, * Machine specific helpers for Entire D-Cache or Per Line ops */ +#ifndef USE_RGN_FLSH +/* + * this version avoids extra read/write of DC_CTRL for flush or invalid ops + * in the non region flush regime (such as for ARCompact) + */ static inline void __before_dc_op(const int op) { if (op == OP_FLUSH_N_INV) { @@ -424,6 +481,32 @@ static inline void __before_dc_op(const int op) } } +#else + +static inline void __before_dc_op(const int op) +{ + const unsigned int ctl = ARC_REG_DC_CTRL; + unsigned int val = read_aux_reg(ctl); + + if (op == OP_FLUSH_N_INV) { + val |= DC_CTRL_INV_MODE_FLUSH; + } + + if (op != OP_INV_IC) { + /* + * Flush / Invalidate is provided by DC_CTRL.RNG_OP 0 or 1 + * combined Flush-n-invalidate uses DC_CTRL.IM = 1 set above + */ + val &= ~DC_CTRL_RGN_OP_MSK; + if (op & OP_INV) + val |= DC_CTRL_RGN_OP_INV; + } + write_aux_reg(ctl, val); +} + +#endif + + static inline void __after_dc_op(const int op) { if (op & OP_FLUSH) { @@ -486,13 +569,14 @@ static void __dc_enable(void) static inline void __dc_line_op(phys_addr_t paddr, unsigned long vaddr, unsigned long sz, const int op) { + const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE; unsigned long flags; local_irq_save(flags); __before_dc_op(op); - __cache_line_loop(paddr, vaddr, sz, op); + __cache_line_loop(paddr, vaddr, sz, op, full_page); __after_dc_op(op); @@ -521,10 +605,11 @@ static inline void __ic_line_inv_vaddr_local(phys_addr_t paddr, unsigned long vaddr, unsigned long sz) { + const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE; unsigned long flags; local_irq_save(flags); - (*_cache_line_loop_ic_fn)(paddr, vaddr, sz, OP_INV_IC); + (*_cache_line_loop_ic_fn)(paddr, vaddr, sz, OP_INV_IC, full_page); local_irq_restore(flags); } diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4c6816be23a9..4c1a35f15838 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -359,15 +359,6 @@ config ARM_SINGLE_ARMV7M select SPARSE_IRQ select USE_OF -config ARCH_GEMINI - bool "Cortina Systems Gemini" - select CLKSRC_MMIO - select CPU_FA526 - select GENERIC_CLOCKEVENTS - select GPIOLIB - help - Support for the Cortina Systems Gemini family SoCs - config ARCH_EBSA110 bool "EBSA-110" select ARCH_USES_GETTIMEOFFSET @@ -819,6 +810,8 @@ source "arch/arm/mach-spear/Kconfig" source "arch/arm/mach-sti/Kconfig" +source "arch/arm/mach-stm32/Kconfig" + source "arch/arm/mach-s3c24xx/Kconfig" source "arch/arm/mach-s3c64xx/Kconfig" @@ -877,28 +870,6 @@ config ARCH_LPC18XX Support for NXP's LPC18xx Cortex-M3 and LPC43xx Cortex-M4 high performance microcontrollers. -config ARCH_STM32 - bool "STMicrolectronics STM32" - depends on ARM_SINGLE_ARMV7M - select ARCH_HAS_RESET_CONTROLLER - select ARMV7M_SYSTICK - select CLKSRC_STM32 - select PINCTRL - select RESET_CONTROLLER - select STM32_EXTI - help - Support for STMicroelectronics STM32 processors. - -config MACH_STM32F429 - bool "STMicrolectronics STM32F429" - depends on ARCH_STM32 - default y - -config MACH_STM32F746 - bool "STMicrolectronics STM32F746" - depends on ARCH_STM32 - default y - config ARCH_MPS2 bool "ARM MPS2 platform" depends on ARM_SINGLE_ARMV7M diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 011808490fed..9c5e1d944d1c 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -77,6 +77,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \ bcm4708-asus-rt-ac56u.dtb \ bcm4708-asus-rt-ac68u.dtb \ bcm4708-buffalo-wzr-1750dhp.dtb \ + bcm4708-linksys-ea6300-v1.dtb \ bcm4708-luxul-xap-1510.dtb \ bcm4708-luxul-xwc-1000.dtb \ bcm4708-netgear-r6250.dtb \ @@ -87,17 +88,21 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \ bcm47081-buffalo-wzr-900dhp.dtb \ bcm47081-luxul-xap-1410.dtb \ bcm47081-luxul-xwr-1200.dtb \ + bcm47081-tplink-archer-c5-v2.dtb \ bcm4709-asus-rt-ac87u.dtb \ bcm4709-buffalo-wxr-1900dhp.dtb \ + bcm4709-linksys-ea9200.dtb \ bcm4709-netgear-r7000.dtb \ bcm4709-netgear-r8000.dtb \ bcm4709-tplink-archer-c9-v1.dtb \ bcm47094-dlink-dir-885l.dtb \ + bcm47094-linksys-panamera.dtb \ bcm47094-luxul-xwr-3100.dtb \ bcm47094-netgear-r8500.dtb \ bcm94708.dtb \ bcm94709.dtb \ bcm953012er.dtb \ + bcm953012hr.dtb \ bcm953012k.dtb dtb-$(CONFIG_ARCH_BCM_53573) += \ bcm47189-tenda-ac9.dtb @@ -173,6 +178,12 @@ dtb-$(CONFIG_ARCH_EXYNOS5) += \ exynos5440-sd5v1.dtb \ exynos5440-ssdk5440.dtb \ exynos5800-peach-pi.dtb +dtb-$(CONFIG_ARCH_GEMINI) += \ + gemini-nas4220b.dtb \ + gemini-rut1xx.dtb \ + gemini-sq201.dtb \ + gemini-wbd111.dtb \ + gemini-wbd222.dtb dtb-$(CONFIG_ARCH_HI3xxx) += \ hi3620-hi4511.dtb dtb-$(CONFIG_ARCH_HIGHBANK) += \ @@ -352,6 +363,8 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6dl-gw551x.dtb \ imx6dl-gw552x.dtb \ imx6dl-gw553x.dtb \ + imx6dl-gw5903.dtb \ + imx6dl-gw5904.dtb \ imx6dl-hummingboard.dtb \ imx6dl-icore.dtb \ imx6dl-icore-rqs.dtb \ @@ -395,9 +408,13 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-gw551x.dtb \ imx6q-gw552x.dtb \ imx6q-gw553x.dtb \ + imx6q-gw5903.dtb \ + imx6q-gw5904.dtb \ imx6q-h100.dtb \ imx6q-hummingboard.dtb \ imx6q-icore.dtb \ + imx6q-icore-ofcap10.dtb \ + imx6q-icore-ofcap12.dtb \ imx6q-icore-rqs.dtb \ imx6q-marsboard.dtb \ imx6q-mccmon6.dtb \ @@ -425,9 +442,12 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-utilite-pro.dtb \ imx6q-wandboard.dtb \ imx6q-wandboard-revb1.dtb \ + imx6q-zii-rdu2.dtb \ imx6qp-nitrogen6_max.dtb \ + imx6qp-nitrogen6_som2.dtb \ imx6qp-sabreauto.dtb \ - imx6qp-sabresd.dtb + imx6qp-sabresd.dtb \ + imx6qp-zii-rdu2.dtb dtb-$(CONFIG_SOC_IMX6SL) += \ imx6sl-evk.dtb \ imx6sl-warp.dtb @@ -458,6 +478,7 @@ dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-nitrogen7.dtb \ imx7d-sbc-imx7.dtb \ imx7d-sdb.dtb \ + imx7d-sdb-sht11.dtb \ imx7s-colibri-eval-v3.dtb \ imx7s-warp.dtb dtb-$(CONFIG_SOC_LS1021A) += \ @@ -488,6 +509,10 @@ dtb-$(CONFIG_ARCH_MXS) += \ imx28-cfa10056.dtb \ imx28-cfa10057.dtb \ imx28-cfa10058.dtb \ + imx28-duckbill-2-485.dtb \ + imx28-duckbill-2.dtb \ + imx28-duckbill-2-enocean.dtb \ + imx28-duckbill-2-spi.dtb \ imx28-duckbill.dtb \ imx28-eukrea-mbmx283lc.dtb \ imx28-eukrea-mbmx287lc.dtb \ @@ -673,6 +698,25 @@ dtb-$(CONFIG_ARCH_REALVIEW) += \ arm-realview-eb-a9mp-bbrevd.dtb \ arm-realview-pba8.dtb \ arm-realview-pbx-a9.dtb +dtb-$(CONFIG_ARCH_RENESAS) += \ + emev2-kzm9d.dtb \ + r7s72100-genmai.dtb \ + r7s72100-rskrza1.dtb \ + r8a73a4-ape6evm.dtb \ + r8a7740-armadillo800eva.dtb \ + r8a7743-sk-rzg1m.dtb \ + r8a7745-sk-rzg1e.dtb \ + r8a7778-bockw.dtb \ + r8a7779-marzen.dtb \ + r8a7790-lager.dtb \ + r8a7791-koelsch.dtb \ + r8a7791-porter.dtb \ + r8a7792-blanche.dtb \ + r8a7792-wheat.dtb \ + r8a7793-gose.dtb \ + r8a7794-alt.dtb \ + r8a7794-silk.dtb \ + sh73a0-kzm9g.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk1108-evb.dtb \ rk3036-evb.dtb \ @@ -692,9 +736,11 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-firefly.dtb \ rk3288-firefly-reload.dtb \ rk3288-miqi.dtb \ + rk3288-phycore-rdk.dtb \ rk3288-popmetal.dtb \ rk3288-r89.dtb \ rk3288-rock2-square.dtb \ + rk3288-tinker.dtb \ rk3288-veyron-brain.dtb \ rk3288-veyron-jaq.dtb \ rk3288-veyron-jerry.dtb \ @@ -713,25 +759,6 @@ dtb-$(CONFIG_ARCH_S5PV210) += \ s5pv210-smdkc110.dtb \ s5pv210-smdkv210.dtb \ s5pv210-torbreck.dtb -dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \ - emev2-kzm9d.dtb \ - r7s72100-genmai.dtb \ - r7s72100-rskrza1.dtb \ - r8a73a4-ape6evm.dtb \ - r8a7740-armadillo800eva.dtb \ - r8a7743-sk-rzg1m.dtb \ - r8a7745-sk-rzg1e.dtb \ - r8a7778-bockw.dtb \ - r8a7779-marzen.dtb \ - r8a7790-lager.dtb \ - r8a7791-koelsch.dtb \ - r8a7791-porter.dtb \ - r8a7792-blanche.dtb \ - r8a7792-wheat.dtb \ - r8a7793-gose.dtb \ - r8a7794-alt.dtb \ - r8a7794-silk.dtb \ - sh73a0-kzm9g.dtb dtb-$(CONFIG_ARCH_SOCFPGA) += \ socfpga_arria5_socdk.dtb \ socfpga_arria10_socdk_nand.dtb \ @@ -764,7 +791,8 @@ dtb-$(CONFIG_ARCH_STM32)+= \ stm32f429-disco.dtb \ stm32f469-disco.dtb \ stm32429i-eval.dtb \ - stm32746g-eval.dtb + stm32746g-eval.dtb \ + stm32h743i-eval.dtb dtb-$(CONFIG_MACH_SUN4I) += \ sun4i-a10-a1000.dtb \ sun4i-a10-ba10-tvbox.dtb \ @@ -868,6 +896,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \ sun8i-h3-beelink-x2.dtb \ sun8i-h3-nanopi-m1.dtb \ sun8i-h3-nanopi-neo.dtb \ + sun8i-h3-nanopi-neo-air.dtb \ sun8i-h3-orangepi-2.dtb \ sun8i-h3-orangepi-lite.dtb \ sun8i-h3-orangepi-one.dtb \ @@ -970,6 +999,8 @@ dtb-$(CONFIG_MACH_ARMADA_38X) += \ armada-385-db-ap.dtb \ armada-385-linksys-caiman.dtb \ armada-385-linksys-cobra.dtb \ + armada-385-linksys-shelby.dtb \ + armada-385-synology-ds116.dtb \ armada-385-turris-omnia.dtb \ armada-388-clearfog.dtb \ armada-388-clearfog-base.dtb \ diff --git a/arch/arm/boot/dts/alpine.dtsi b/arch/arm/boot/dts/alpine.dtsi index d0eefc3b886c..731df7a8c4e6 100644 --- a/arch/arm/boot/dts/alpine.dtsi +++ b/arch/arm/boot/dts/alpine.dtsi @@ -41,28 +41,28 @@ compatible = "arm,cortex-a15"; device_type = "cpu"; reg = <0>; - clock-frequency = <0>; /* Filled by loader */ + clock-frequency = <1700000000>; }; cpu@1 { compatible = "arm,cortex-a15"; device_type = "cpu"; reg = <1>; - clock-frequency = <0>; /* Filled by loader */ + clock-frequency = <1700000000>; }; cpu@2 { compatible = "arm,cortex-a15"; device_type = "cpu"; reg = <2>; - clock-frequency = <0>; /* Filled by loader */ + clock-frequency = <1700000000>; }; cpu@3 { compatible = "arm,cortex-a15"; device_type = "cpu"; reg = <3>; - clock-frequency = <0>; /* Filled by loader */ + clock-frequency = <1700000000>; }; }; @@ -81,7 +81,7 @@ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; - clock-frequency = <0>; /* Filled by loader */ + clock-frequency = <50000000>; }; /* Interrupt Controller */ @@ -120,26 +120,26 @@ <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; }; - uart0:uart@fd883000 { + uart0: uart@fd883000 { compatible = "ns16550a"; reg = <0x0 0xfd883000 0x0 0x1000>; - clock-frequency = <0>; /* Filled by loader */ + clock-frequency = <375000000>; interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; }; - uart1:uart@0xfd884000 { + uart1: uart@fd884000 { compatible = "ns16550a"; reg = <0x0 0xfd884000 0x0 0x1000>; - clock-frequency = <0>; /* Filled by loader */ + clock-frequency = <375000000>; interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; }; /* Internal PCIe Controller */ - pcie-internal@0xfbc00000 { + pcie@fbc00000 { compatible = "pci-host-ecam-generic"; device_type = "pci"; #size-cells = <2>; diff --git a/arch/arm/boot/dts/am335x-baltos-ir2110.dts b/arch/arm/boot/dts/am335x-baltos-ir2110.dts index 501c7527121b..75de1e723303 100644 --- a/arch/arm/boot/dts/am335x-baltos-ir2110.dts +++ b/arch/arm/boot/dts/am335x-baltos-ir2110.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "am335x-baltos.dtsi" +#include "am335x-baltos-leds.dtsi" / { model = "OnRISC Baltos iR 2110"; diff --git a/arch/arm/boot/dts/am335x-baltos-ir3220.dts b/arch/arm/boot/dts/am335x-baltos-ir3220.dts index 19f53b8569e1..46df1b22022c 100644 --- a/arch/arm/boot/dts/am335x-baltos-ir3220.dts +++ b/arch/arm/boot/dts/am335x-baltos-ir3220.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "am335x-baltos.dtsi" +#include "am335x-baltos-leds.dtsi" / { model = "OnRISC Baltos iR 3220"; diff --git a/arch/arm/boot/dts/am335x-baltos-ir5221.dts b/arch/arm/boot/dts/am335x-baltos-ir5221.dts index 2b9d7f4db23f..5d56355ba040 100644 --- a/arch/arm/boot/dts/am335x-baltos-ir5221.dts +++ b/arch/arm/boot/dts/am335x-baltos-ir5221.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "am335x-baltos.dtsi" +#include "am335x-baltos-leds.dtsi" / { model = "OnRISC Baltos iR 5221"; diff --git a/arch/arm/boot/dts/am335x-baltos-leds.dtsi b/arch/arm/boot/dts/am335x-baltos-leds.dtsi new file mode 100644 index 000000000000..3ab1767d5c13 --- /dev/null +++ b/arch/arm/boot/dts/am335x-baltos-leds.dtsi @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * VScom OnRISC + * http://www.vscom.de + */ + +/*#include "am33xx.dtsi"*/ + +/ { + leds { + pinctrl-names = "default"; + pinctrl-0 = <&user_leds>; + + compatible = "gpio-leds"; + + power { + label = "onrisc:red:power"; + linux,default-trigger = "default-on"; + gpios = <&gpio3 0 GPIO_ACTIVE_LOW>; + default-state = "on"; + }; + wlan { + label = "onrisc:blue:wlan"; + gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + app { + label = "onrisc:green:app"; + gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +}; + +&am33xx_pinmux { + user_leds: pinmux_user_leds { + pinctrl-single,pins = < + AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mii1_col.gpio3_0 PWR LED */ + AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mii1_txd3.gpio0_16 WLAN LED */ + AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mii1_txd2.gpio0_17 APP LED */ + >; + }; +}; diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts index 77273df1a028..935ed17d22e4 100644 --- a/arch/arm/boot/dts/am335x-boneblack.dts +++ b/arch/arm/boot/dts/am335x-boneblack.dts @@ -15,3 +15,14 @@ model = "TI AM335x BeagleBone Black"; compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; }; + +&cpu0_opp_table { + /* + * All PG 2.0 silicon may not support 1GHz but some of the early + * BeagleBone Blacks have PG 2.0 silicon which is guaranteed + * to support 1GHz OPP so enable it for PG 2.0 on this board. + */ + oppnitro@1000000000 { + opp-supported-hw = <0x06 0x0100>; + }; +}; diff --git a/arch/arm/boot/dts/am335x-icev2.dts b/arch/arm/boot/dts/am335x-icev2.dts index a2ad076822db..f2005ecca74f 100644 --- a/arch/arm/boot/dts/am335x-icev2.dts +++ b/arch/arm/boot/dts/am335x-icev2.dts @@ -201,6 +201,69 @@ AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLUP | MUX_MODE1) /* (L16) gmii1_rxd2.uart3_txd */ >; }; + + cpsw_default: cpsw_default { + pinctrl-single,pins = < + /* Slave 1, RMII mode */ + AM33XX_IOPAD(0x90c, (PIN_INPUT_PULLUP | MUX_MODE1)) /* mii1_crs.rmii1_crs_dv */ + AM33XX_IOPAD(0x944, (PIN_INPUT_PULLUP | MUX_MODE0)) /* rmii1_refclk.rmii1_refclk */ + AM33XX_IOPAD(0x940, (PIN_INPUT_PULLUP | MUX_MODE1)) /* mii1_rxd0.rmii1_rxd0 */ + AM33XX_IOPAD(0x93c, (PIN_INPUT_PULLUP | MUX_MODE1)) /* mii1_rxd1.rmii1_rxd1 */ + AM33XX_IOPAD(0x910, (PIN_INPUT_PULLUP | MUX_MODE1)) /* mii1_rxerr.rmii1_rxerr */ + AM33XX_IOPAD(0x928, (PIN_OUTPUT_PULLDOWN | MUX_MODE1)) /* mii1_txd0.rmii1_txd0 */ + AM33XX_IOPAD(0x924, (PIN_OUTPUT_PULLDOWN | MUX_MODE1)) /* mii1_txd1.rmii1_txd1 */ + AM33XX_IOPAD(0x914, (PIN_OUTPUT_PULLDOWN | MUX_MODE1)) /* mii1_txen.rmii1_txen */ + /* Slave 2, RMII mode */ + AM33XX_IOPAD(0x870, (PIN_INPUT_PULLUP | MUX_MODE3)) /* gpmc_wait0.rmii2_crs_dv */ + AM33XX_IOPAD(0x908, (PIN_INPUT_PULLUP | MUX_MODE1)) /* mii1_col.rmii2_refclk */ + AM33XX_IOPAD(0x86c, (PIN_INPUT_PULLUP | MUX_MODE3)) /* gpmc_a11.rmii2_rxd0 */ + AM33XX_IOPAD(0x868, (PIN_INPUT_PULLUP | MUX_MODE3)) /* gpmc_a10.rmii2_rxd1 */ + AM33XX_IOPAD(0x874, (PIN_INPUT_PULLUP | MUX_MODE3)) /* gpmc_wpn.rmii2_rxerr */ + AM33XX_IOPAD(0x854, (PIN_OUTPUT_PULLDOWN | MUX_MODE3)) /* gpmc_a5.rmii2_txd0 */ + AM33XX_IOPAD(0x850, (PIN_OUTPUT_PULLDOWN | MUX_MODE3)) /* gpmc_a4.rmii2_txd1 */ + AM33XX_IOPAD(0x840, (PIN_OUTPUT_PULLDOWN | MUX_MODE3)) /* gpmc_a0.rmii2_txen */ + >; + }; + + cpsw_sleep: cpsw_sleep { + pinctrl-single,pins = < + /* Slave 1 reset value */ + AM33XX_IOPAD(0x90c, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x944, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x940, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x93c, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x910, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x928, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x924, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x914, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + + /* Slave 2 reset value */ + AM33XX_IOPAD(0x870, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x908, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x86c, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x868, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x874, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x854, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x850, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x840, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + >; + }; + + davinci_mdio_default: davinci_mdio_default { + pinctrl-single,pins = < + /* MDIO */ + AM33XX_IOPAD(0x948, (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)) /* mdio_data.mdio_data */ + AM33XX_IOPAD(0x94c, (PIN_OUTPUT_PULLUP | MUX_MODE0)) /* mdio_clk.mdio_clk */ + >; + }; + + davinci_mdio_sleep: davinci_mdio_sleep { + pinctrl-single,pins = < + /* MDIO reset value */ + AM33XX_IOPAD(0x948, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + AM33XX_IOPAD(0x94c, (PIN_INPUT_PULLDOWN | MUX_MODE7)) + >; + }; }; &i2c0 { @@ -245,6 +308,39 @@ spi-max-frequency = <1000000>; spi-cpol; }; + + spi_nor: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q64", "jedec,spi-nor"; + spi-max-frequency = <80000000>; + m25p,fast-read; + reg = <0>; + + partition@0 { + label = "u-boot-spl"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@1 { + label = "u-boot"; + reg = <0x80000 0x100000>; + read-only; + }; + + partition@2 { + label = "u-boot-env"; + reg = <0x180000 0x20000>; + read-only; + }; + + partition@3 { + label = "misc"; + reg = <0x1A0000 0x660000>; + }; + }; + }; &tscadc { @@ -350,3 +446,61 @@ pinctrl-0 = <&uart3_pins_default>; status = "okay"; }; + +&gpio3 { + p4 { + gpio-hog; + gpios = <4 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "PR1_MII_CTRL"; + }; + + p10 { + gpio-hog; + gpios = <10 GPIO_ACTIVE_HIGH>; + /* ETH1 mux: Low for MII-PRU, high for RMII-CPSW */ + output-high; + line-name = "MUX_MII_CTL1"; + }; +}; + +&cpsw_emac0 { + phy-handle = <ðphy0>; + phy-mode = "rmii"; + dual_emac_res_vlan = <1>; +}; + +&cpsw_emac1 { + phy-handle = <ðphy1>; + phy-mode = "rmii"; + dual_emac_res_vlan = <2>; +}; + +&mac { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cpsw_default>; + pinctrl-1 = <&cpsw_sleep>; + status = "okay"; + dual_emac; +}; + +&phy_sel { + rmii-clock-ext; +}; + +&davinci_mdio { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&davinci_mdio_default>; + pinctrl-1 = <&davinci_mdio_sleep>; + status = "okay"; + reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + reset-delay-us = <2>; /* PHY datasheet states 1uS min */ + + ethphy0: ethernet-phy@1 { + reg = <1>; + }; + + ethphy1: ethernet-phy@3 { + reg = <3>; + }; +}; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 9e96d60976b7..9e242943dcec 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -46,19 +46,7 @@ device_type = "cpu"; reg = <0>; - /* - * To consider voltage drop between PMIC and SoC, - * tolerance value is reduced to 2% from 4% and - * voltage value is increased as a precaution. - */ - operating-points = < - /* kHz uV */ - 720000 1285000 - 600000 1225000 - 500000 1125000 - 275000 1125000 - >; - voltage-tolerance = <2>; /* 2 percentage */ + operating-points-v2 = <&cpu0_opp_table>; clocks = <&dpll_mpu_ck>; clock-names = "cpu"; @@ -67,6 +55,79 @@ }; }; + cpu0_opp_table: opp-table { + compatible = "operating-points-v2-ti-cpu"; + syscon = <&scm_conf>; + + /* + * The three following nodes are marked with opp-suspend + * because the can not be enabled simultaneously on a + * single SoC. + */ + opp50@300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <950000 931000 969000>; + opp-supported-hw = <0x06 0x0010>; + opp-suspend; + }; + + opp100@275000000 { + opp-hz = /bits/ 64 <275000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x01 0x00FF>; + opp-suspend; + }; + + opp100@300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x06 0x0020>; + opp-suspend; + }; + + opp100@500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x01 0xFFFF>; + }; + + opp100@600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x06 0x0040>; + }; + + opp120@600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <1200000 1176000 1224000>; + opp-supported-hw = <0x01 0xFFFF>; + }; + + opp120@720000000 { + opp-hz = /bits/ 64 <720000000>; + opp-microvolt = <1200000 1176000 1224000>; + opp-supported-hw = <0x06 0x0080>; + }; + + oppturbo@720000000 { + opp-hz = /bits/ 64 <720000000>; + opp-microvolt = <1260000 1234800 1285200>; + opp-supported-hw = <0x01 0xFFFF>; + }; + + oppturbo@800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1260000 1234800 1285200>; + opp-supported-hw = <0x06 0x0100>; + }; + + oppnitro@1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <1325000 1298500 1351500>; + opp-supported-hw = <0x04 0x0200>; + }; + }; + pmu { compatible = "arm,cortex-a8-pmu"; interrupts = <3>; diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 9fe545dbfa89..00da3f2c4072 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -13,6 +13,7 @@ / { aliases { serial3 = &uart4; + can = &hecc; }; ocp@68000000 { @@ -72,6 +73,17 @@ pinctrl-single,register-width = <16>; pinctrl-single,function-mask = <0xff1f>; }; + + hecc: can@5c050000 { + compatible = "ti,am3517-hecc"; + status = "disabled"; + reg = <0x5c050000 0x80>, + <0x5c053000 0x180>, + <0x5c052000 0x200>; + reg-names = "hecc", "hecc-ram", "mbx"; + interrupts = <24>; + clocks = <&hecc_ck>; + }; }; }; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 97fcaf415de1..176e09e9a45e 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -50,15 +50,14 @@ clock-names = "cpu"; operating-points-v2 = <&cpu0_opp_table>; - ti,syscon-efuse = <&scm_conf 0x610 0x3f 0>; - ti,syscon-rev = <&scm_conf 0x600>; clock-latency = <300000>; /* From omap-cpufreq driver */ }; }; - cpu0_opp_table: opp_table0 { - compatible = "operating-points-v2"; + cpu0_opp_table: opp-table { + compatible = "operating-points-v2-ti-cpu"; + syscon = <&scm_conf>; opp50@300000000 { opp-hz = /bits/ 64 <300000000>; diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index a4f31739057f..397e98b7e246 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -501,6 +501,21 @@ AM4372_IOPAD(0x884, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn2.gpio1_31 */ >; }; + + uart0_pins_default: uart0_pins_default { + pinctrl-single,pins = < + AM4372_IOPAD(0x968, PIN_INPUT | MUX_MODE0) /* uart0_ctsn.uart0_ctsn */ + AM4372_IOPAD(0x96C, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_rtsn.uart0_rtsn */ + AM4372_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */ + AM4372_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */ + >; + }; +}; + +&uart0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_default>; }; &i2c0 { diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi index e5ac1d81d15c..c536b2f5389f 100644 --- a/arch/arm/boot/dts/am57xx-idk-common.dtsi +++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi @@ -101,6 +101,22 @@ }; }; +&dra7_pmx_core { + dcan1_pins_default: dcan1_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x37d0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */ + DRA7XX_CORE_IOPAD(0x37d4, PIN_INPUT_PULLUP | MUX_MODE0) /* dcan1_rx */ + >; + }; + + dcan1_pins_sleep: dcan1_pins_sleep { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x37d0, MUX_MODE15 | PULL_UP) /* dcan1_tx.off */ + DRA7XX_CORE_IOPAD(0x37d4, MUX_MODE15 | PULL_UP) /* dcan1_rx.off */ + >; + }; +}; + &i2c1 { status = "okay"; clock-frequency = <400000>; @@ -391,6 +407,14 @@ max-frequency = <96000000>; }; +&dcan1 { + status = "okay"; + pinctrl-names = "default", "sleep", "active"; + pinctrl-0 = <&dcan1_pins_sleep>; + pinctrl-1 = <&dcan1_pins_sleep>; + pinctrl-2 = <&dcan1_pins_default>; +}; + &qspi { status = "okay"; diff --git a/arch/arm/boot/dts/armada-385-linksys-shelby.dts b/arch/arm/boot/dts/armada-385-linksys-shelby.dts new file mode 100644 index 000000000000..c7a8ddd7f9a5 --- /dev/null +++ b/arch/arm/boot/dts/armada-385-linksys-shelby.dts @@ -0,0 +1,114 @@ +/* + * Device Tree file for the Linksys WRT1900ACS (Shelby) + * + * Copyright (C) 2015 Imre Kaloz <kaloz@openwrt.org> + * + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "armada-385-linksys.dtsi" + +/ { + model = "Linksys WRT1900ACS"; + compatible = "linksys,shelby", "linksys,armada385", "marvell,armada385", + "marvell,armada380"; + + soc { + internal-regs{ + i2c@11000 { + + pca9635@68 { + #address-cells = <1>; + #size-cells = <0>; + + wan_amber@0 { + label = "shelby:amber:wan"; + reg = <0x0>; + }; + + wan_white@1 { + label = "shelby:white:wan"; + reg = <0x1>; + }; + + wlan_2g@2 { + label = "shelby:white:wlan_2g"; + reg = <0x2>; + }; + + wlan_5g@3 { + label = "shelby:white:wlan_5g"; + reg = <0x3>; + }; + + usb2@5 { + label = "shelby:white:usb2"; + reg = <0x5>; + }; + + usb3_1@6 { + label = "shelby:white:usb3_1"; + reg = <0x6>; + }; + + usb3_2@7 { + label = "shelby:white:usb3_2"; + reg = <0x7>; + }; + + wps_white@8 { + label = "shelby:white:wps"; + reg = <0x8>; + }; + + wps_amber@9 { + label = "shelby:amber:wps"; + reg = <0x9>; + }; + }; + }; + }; + }; + + gpio-leds { + power { + label = "shelby:white:power"; + }; + + sata { + label = "shelby:white:sata"; + }; + }; +}; diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi index df47bf1ea5eb..2306c45685b1 100644 --- a/arch/arm/boot/dts/armada-385-linksys.dtsi +++ b/arch/arm/boot/dts/armada-385-linksys.dtsi @@ -59,7 +59,8 @@ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000 MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000 - MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>; + MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000 + MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>; internal-regs { i2c@11000 { @@ -88,6 +89,9 @@ ethernet@70000 { status = "okay"; phy-mode = "rgmii-id"; + buffer-manager = <&bm>; + bm,pool-long = <2>; + bm,pool-short = <3>; fixed-link { speed = <1000>; full-duplex; @@ -97,6 +101,9 @@ ethernet@34000 { status = "okay"; phy-mode = "sgmii"; + buffer-manager = <&bm>; + bm,pool-long = <0>; + bm,pool-short = <1>; fixed-link { speed = <1000>; full-duplex; @@ -159,6 +166,10 @@ status = "okay"; }; + bm@c8000 { + status = "okay"; + }; + /* USB part of the eSATA/USB 2.0 port */ usb@58000 { status = "okay"; @@ -241,6 +252,10 @@ }; }; + bm-bppi { + status = "okay"; + }; + pcie-controller { status = "okay"; @@ -305,6 +320,7 @@ sata { gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; default-state = "off"; + linux,default-trigger = "disk-activity"; }; }; diff --git a/arch/arm/boot/dts/armada-385-synology-ds116.dts b/arch/arm/boot/dts/armada-385-synology-ds116.dts new file mode 100644 index 000000000000..31510eb56f10 --- /dev/null +++ b/arch/arm/boot/dts/armada-385-synology-ds116.dts @@ -0,0 +1,321 @@ +/* + * Device Tree file for Synology DS116 NAS + * + * Copyright (C) 2017 Willy Tarreau <w@1wt.eu> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "armada-385.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Synology DS116"; + compatible = "marvell,a385-gp", "marvell,armada385", "marvell,armada380"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; /* 1 GB */ + }; + + soc { + ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000 + MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000 + MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000 + MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>; + + internal-regs { + i2c@11000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + clock-frequency = <100000>; + + eeprom@57 { + compatible = "atmel,24c64"; + reg = <0x57>; + }; + }; + + serial@12000 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; + }; + + serial@12100 { + /* A PIC16F1829 is connected to uart1 at 9600 bps, + * and takes single-character orders : + * "1" : power off // already handled by the poweroff node + * "2" : short beep + * "3" : long beep + * "4" : turn the power LED ON + * "5" : flash the power LED + * "6" : turn the power LED OFF + * "7" : turn the status LED OFF + * "8" : turn the status LED ON + * "9" : flash the status LED + * "A" : flash the motherboard LED (D8) + * "B" : turn the motherboard LED OFF + * "C" : hard reset + */ + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "okay"; + }; + + poweroff@12100 { + compatible = "synology,power-off"; + reg = <0x12100 0x100>; + clocks = <&coreclk 0>; + }; + + ethernet@70000 { + pinctrl-names = "default"; + phy = <&phy0>; + phy-mode = "sgmii"; + buffer-manager = <&bm>; + bm,pool-long = <0>; + status = "okay"; + }; + + + mdio@72004 { + pinctrl-names = "default"; + pinctrl-0 = <&mdio_pins>; + + phy0: ethernet-phy@1 { + reg = <1>; + }; + }; + + sata@a8000 { + pinctrl-names = "default"; + pinctrl-0 = <&sata0_pins>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + sata0: sata-port@0 { + reg = <0>; + target-supply = <®_5v_sata0>; + }; + }; + + bm@c8000 { + status = "okay"; + }; + + usb3@f0000 { + usb-phy = <&usb3_0_phy>; + status = "okay"; + }; + + usb3@f8000 { + usb-phy = <&usb3_1_phy>; + status = "okay"; + }; + }; + + bm-bppi { + status = "okay"; + }; + + gpio-fan { + compatible = "gpio-fan"; + gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>, + <&gpio1 17 GPIO_ACTIVE_HIGH>, + <&gpio1 16 GPIO_ACTIVE_HIGH>; + gpio-fan,speed-map = < 0 0 + 1500 1 + 2500 2 + 3000 3 + 3400 4 + 3700 5 + 3900 6 + 4000 7>; + cooling-cells = <2>; + }; + + gpio-leds { + compatible = "gpio-leds"; + + /* The green part is on gpio0.20 which is also used by + * sata0, and accesses to SATA disk 0 make it blink so it + * doesn't need to be declared here. + */ + orange { + gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + label = "ds116:orange:disk"; + default-state = "off"; + }; + }; + }; + + usb3_0_phy: usb3_0_phy { + compatible = "usb-nop-xceiv"; + vcc-supply = <®_usb3_0_vbus>; + }; + + usb3_1_phy: usb3_1_phy { + compatible = "usb-nop-xceiv"; + vcc-supply = <®_usb3_1_vbus>; + }; + + reg_usb3_0_vbus: usb3-vbus0 { + compatible = "regulator-fixed"; + regulator-name = "usb3-vbus0"; + pinctrl-names = "default"; + pinctrl-0 = <&xhci0_vbus_pins>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&gpio1 26 GPIO_ACTIVE_HIGH>; + }; + + reg_usb3_1_vbus: usb3-vbus1 { + compatible = "regulator-fixed"; + regulator-name = "usb3-vbus1"; + pinctrl-names = "default"; + pinctrl-0 = <&xhci1_vbus_pins>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&gpio1 27 GPIO_ACTIVE_HIGH>; + }; + + reg_sata0: pwr-sata0 { + compatible = "regulator-fixed"; + regulator-name = "pwr_en_sata0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + enable-active-high; + regulator-boot-on; + gpio = <&gpio0 15 GPIO_ACTIVE_HIGH>; + }; + + reg_5v_sata0: v5-sata0 { + compatible = "regulator-fixed"; + regulator-name = "v5.0-sata0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_sata0>; + }; + + reg_12v_sata0: v12-sata0 { + compatible = "regulator-fixed"; + regulator-name = "v12.0-sata0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + vin-supply = <®_sata0>; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; + status = "okay"; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "macronix,mx25l6405d", "jedec,spi-nor"; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <50000000>; + m25p,fast-read; + + /* Note: there is a redboot partition table despite u-boot + * being used. The names presented here are the same as those + * found in the FIS directory. There is also a small device + * tree in the last 64kB of the RedBoot partition which is not + * enumerated. The MAC address and the serial number are listed + * in the "vendor" partition. + */ + partition@00000000 { + label = "RedBoot"; + reg = <0x00000000 0x000f0000>; + read-only; + }; + + partition@000c0000 { + label = "zImage"; + reg = <0x000f0000 0x002d0000>; + }; + + partition@00390000 { + label = "rd.gz"; + reg = <0x003c0000 0x00410000>; + }; + + partition@007d0000 { + label = "vendor"; + reg = <0x007d0000 0x00010000>; + read-only; + }; + + partition@007e0000 { + label = "RedBoot config"; + reg = <0x007e0000 0x00010000>; + read-only; + }; + + partition@007f0000 { + label = "FIS directory"; + reg = <0x007f0000 0x00010000>; + read-only; + }; + }; +}; + +&pinctrl { + /* use only one pin for UART1, as mpp20 is used by sata0 */ + uart1_pins: uart-pins-1 { + marvell,pins = "mpp19"; + marvell,function = "ua1"; + }; + + xhci0_vbus_pins: xhci0_vbus_pins { + marvell,pins = "mpp58"; + marvell,function = "gpio"; + }; + xhci1_vbus_pins: xhci1_vbus_pins { + marvell,pins = "mpp59"; + marvell,function = "gpio"; + }; +}; diff --git a/arch/arm/boot/dts/armada-385.dtsi b/arch/arm/boot/dts/armada-385.dtsi index 8e63be33472e..7fcc4c4885cf 100644 --- a/arch/arm/boot/dts/armada-385.dtsi +++ b/arch/arm/boot/dts/armada-385.dtsi @@ -70,13 +70,7 @@ }; soc { - internal-regs { - pinctrl@18000 { - compatible = "marvell,mv88f6820-pinctrl"; - }; - }; - - pcie-controller { + pciec: pcie-controller { compatible = "marvell,armada-370-pcie"; status = "disabled"; device_type = "pci"; @@ -106,7 +100,7 @@ * configured in x4 by the bootloader, then * pcie@4,0 is not available. */ - pcie@1,0 { + pcie1: pcie@1,0 { device_type = "pci"; assigned-addresses = <0x82000800 0 0x80000 0 0x2000>; reg = <0x0800 0 0 0 0>; @@ -124,7 +118,7 @@ }; /* x1 port */ - pcie@2,0 { + pcie2: pcie@2,0 { device_type = "pci"; assigned-addresses = <0x82000800 0 0x40000 0 0x2000>; reg = <0x1000 0 0 0 0>; @@ -142,7 +136,7 @@ }; /* x1 port */ - pcie@3,0 { + pcie3: pcie@3,0 { device_type = "pci"; assigned-addresses = <0x82000800 0 0x44000 0 0x2000>; reg = <0x1800 0 0 0 0>; @@ -163,7 +157,7 @@ * x1 port only available when pcie@1,0 is * configured as a x1 port */ - pcie@4,0 { + pcie4: pcie@4,0 { device_type = "pci"; assigned-addresses = <0x82000800 0 0x48000 0 0x2000>; reg = <0x2000 0 0 0 0>; @@ -182,3 +176,7 @@ }; }; }; + +&pinctrl { + compatible = "marvell,mv88f6820-pinctrl"; +}; diff --git a/arch/arm/boot/dts/armada-388-clearfog.dts b/arch/arm/boot/dts/armada-388-clearfog.dts index 2745b7416313..0d5f1f062275 100644 --- a/arch/arm/boot/dts/armada-388-clearfog.dts +++ b/arch/arm/boot/dts/armada-388-clearfog.dts @@ -186,25 +186,6 @@ }; }; -&pinctrl { - clearfog_dsa0_clk_pins: clearfog-dsa0-clk-pins { - marvell,pins = "mpp46"; - marvell,function = "ref"; - }; - clearfog_dsa0_pins: clearfog-dsa0-pins { - marvell,pins = "mpp23", "mpp41"; - marvell,function = "gpio"; - }; - clearfog_spi1_cs_pins: spi1-cs-pins { - marvell,pins = "mpp55"; - marvell,function = "spi1"; - }; - rear_button_pins: rear-button-pins { - marvell,pins = "mpp34"; - marvell,function = "gpio"; - }; -}; - &mdio { status = "okay"; @@ -268,6 +249,25 @@ }; }; +&pinctrl { + clearfog_dsa0_clk_pins: clearfog-dsa0-clk-pins { + marvell,pins = "mpp46"; + marvell,function = "ref"; + }; + clearfog_dsa0_pins: clearfog-dsa0-pins { + marvell,pins = "mpp23", "mpp41"; + marvell,function = "gpio"; + }; + clearfog_spi1_cs_pins: spi1-cs-pins { + marvell,pins = "mpp55"; + marvell,function = "spi1"; + }; + rear_button_pins: rear-button-pins { + marvell,pins = "mpp34"; + marvell,function = "gpio"; + }; +}; + &spi1 { /* * Add SPI CS pins for clearfog: diff --git a/arch/arm/boot/dts/armada-388.dtsi b/arch/arm/boot/dts/armada-388.dtsi index 564fa5937e25..1c0d151b2aaa 100644 --- a/arch/arm/boot/dts/armada-388.dtsi +++ b/arch/arm/boot/dts/armada-388.dtsi @@ -50,13 +50,8 @@ model = "Marvell Armada 388 family SoC"; compatible = "marvell,armada388", "marvell,armada385", "marvell,armada380"; - soc { internal-regs { - pinctrl@18000 { - compatible = "marvell,mv88f6828-pinctrl"; - }; - sata@e0000 { compatible = "marvell,armada-380-ahci"; reg = <0xe0000 0x2000>; @@ -68,3 +63,7 @@ }; }; }; + +&pinctrl { + compatible = "marvell,mv88f6828-pinctrl"; +}; diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index 79b767507eab..8b165c31de1e 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -82,7 +82,7 @@ reg = <MBUS_ID(0x01, 0x1d) 0 0x200000>; }; - devbus-bootcs { + devbus_bootcs: devbus-bootcs { compatible = "marvell,mvebu-devbus"; reg = <MBUS_ID(0xf0, 0x01) 0x10400 0x8>; ranges = <0 MBUS_ID(0x01, 0x2f) 0 0xffffffff>; @@ -92,7 +92,7 @@ status = "disabled"; }; - devbus-cs0 { + devbus_cs0: devbus-cs0 { compatible = "marvell,mvebu-devbus"; reg = <MBUS_ID(0xf0, 0x01) 0x10408 0x8>; ranges = <0 MBUS_ID(0x01, 0x3e) 0 0xffffffff>; @@ -102,7 +102,7 @@ status = "disabled"; }; - devbus-cs1 { + devbus_cs1: devbus-cs1 { compatible = "marvell,mvebu-devbus"; reg = <MBUS_ID(0xf0, 0x01) 0x10410 0x8>; ranges = <0 MBUS_ID(0x01, 0x3d) 0 0xffffffff>; @@ -112,7 +112,7 @@ status = "disabled"; }; - devbus-cs2 { + devbus_cs2: devbus-cs2 { compatible = "marvell,mvebu-devbus"; reg = <MBUS_ID(0xf0, 0x01) 0x10418 0x8>; ranges = <0 MBUS_ID(0x01, 0x3b) 0 0xffffffff>; @@ -122,7 +122,7 @@ status = "disabled"; }; - devbus-cs3 { + devbus_cs3: devbus-cs3 { compatible = "marvell,mvebu-devbus"; reg = <MBUS_ID(0xf0, 0x01) 0x10420 0x8>; ranges = <0 MBUS_ID(0x01, 0x37) 0 0xffffffff>; @@ -339,7 +339,7 @@ <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; }; - system-controller@18200 { + systemc: system-controller@18200 { compatible = "marvell,armada-380-system-controller", "marvell,armada-370-xp-system-controller"; reg = <0x18200 0x100>; @@ -360,7 +360,8 @@ mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, + <0x20250 0x8>; }; mpic: interrupt-controller@20a00 { @@ -373,7 +374,7 @@ interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>; }; - timer@20300 { + timer: timer@20300 { compatible = "marvell,armada-380-timer", "marvell,armada-xp-timer"; reg = <0x20300 0x30>, <0x21040 0x30>; @@ -387,14 +388,14 @@ clock-names = "nbclk", "fixed"; }; - watchdog@20300 { + watchdog: watchdog@20300 { compatible = "marvell,armada-380-wdt"; reg = <0x20300 0x34>, <0x20704 0x4>, <0x18260 0x4>; clocks = <&coreclk 2>, <&refclk>; clock-names = "nbclk", "fixed"; }; - cpurst@20800 { + cpurst: cpurst@20800 { compatible = "marvell,armada-370-cpu-reset"; reg = <0x20800 0x10>; }; @@ -404,12 +405,12 @@ reg = <0x20d20 0x6c>; }; - coherency-fabric@21010 { + coherencyfab: coherency-fabric@21010 { compatible = "marvell,armada-380-coherency-fabric"; reg = <0x21010 0x1c>; }; - pmsu@22000 { + pmsu: pmsu@22000 { compatible = "marvell,armada-380-pmsu"; reg = <0x22000 0x1000>; }; @@ -451,7 +452,7 @@ status = "disabled"; }; - usb@58000 { + usb0: usb@58000 { compatible = "marvell,orion-ehci"; reg = <0x58000 0x500>; interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>; @@ -459,7 +460,7 @@ status = "disabled"; }; - xor@60800 { + xor0: xor@60800 { compatible = "marvell,armada-380-xor", "marvell,orion-xor"; reg = <0x60800 0x100 0x60a00 0x100>; @@ -479,7 +480,7 @@ }; }; - xor@60900 { + xor1: xor@60900 { compatible = "marvell,armada-380-xor", "marvell,orion-xor"; reg = <0x60900 0x100 0x60b00 0x100>; @@ -507,7 +508,7 @@ clocks = <&gateclk 4>; }; - crypto@90000 { + cesa: crypto@90000 { compatible = "marvell,armada-38x-crypto"; reg = <0x90000 0x10000>; reg-names = "regs"; @@ -522,14 +523,14 @@ marvell,crypto-sram-size = <0x800>; }; - rtc@a3800 { + rtc: rtc@a3800 { compatible = "marvell,armada-380-rtc"; reg = <0xa3800 0x20>, <0x184a0 0x0c>; reg-names = "rtc", "rtc-soc"; interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; }; - sata@a8000 { + ahci0: sata@a8000 { compatible = "marvell,armada-380-ahci"; reg = <0xa8000 0x2000>; interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; @@ -545,7 +546,7 @@ status = "disabled"; }; - sata@e0000 { + ahci1: sata@e0000 { compatible = "marvell,armada-380-ahci"; reg = <0xe0000 0x2000>; interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; @@ -561,13 +562,13 @@ clock-output-names = "nand"; }; - thermal@e8078 { + thermal: thermal@e8078 { compatible = "marvell,armada380-thermal"; reg = <0xe4078 0x4>, <0xe4074 0x4>; status = "okay"; }; - flash@d0000 { + nand: flash@d0000 { compatible = "marvell,armada370-nand"; reg = <0xd0000 0x54>; #address-cells = <1>; @@ -577,7 +578,7 @@ status = "disabled"; }; - sdhci@d8000 { + sdhci: sdhci@d8000 { compatible = "marvell,armada-380-sdhci"; reg-names = "sdhci", "mbus", "conf-sdio3"; reg = <0xd8000 0x1000>, @@ -589,7 +590,7 @@ status = "disabled"; }; - usb3@f0000 { + usb3_0: usb3@f0000 { compatible = "marvell,armada-380-xhci"; reg = <0xf0000 0x4000>,<0xf4000 0x4000>; interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; @@ -597,7 +598,7 @@ status = "disabled"; }; - usb3@f8000 { + usb3_1: usb3@f8000 { compatible = "marvell,armada-380-xhci"; reg = <0xf8000 0x4000>,<0xfc000 0x4000>; interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/armada-xp-98dx3236.dtsi b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi index f6a03dcee5ef..84cc232a29e9 100644 --- a/arch/arm/boot/dts/armada-xp-98dx3236.dtsi +++ b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi @@ -45,11 +45,14 @@ * common to all Armada XP SoCs. */ -#include "armada-xp.dtsi" +#include "armada-370-xp.dtsi" / { + #address-cells = <2>; + #size-cells = <2>; + model = "Marvell 98DX3236 SoC"; - compatible = "marvell,armadaxp-98dx3236", "marvell,armadaxp", "marvell,armada-370-xp"; + compatible = "marvell,armadaxp-98dx3236", "marvell,armada-370-xp"; aliases { gpio0 = &gpio0; @@ -72,12 +75,19 @@ }; soc { + compatible = "marvell,armadaxp-mbus", "simple-bus"; + ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000 MBUS_ID(0x03, 0x00) 0 0 0xa8000000 0x4000000 MBUS_ID(0x08, 0x00) 0 0 0xac000000 0x100000>; + bootrom { + compatible = "marvell,bootrom"; + reg = <MBUS_ID(0x01, 0x1d) 0 0x100000>; + }; + /* * 98DX3236 has 1 x1 PCIe unit Gen2.0 */ @@ -95,8 +105,7 @@ ranges = <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 /* Port 0.0 registers */ 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ - 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */ - 0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */>; + 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */>; pcie1: pcie@1,0 { device_type = "pci"; @@ -117,31 +126,86 @@ }; internal-regs { - coreclk: mvebu-sar@18230 { - compatible = "marvell,mv98dx3236-core-clock"; + sdramc@1400 { + compatible = "marvell,armada-xp-sdram-controller"; + reg = <0x1400 0x500>; + }; + + L2: l2-cache@8000 { + compatible = "marvell,aurora-system-cache"; + reg = <0x08000 0x1000>; + cache-id-part = <0x100>; + cache-level = <2>; + cache-unified; + wt-override; + }; + + gpio0: gpio@18100 { + compatible = "marvell,orion-gpio"; + reg = <0x18100 0x40>; + ngpios = <32>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <82>, <83>, <84>, <85>; + }; + + /* does not exist */ + gpio1: gpio@18140 { + compatible = "marvell,orion-gpio"; + reg = <0x18140 0x40>; + status = "disabled"; + }; + + gpio2: gpio@18180 { /* rework some properties */ + compatible = "marvell,orion-gpio"; + reg = <0x18180 0x40>; + ngpios = <1>; /* only gpio #32 */ + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <87>; + }; + + systemc: system-controller@18200 { + compatible = "marvell,armada-370-xp-system-controller"; + reg = <0x18200 0x500>; + }; + + gateclk: clock-gating-control@18220 { + compatible = "marvell,mv98dx3236-gating-clock"; + reg = <0x18220 0x4>; + clocks = <&coreclk 0>; + #clock-cells = <1>; }; cpuclk: clock-complex@18700 { + #clock-cells = <1>; compatible = "marvell,mv98dx3236-cpu-clock"; + reg = <0x18700 0x24>, <0x1c054 0x10>; + clocks = <&coreclk 1>; }; corediv-clock@18740 { status = "disabled"; }; - xor@60900 { - status = "disabled"; + cpu-config@21000 { + compatible = "marvell,armada-xp-cpu-config"; + reg = <0x21000 0x8>; }; - crypto@90000 { - status = "disabled"; + ethernet@70000 { + compatible = "marvell,armada-xp-neta"; }; - xor@f0900 { - status = "disabled"; + ethernet@74000 { + compatible = "marvell,armada-xp-neta"; }; - xor@f0800 { + xor1: xor@f0800 { compatible = "marvell,orion-xor"; reg = <0xf0800 0x100 0xf0a00 0x100>; @@ -161,45 +225,43 @@ }; }; - gpio0: gpio@18100 { - compatible = "marvell,orion-gpio"; - reg = <0x18100 0x40>; - ngpios = <32>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <82>, <83>, <84>, <85>; - }; - - /* does not exist */ - gpio1: gpio@18140 { - compatible = "marvell,orion-gpio"; - reg = <0x18140 0x40>; - status = "disabled"; + nand: nand@d0000 { + clocks = <&dfx_coredivclk 0>; }; - gpio2: gpio@18180 { /* rework some properties */ - compatible = "marvell,orion-gpio"; - reg = <0x18180 0x40>; - ngpios = <1>; /* only gpio #32 */ - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <87>; - }; + xor0: xor@f0900 { + compatible = "marvell,orion-xor"; + reg = <0xF0900 0x100 + 0xF0B00 0x100>; + clocks = <&gateclk 28>; + status = "okay"; - nand: nand@d0000 { - clocks = <&dfx_coredivclk 0>; + xor00 { + interrupts = <94>; + dmacap,memcpy; + dmacap,xor; + }; + xor01 { + interrupts = <95>; + dmacap,memcpy; + dmacap,xor; + dmacap,memset; + }; }; }; - dfxr: dfx-registers@ac000000 { - compatible = "simple-bus"; + dfx: dfx-server@ac000000 { + compatible = "marvell,dfx-server", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; + reg = <MBUS_ID(0x08, 0x00) 0 0x100000>; + + coreclk: mvebu-sar@f8204 { + compatible = "marvell,mv98dx3236-core-clock"; + reg = <0xf8204 0x4>; + #clock-cells = <1>; + }; dfx_coredivclk: corediv-clock@f8268 { compatible = "marvell,mv98dx3236-corediv-clock"; @@ -208,11 +270,6 @@ clocks = <&mainpll>; clock-output-names = "nand"; }; - - dfx: dfx@0 { - compatible = "marvell,dfx-server"; - reg = <0 0x100000>; - }; }; switch: switch@a8000000 { @@ -229,6 +286,53 @@ }; }; }; + + clocks { + /* 25 MHz reference crystal */ + refclk: oscillator { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + }; +}; + +&i2c0 { + compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c"; + reg = <0x11000 0x100>; +}; + +&i2c1 { + compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c"; + reg = <0x11100 0x100>; +}; + +&mpic { + reg = <0x20a00 0x2d0>, <0x21070 0x58>; +}; + +&timer { + compatible = "marvell,armada-xp-timer"; + clocks = <&coreclk 2>, <&refclk>; + clock-names = "nbclk", "fixed"; +}; + +&watchdog { + compatible = "marvell,armada-xp-wdt"; + clocks = <&coreclk 2>, <&refclk>; + clock-names = "nbclk", "fixed"; +}; + +&cpurst { + reg = <0x20800 0x20>; +}; + +&usb0 { + clocks = <&gateclk 18>; +}; + +&usb1 { + clocks = <&gateclk 19>; }; &pinctrl { @@ -241,14 +345,13 @@ }; }; -&sdio { - status = "disabled"; +&spi0 { + compatible = "marvell,armada-xp-spi", "marvell,orion-spi"; + pinctrl-0 = <&spi0_pins>; + pinctrl-names = "default"; }; -&crypto_sram0 { +&sdio { status = "disabled"; }; -&crypto_sram1 { - status = "disabled"; -}; diff --git a/arch/arm/boot/dts/armada-xp-98dx3336.dtsi b/arch/arm/boot/dts/armada-xp-98dx3336.dtsi index e1580afdc260..a0d81bd7312b 100644 --- a/arch/arm/boot/dts/armada-xp-98dx3336.dtsi +++ b/arch/arm/boot/dts/armada-xp-98dx3336.dtsi @@ -49,7 +49,7 @@ / { model = "Marvell 98DX3336 SoC"; - compatible = "marvell,armadaxp-98dx3336", "marvell,armadaxp-98dx3236", "marvell,armadaxp", "marvell,armada-370-xp"; + compatible = "marvell,armadaxp-98dx3336", "marvell,armadaxp-98dx3236", "marvell,armada-370-xp"; cpus { cpu@1 { diff --git a/arch/arm/boot/dts/armada-xp-98dx4251.dtsi b/arch/arm/boot/dts/armada-xp-98dx4251.dtsi index b9d9b269efb4..51de91b31a9d 100644 --- a/arch/arm/boot/dts/armada-xp-98dx4251.dtsi +++ b/arch/arm/boot/dts/armada-xp-98dx4251.dtsi @@ -49,7 +49,7 @@ / { model = "Marvell 98DX4251 SoC"; - compatible = "marvell,armadaxp-98dx4251", "marvell,armadaxp-98dx3236", "marvell,armadaxp", "marvell,armada-370-xp"; + compatible = "marvell,armadaxp-98dx4251", "marvell,armadaxp-98dx3236", "marvell,armada-370-xp"; cpus { cpu@1 { diff --git a/arch/arm/boot/dts/armada-xp-db-dxbc2.dts b/arch/arm/boot/dts/armada-xp-db-dxbc2.dts index a8130805074e..1b1ff17fdd9c 100644 --- a/arch/arm/boot/dts/armada-xp-db-dxbc2.dts +++ b/arch/arm/boot/dts/armada-xp-db-dxbc2.dts @@ -58,7 +58,7 @@ / { model = "Marvell Bobcat2 Evaluation Board"; - compatible = "marvell,db-dxbc2", "marvell,armadaxp-98dx4251", "marvell,armadaxp", "marvell,armada-370-xp"; + compatible = "marvell,db-dxbc2", "marvell,armadaxp-98dx4251", "marvell,armada-370-xp"; chosen { bootargs = "console=ttyS0,115200 earlyprintk"; diff --git a/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts b/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts index 4e07cb6ed800..06fce35d7491 100644 --- a/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts +++ b/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts @@ -58,7 +58,7 @@ / { model = "DB-XC3-24G4XG"; - compatible = "marvell,db-xc3-24g4xg", "marvell,armadaxp-98dx3336", "marvell,armadaxp", "marvell,armada-370-xp"; + compatible = "marvell,db-xc3-24g4xg", "marvell,armadaxp-98dx3336", "marvell,armada-370-xp"; chosen { bootargs = "console=ttyS0,115200 earlyprintk"; diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts index 42ea8764814c..9efcf59c9b44 100644 --- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts +++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts @@ -71,7 +71,8 @@ ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000 + MBUS_ID(0x0c, 0x04) 0 0 0xf1200000 0x100000>; internal-regs { @@ -95,6 +96,9 @@ pinctrl-names = "default"; status = "okay"; phy-mode = "rgmii-id"; + buffer-manager = <&bm>; + bm,pool-long = <0>; + bm,pool-short = <1>; fixed-link { speed = <1000>; full-duplex; @@ -106,6 +110,9 @@ pinctrl-names = "default"; status = "okay"; phy-mode = "rgmii-id"; + buffer-manager = <&bm>; + bm,pool-long = <2>; + bm,pool-short = <3>; fixed-link { speed = <1000>; full-duplex; @@ -156,6 +163,7 @@ esata@4 { label = "mamba:white:esata"; reg = <0x4>; + linux,default-trigger = "disk-activity"; }; usb2@5 { @@ -185,6 +193,10 @@ }; }; + bm@c8000 { + status = "okay"; + }; + nand@d0000 { status = "okay"; num-cs = <1>; @@ -258,6 +270,10 @@ }; }; }; + + bm-bppi { + status = "okay"; + }; }; gpio_keys { diff --git a/arch/arm/boot/dts/aspeed-ast2500-evb.dts b/arch/arm/boot/dts/aspeed-ast2500-evb.dts index d967603dade8..7c90dac99822 100644 --- a/arch/arm/boot/dts/aspeed-ast2500-evb.dts +++ b/arch/arm/boot/dts/aspeed-ast2500-evb.dts @@ -20,6 +20,28 @@ }; }; +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + }; +}; + +&spi1 { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "pnor"; + }; +}; + +&spi2 { + status = "okay"; +}; + &uart5 { status = "okay"; }; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts index 1d2fc1e1dc29..112551766275 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts @@ -31,6 +31,24 @@ }; }; +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + }; +}; + +&spi { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "pnor"; + }; +}; + &uart5 { status = "okay"; }; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts index 7a3b2b50c884..1190fec1b5d0 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts @@ -31,6 +31,42 @@ }; }; +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "pnor"; + }; +}; + +&uart1 { + /* Rear RS-232 connector */ + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default + &pinctrl_nrts1_default + &pinctrl_ndtr1_default + &pinctrl_ndsr1_default + &pinctrl_ncts1_default + &pinctrl_ndcd1_default + &pinctrl_nri1_default>; +}; + &uart5 { status = "okay"; }; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index c79c937b0a8a..8c6bc29eb7f6 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -18,21 +18,41 @@ }; }; - clocks { - clk_clkin: clk_clkin { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <48000000>; - }; - - }; - ahb { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges; + fmc: flash-controller@1e620000 { + reg = < 0x1e620000 0x94 + 0x20000000 0x02000000 >; + #address-cells = <1>; + #size-cells = <0>; + compatible = "aspeed,ast2400-fmc"; + status = "disabled"; + interrupts = <19>; + flash@0 { + reg = < 0 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + }; + + spi: flash-controller@1e630000 { + reg = < 0x1e630000 0x18 + 0x30000000 0x02000000 >; + #address-cells = <1>; + #size-cells = <0>; + compatible = "aspeed,ast2400-spi"; + status = "disabled"; + flash@0 { + reg = < 0 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + }; + vic: interrupt-controller@1e6c0080 { compatible = "aspeed,ast2400-vic"; interrupt-controller; @@ -61,16 +81,48 @@ #size-cells = <1>; ranges; - clk_hpll: clk_hpll@1e6e2070 { - #clock-cells = <0>; - compatible = "aspeed,g4-hpll-clock"; - reg = <0x1e6e2070 0x4>; - clocks = <&clk_clkin>; - }; - syscon: syscon@1e6e2000 { compatible = "aspeed,g4-scu", "syscon", "simple-mfd"; reg = <0x1e6e2000 0x1a8>; + #address-cells = <1>; + #size-cells = <0>; + + clk_clkin: clk_clkin { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <48000000>; + }; + + clk_hpll: clk_hpll@70 { + #clock-cells = <0>; + compatible = "aspeed,g4-hpll-clock", "fixed-clock"; + reg = <0x70>; + clocks = <&clk_clkin>; + clock-frequency = <384000000>; + }; + + clk_ahb: clk_ahb@70 { + #clock-cells = <0>; + compatible = "aspeed,g4-ahb-clock", "fixed-clock"; + reg = <0x70>; + clocks = <&clk_hpll>; + clock-frequency = <192000000>; + }; + + clk_apb: clk_apb@08 { + #clock-cells = <0>; + compatible = "aspeed,g4-apb-clock", "fixed-clock"; + reg = <0x08>; + clocks = <&clk_hpll>; + clock-frequency = <48000000>; + }; + + clk_uart: clk_uart@2c{ + #clock-cells = <0>; + compatible = "aspeed,g4-uart-clock", "fixed-clock"; + reg = <0x2c>; + clock-frequency = <24000000>; + }; pinctrl: pinctrl { compatible = "aspeed,g4-pinctrl"; @@ -818,19 +870,6 @@ }; }; - clk_apb: clk_apb@1e6e2008 { - #clock-cells = <0>; - compatible = "aspeed,g4-apb-clock"; - reg = <0x1e6e2008 0x4>; - clocks = <&clk_hpll>; - }; - - clk_uart: clk_uart@1e6e2008 { - #clock-cells = <0>; - compatible = "aspeed,uart-clock"; - reg = <0x1e6e202c 0x4>; - }; - sram@1e720000 { compatible = "mmio-sram"; reg = <0x1e720000 0x8000>; // 32K @@ -857,13 +896,13 @@ }; wdt1: wdt@1e785000 { - compatible = "aspeed,wdt"; + compatible = "aspeed,ast2400-wdt"; reg = <0x1e785000 0x1c>; interrupts = <27>; }; wdt2: wdt@1e785020 { - compatible = "aspeed,wdt"; + compatible = "aspeed,ast2400-wdt"; reg = <0x1e785020 0x1c>; interrupts = <27>; clocks = <&clk_apb>; @@ -930,6 +969,14 @@ no-loopback-test; status = "disabled"; }; + + adc: adc@1e6e9000 { + compatible = "aspeed,ast2400-adc"; + reg = <0x1e6e9000 0xb0>; + clocks = <&clk_apb>; + #io-channel-cells = <1>; + status = "disabled"; + }; }; }; }; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index b6596633036c..a0bea4a6ec77 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -24,6 +24,69 @@ #size-cells = <1>; ranges; + fmc: flash-controller@1e620000 { + reg = < 0x1e620000 0xc4 + 0x20000000 0x10000000 >; + #address-cells = <1>; + #size-cells = <0>; + compatible = "aspeed,ast2500-fmc"; + status = "disabled"; + interrupts = <19>; + flash@0 { + reg = < 0 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + flash@1 { + reg = < 1 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + flash@2 { + reg = < 2 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + }; + + spi1: flash-controller@1e630000 { + reg = < 0x1e630000 0xc4 + 0x30000000 0x08000000 >; + #address-cells = <1>; + #size-cells = <0>; + compatible = "aspeed,ast2500-spi"; + status = "disabled"; + flash@0 { + reg = < 0 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + flash@1 { + reg = < 1 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + }; + + spi2: flash-controller@1e631000 { + reg = < 0x1e631000 0xc4 + 0x38000000 0x08000000 >; + #address-cells = <1>; + #size-cells = <0>; + compatible = "aspeed,ast2500-spi"; + status = "disabled"; + flash@0 { + reg = < 0 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + flash@1 { + reg = < 1 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + }; + vic: interrupt-controller@1e6c0080 { compatible = "aspeed,ast2400-vic"; interrupt-controller; @@ -52,15 +115,49 @@ #size-cells = <1>; ranges; - clk_clkin: clk_clkin@1e6e2070 { - #clock-cells = <0>; - compatible = "aspeed,g5-clkin-clock"; - reg = <0x1e6e2070 0x04>; - }; - syscon: syscon@1e6e2000 { compatible = "aspeed,g5-scu", "syscon", "simple-mfd"; reg = <0x1e6e2000 0x1a8>; + #address-cells = <1>; + #size-cells = <0>; + + clk_clkin: clk_clkin@70 { + #clock-cells = <0>; + compatible = "aspeed,g5-clkin-clock", "fixed-clock"; + reg = <0x70>; + clock-frequency = <24000000>; + }; + + clk_hpll: clk_hpll@24 { + #clock-cells = <0>; + compatible = "aspeed,g5-hpll-clock", "fixed-clock"; + reg = <0x24>; + clocks = <&clk_clkin>; + clock-frequency = <792000000>; + }; + + clk_ahb: clk_ahb@70 { + #clock-cells = <0>; + compatible = "aspeed,g5-ahb-clock", "fixed-clock"; + reg = <0x70>; + clocks = <&clk_hpll>; + clock-frequency = <198000000>; + }; + + clk_apb: clk_apb@08 { + #clock-cells = <0>; + compatible = "aspeed,g5-apb-clock", "fixed-clock"; + reg = <0x08>; + clocks = <&clk_hpll>; + clock-frequency = <24750000>; + }; + + clk_uart: clk_uart@2c { + #clock-cells = <0>; + compatible = "aspeed,uart-clock", "fixed-clock"; + reg = <0x2c>; + clock-frequency = <24000000>; + }; pinctrl: pinctrl { compatible = "aspeed,g5-pinctrl"; @@ -285,7 +382,6 @@ function = "LAD0"; groups = "LAD0"; }; - pinctrl_lad1_default: lad1_default { function = "LAD1"; groups = "LAD1"; @@ -872,33 +968,7 @@ }; }; - }; - - clk_hpll: clk_hpll@1e6e2024 { - #clock-cells = <0>; - compatible = "aspeed,g5-hpll-clock"; - reg = <0x1e6e2024 0x4>; - clocks = <&clk_clkin>; - }; - - clk_ahb: clk_ahb@1e6e2070 { - #clock-cells = <0>; - compatible = "aspeed,g5-ahb-clock"; - reg = <0x1e6e2070 0x4>; - clocks = <&clk_hpll>; - }; - clk_apb: clk_apb@1e6e2008 { - #clock-cells = <0>; - compatible = "aspeed,g5-apb-clock"; - reg = <0x1e6e2008 0x4>; - clocks = <&clk_hpll>; - }; - - clk_uart: clk_uart@1e6e2008 { - #clock-cells = <0>; - compatible = "aspeed,uart-clock"; - reg = <0x1e6e202c 0x4>; }; gfx: display@1e6e6000 { @@ -934,21 +1004,21 @@ wdt1: wdt@1e785000 { - compatible = "aspeed,wdt"; - reg = <0x1e785000 0x1c>; + compatible = "aspeed,ast2500-wdt"; + reg = <0x1e785000 0x20>; interrupts = <27>; }; wdt2: wdt@1e785020 { - compatible = "aspeed,wdt"; - reg = <0x1e785020 0x1c>; + compatible = "aspeed,ast2500-wdt"; + reg = <0x1e785020 0x20>; interrupts = <27>; status = "disabled"; }; wdt3: wdt@1e785040 { - compatible = "aspeed,wdt"; - reg = <0x1e785074 0x1c>; + compatible = "aspeed,ast2500-wdt"; + reg = <0x1e785040 0x20>; status = "disabled"; }; @@ -1042,6 +1112,14 @@ no-loopback-test; status = "disabled"; }; + + adc: adc@1e6e9000 { + compatible = "aspeed,ast2500-adc"; + reg = <0x1e6e9000 0xb0>; + clocks = <&clk_apb>; + #io-channel-cells = <1>; + status = "disabled"; + }; }; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 9f7f8a7d8ff9..0bef9e0b89c6 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -246,6 +246,7 @@ shdwc@f8048010 { atmel,shdwc-debouncer = <976>; + atmel,wakeup-rtc-timer; input@0 { reg = <0>; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts index c51fc652f6c7..5a53fcf542ab 100644 --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -162,9 +162,10 @@ }; adc0: adc@f8018000 { + atmel,adc-vref = <3300>; + atmel,adc-channels-used = <0xfe>; pinctrl-0 = < &pinctrl_adc0_adtrg - &pinctrl_adc0_ad0 &pinctrl_adc0_ad1 &pinctrl_adc0_ad2 &pinctrl_adc0_ad3 @@ -172,8 +173,6 @@ &pinctrl_adc0_ad5 &pinctrl_adc0_ad6 &pinctrl_adc0_ad7 - &pinctrl_adc0_ad8 - &pinctrl_adc0_ad9 >; status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-tse850-3.dts b/arch/arm/boot/dts/at91-tse850-3.dts index 669a2c6bdefc..498fba3e52b5 100644 --- a/arch/arm/boot/dts/at91-tse850-3.dts +++ b/arch/arm/boot/dts/at91-tse850-3.dts @@ -86,16 +86,43 @@ #io-channel-cells = <1>; }; - envelope-detector { + env_det: envelope-detector { compatible = "axentia,tse850-envelope-detector"; io-channels = <&dac 0>; io-channel-names = "dac"; + #io-channel-cells = <1>; interrupt-parent = <&pioA>; interrupts = <3 IRQ_TYPE_EDGE_RISING>; interrupt-names = "comp"; }; + mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>, + <&pioA 1 GPIO_ACTIVE_HIGH>, + <&pioA 2 GPIO_ACTIVE_HIGH>; + idle-state = <0>; + }; + + envelope-detector-mux { + compatible = "io-channel-mux"; + io-channels = <&env_det 0>; + io-channel-names = "parent"; + + mux-controls = <&mux>; + + channels = "", "", + "sync-1", + "in", + "out", + "sync-2", + "sys-reg", + "ana-reg"; + }; + leds { compatible = "gpio-leds"; diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi index 3fe77c38bd0d..7e80acda8f69 100644 --- a/arch/arm/boot/dts/at91sam9261.dtsi +++ b/arch/arm/boot/dts/at91sam9261.dtsi @@ -263,7 +263,7 @@ }; matrix: matrix@ffffee00 { - compatible = "atmel,at91sam9260-bus-matrix", "syscon"; + compatible = "atmel,at91sam9261-matrix", "syscon"; reg = <0xffffee00 0x200>; }; diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi index 696b8ba064a6..9d2bbc41a7b0 100644 --- a/arch/arm/boot/dts/at91sam9x5ek.dtsi +++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi @@ -116,7 +116,7 @@ }; spi0: spi@f0000000 { - status = "okay"; + status = "disabled"; /* conflicts with mmc1 */ cs-gpios = <&pioA 14 0>, <0>, <0>, <0>; m25p80@0 { compatible = "atmel,at25df321a"; diff --git a/arch/arm/boot/dts/axp209.dtsi b/arch/arm/boot/dts/axp209.dtsi index 675bb0f30825..9677dd5cf6b6 100644 --- a/arch/arm/boot/dts/axp209.dtsi +++ b/arch/arm/boot/dts/axp209.dtsi @@ -53,6 +53,11 @@ interrupt-controller; #interrupt-cells = <1>; + ac_power_supply: ac-power-supply { + compatible = "x-powers,axp202-ac-power-supply"; + status = "disabled"; + }; + axp_gpio: gpio { compatible = "x-powers,axp209-gpio"; gpio-controller; diff --git a/arch/arm/boot/dts/axp22x.dtsi b/arch/arm/boot/dts/axp22x.dtsi index 458b6681e3ec..67331c5f1714 100644 --- a/arch/arm/boot/dts/axp22x.dtsi +++ b/arch/arm/boot/dts/axp22x.dtsi @@ -52,6 +52,11 @@ interrupt-controller; #interrupt-cells = <1>; + ac_power_supply: ac-power-supply { + compatible = "x-powers,axp221-ac-power-supply"; + status = "disabled"; + }; + regulators { /* Default work frequency for buck regulators */ x-powers,dcdc-freq = <3000>; diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi index 8833a4c3cd96..9644fddb5e3c 100644 --- a/arch/arm/boot/dts/bcm-cygnus.dtsi +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi @@ -205,7 +205,7 @@ status = "disabled"; msi-parent = <&msi0>; - msi0: msi@18012000 { + msi0: msi-controller { compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; @@ -240,7 +240,7 @@ status = "disabled"; msi-parent = <&msi1>; - msi1: msi@18013000 { + msi1: msi-controller { compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi index 832795b0fd0f..fe6cba994a97 100644 --- a/arch/arm/boot/dts/bcm-nsp.dtsi +++ b/arch/arm/boot/dts/bcm-nsp.dtsi @@ -245,6 +245,15 @@ status = "disabled"; }; + mailbox: mailbox@25000 { + compatible = "brcm,iproc-fa2-mbox"; + reg = <0x25000 0x445>; + interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>; + #mbox-cells = <1>; + brcm,rx-status-len = <32>; + brcm,use-bcm-hdr; + }; + nand: nand@26000 { compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1"; reg = <0x026000 0x600>, @@ -288,6 +297,12 @@ #size-cells = <0>; }; + crypto@2f000 { + compatible = "brcm,spum-nsp-crypto"; + reg = <0x2f000 0x900>; + mboxes = <&mailbox 0>; + }; + gpiob: gpio@30000 { compatible = "brcm,iproc-nsp-gpio", "brcm,iproc-gpio"; reg = <0x30000 0x50>; @@ -306,6 +321,20 @@ status = "disabled"; }; + ehci0: usb@2a000 { + compatible = "generic-ehci"; + reg = <0x2a000 0x100>; + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + ohci0: usb@2b000 { + compatible = "generic-ohci"; + reg = <0x2b000 0x100>; + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + rng: rng@33000 { compatible = "brcm,bcm-nsp-rng"; reg = <0x33000 0x14>; @@ -347,6 +376,7 @@ #size-cells = <0>; interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>; clock-frequency = <100000>; + status = "disabled"; }; watchdog@39000 { @@ -450,7 +480,7 @@ status = "disabled"; msi-parent = <&msi0>; - msi0: msi@18012000 { + msi0: msi-controller { compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; @@ -486,7 +516,7 @@ status = "disabled"; msi-parent = <&msi1>; - msi1: msi@18013000 { + msi1: msi-controller { compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; @@ -522,7 +552,7 @@ status = "disabled"; msi-parent = <&msi2>; - msi2: msi@18014000 { + msi2: msi-controller { compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi index 38e6050035bc..a7b5ce133784 100644 --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi @@ -69,6 +69,12 @@ bus-width = <4>; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; +}; + &pwm { pinctrl-names = "default"; pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>; @@ -92,3 +98,11 @@ power-domains = <&power RPI_POWER_DOMAIN_VEC>; status = "okay"; }; + +&dsi0 { + power-domains = <&power RPI_POWER_DOMAIN_DSI0>; +}; + +&dsi1 { + power-domains = <&power RPI_POWER_DOMAIN_DSI1>; +}; diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index a3106aa446c6..35cea3fcaf5c 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -93,10 +93,13 @@ #clock-cells = <1>; reg = <0x7e101000 0x2000>; - /* CPRMAN derives everything from the platform's - * oscillator. + /* CPRMAN derives almost everything from the + * platform's oscillator. However, the DSI + * pixel clocks come from the DSI analog PHY. */ - clocks = <&clk_osc>; + clocks = <&clk_osc>, + <&dsi0 0>, <&dsi0 1>, <&dsi0 2>, + <&dsi1 0>, <&dsi1 1>, <&dsi1 2>; }; rng@7e104000 { @@ -347,6 +350,16 @@ arm,primecell-periphid = <0x00241011>; }; + sdhost: mmc@7e202000 { + compatible = "brcm,bcm2835-sdhost"; + reg = <0x7e202000 0x100>; + interrupts = <2 24>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + dmas = <&dma 13>; + dma-names = "rx-tx"; + status = "disabled"; + }; + i2s: i2s@7e203000 { compatible = "brcm,bcm2835-i2s"; reg = <0x7e203000 0x20>, @@ -390,6 +403,25 @@ interrupts = <2 14>; /* pwa1 */ }; + dsi0: dsi@7e209000 { + compatible = "brcm,bcm2835-dsi0"; + reg = <0x7e209000 0x78>; + interrupts = <2 4>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + + clocks = <&clocks BCM2835_PLLA_DSI0>, + <&clocks BCM2835_CLOCK_DSI0E>, + <&clocks BCM2835_CLOCK_DSI0P>; + clock-names = "phy", "escape", "pixel"; + + clock-output-names = "dsi0_byte", + "dsi0_ddr2", + "dsi0_ddr"; + + }; + thermal: thermal@7e212000 { compatible = "brcm,bcm2835-thermal"; reg = <0x7e212000 0x8>; @@ -456,6 +488,26 @@ interrupts = <2 1>; }; + dsi1: dsi@7e700000 { + compatible = "brcm,bcm2835-dsi1"; + reg = <0x7e700000 0x8c>; + interrupts = <2 12>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + + clocks = <&clocks BCM2835_PLLD_DSI1>, + <&clocks BCM2835_CLOCK_DSI1E>, + <&clocks BCM2835_CLOCK_DSI1P>; + clock-names = "phy", "escape", "pixel"; + + clock-output-names = "dsi1_byte", + "dsi1_ddr2", + "dsi1_ddr"; + + status = "disabled"; + }; + i2c1: i2c@7e804000 { compatible = "brcm,bcm2835-i2c"; reg = <0x7e804000 0x1000>; @@ -499,6 +551,8 @@ clocks = <&clocks BCM2835_PLLH_PIX>, <&clocks BCM2835_CLOCK_HSM>; clock-names = "pixel", "hdmi"; + dmas = <&dma 17>; + dma-names = "audio-rx"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts index d241cee4bfcc..4175174e589a 100644 --- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts +++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2015 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -31,19 +41,16 @@ usb3 { label = "bcm53xx:blue:usb3"; gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wan { label = "bcm53xx:blue:wan"; gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; lan { label = "bcm53xx:blue:lan"; gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; power { @@ -61,14 +68,12 @@ 2ghz { label = "bcm53xx:blue:2ghz"; gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb2 { label = "bcm53xx:blue:usb2"; gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts index b0e62042f62f..8fa033fea959 100644 --- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts +++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2015 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -31,7 +41,6 @@ usb2 { label = "bcm53xx:blue:usb2"; gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; power { @@ -49,7 +58,6 @@ usb3 { label = "bcm53xx:blue:usb3"; gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts index c9ba6b964b38..62e1427b3f10 100644 --- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts +++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts @@ -52,13 +52,11 @@ usb { label = "bcm53xx:blue:usb"; gpios = <&hc595 0 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; power0 { label = "bcm53xx:red:power"; gpios = <&hc595 1 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; power1 { @@ -76,7 +74,6 @@ router1 { label = "bcm53xx:amber:router"; gpios = <&hc595 4 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan { @@ -88,13 +85,11 @@ wireless0 { label = "bcm53xx:blue:wireless"; gpios = <&hc595 6 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wireless1 { label = "bcm53xx:amber:wireless"; gpios = <&hc595 7 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts new file mode 100644 index 000000000000..126ab5867772 --- /dev/null +++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> + * + * Licensed under the ISC license. + */ + +/dts-v1/; + +#include "bcm4708.dtsi" +#include "bcm5301x-nand-cs0-bch8.dtsi" + +/ { + compatible = "linksys,ea6300-v1", "brcm,bcm4708"; + model = "Linksys EA6300 V1"; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + memory { + reg = <0x00000000 0x08000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + wps { + label = "WPS"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>; + }; + + restart { + label = "Reset"; + linux,code = <KEY_RESTART>; + gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>; + }; + }; +}; diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts index b9f66c0fae27..a5647efe4118 100644 --- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts +++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts @@ -43,19 +43,16 @@ power1 { label = "bcm53xx:amber:power"; gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb { label = "bcm53xx:blue:usb"; gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wireless { label = "bcm53xx:blue:wireless"; gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts index ae0199f6c7a2..bb66cebe0bd8 100644 --- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts +++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2014 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -37,7 +47,6 @@ power0 { label = "bcm53xx:green:power"; gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; power1 { @@ -49,13 +58,11 @@ usb { label = "bcm53xx:blue:usb"; gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wireless { label = "bcm53xx:blue:wireless"; gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts index 36b628b190d7..19ee924d7d53 100644 --- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts +++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts @@ -37,61 +37,51 @@ power-amber { label = "bcm53xx:amber:power"; gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; usb2 { label = "bcm53xx:white:usb2"; gpios = <&chipcommon 3 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; usb3-white { label = "bcm53xx:white:usb3"; gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; usb3-green { label = "bcm53xx:green:usb3"; gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wps { label = "bcm53xx:white:wps"; gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; status-red { label = "bcm53xx:red:status"; gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; status-green { label = "bcm53xx:green:status"; gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; status-blue { label = "bcm53xx:blue:status"; gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan-white { label = "bcm53xx:white:wan"; gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan-red { label = "bcm53xx:red:wan"; gpios = <&chipcommon 13 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi index d0eec099f1f8..1a19e97a987d 100644 --- a/arch/arm/boot/dts/bcm4708.dtsi +++ b/arch/arm/boot/dts/bcm4708.dtsi @@ -12,6 +12,14 @@ / { compatible = "brcm,bcm4708"; + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts index db8608be0ee7..0800a964f2fe 100644 --- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts +++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2014 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -37,7 +47,6 @@ usb2 { label = "bcm53xx:blue:usb2"; gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wan { @@ -55,7 +64,6 @@ usb3 { label = "bcm53xx:blue:usb3"; gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts index d51586d95b9a..c2af33eb47de 100644 --- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts +++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2014 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -58,7 +68,6 @@ power1 { label = "bcm53xx:red:power"; gpios = <&hc595 2 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; router0 { @@ -70,7 +79,6 @@ router1 { label = "bcm53xx:amber:router"; gpios = <&hc595 4 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan { @@ -82,13 +90,11 @@ wireless0 { label = "bcm53xx:green:wireless"; gpios = <&hc595 6 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wireless1 { label = "bcm53xx:amber:wireless"; gpios = <&hc595 7 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts index de041b8c3342..8bef6429feee 100644 --- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts +++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2015 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; diff --git a/arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts b/arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts new file mode 100644 index 000000000000..a854a5174b7f --- /dev/null +++ b/arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2017 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> + * + * Licensed under the ISC license. + */ + +/dts-v1/; + +#include "bcm47081.dtsi" + +/ { + compatible = "tplink,archer-c5-v2", "brcm,bcm47081", "brcm,bcm4708"; + model = "TP-LINK Archer C5 V2"; + + chosen { + bootargs = "earlycon"; + }; + + memory { + reg = <0x00000000 0x08000000>; + }; + + leds { + compatible = "gpio-leds"; + + 2ghz { + label = "bcm53xx:green:2ghz"; + gpios = <&chipcommon 0 GPIO_ACTIVE_HIGH>; + }; + + lan { + label = "bcm53xx:green:lan"; + gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>; + }; + + usb2-port1 { + label = "bcm53xx:green:usb2-port1"; + gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>; + }; + + power { + label = "bcm53xx:green:power"; + gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + wan-green { + label = "bcm53xx:green:wan"; + gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "bcm53xx:green:wps"; + gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>; + }; + + wan-amber { + label = "bcm53xx:amber:wan"; + gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>; + }; + + 5ghz { + label = "bcm53xx:green:5ghz"; + gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>; + }; + + usb2-port2 { + label = "bcm53xx:green:usb2-port2"; + gpios = <&chipcommon 13 GPIO_ACTIVE_HIGH>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + rfkill { + label = "WiFi"; + linux,code = <KEY_RFKILL>; + gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; + }; + + restart { + label = "Reset"; + linux,code = <KEY_RESTART>; + gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&spi_nor { + status = "okay"; +}; + +&usb2 { + vcc-gpio = <&chipcommon 9 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm/boot/dts/bcm47081.dtsi b/arch/arm/boot/dts/bcm47081.dtsi index c5f7619af4a6..9829d044aaf4 100644 --- a/arch/arm/boot/dts/bcm47081.dtsi +++ b/arch/arm/boot/dts/bcm47081.dtsi @@ -4,7 +4,17 @@ * * Copyright © 2014 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ #include "bcm5301x.dtsi" @@ -12,6 +22,14 @@ / { compatible = "brcm,bcm47081"; + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts index eaca6876db0f..df473cc41572 100644 --- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts +++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2015 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -31,7 +41,6 @@ wps { label = "bcm53xx:blue:wps"; gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; power { @@ -43,7 +52,6 @@ wan { label = "bcm53xx:red:wan"; gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts index b32957ca9443..92058c73ee59 100644 --- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts +++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts @@ -31,13 +31,11 @@ usb { label = "bcm53xx:green:usb"; gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; power-amber { label = "bcm53xx:amber:power"; gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; power-white { @@ -49,37 +47,31 @@ router-amber { label = "bcm53xx:amber:router"; gpios = <&chipcommon 7 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; router-white { label = "bcm53xx:white:router"; gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan-amber { label = "bcm53xx:amber:wan"; gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan-white { label = "bcm53xx:white:wan"; gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wireless-amber { label = "bcm53xx:amber:wireless"; gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wireless-white { label = "bcm53xx:white:wireless"; gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts b/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts new file mode 100644 index 000000000000..3d1d9c2c4efc --- /dev/null +++ b/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> + * + * Licensed under the ISC license. + */ + +/dts-v1/; + +#include "bcm4709.dtsi" +#include "bcm5301x-nand-cs0-bch8.dtsi" + +/ { + compatible = "linksys,ea9200", "brcm,bcm4709", "brcm,bcm4708"; + model = "Linksys EA9200"; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + memory { + reg = <0x00000000 0x08000000 + 0x88000000 0x08000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + wps { + label = "WPS"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; + }; + + restart { + label = "Reset"; + linux,code = <KEY_RESTART>; + gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>; + }; + }; +}; diff --git a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts index f459a98a72c6..f43ab4721456 100644 --- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts +++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2015 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -37,43 +47,36 @@ power-amber { label = "bcm53xx:amber:power"; gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 5ghz { label = "bcm53xx:white:5ghz"; gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 2ghz { label = "bcm53xx:white:2ghz"; gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wps { label = "bcm53xx:white:wps"; gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wireless { label = "bcm53xx:white:wireless"; gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; usb3 { label = "bcm53xx:white:usb3"; gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb2 { label = "bcm53xx:white:usb2"; gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts index 8e39a84e5bf9..d266131652ad 100644 --- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts +++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2015 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -28,58 +38,61 @@ leds { compatible = "gpio-leds"; - power0 { + power-white { label = "bcm53xx:white:power"; gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>; linux,default-trigger = "default-on"; }; - power1 { + power-amber { label = "bcm53xx:amber:power"; gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; + }; + + wan-white { + label = "bcm53xx:white:wan"; + gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>; + linux,default-trigger = "default-on"; + }; + + wan-amber { + label = "bcm53xx:amber:wan"; + gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>; }; 5ghz-1 { label = "bcm53xx:white:5ghz-1"; gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 2ghz { label = "bcm53xx:white:2ghz"; gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wireless { label = "bcm53xx:white:wireless"; gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wps { label = "bcm53xx:white:wps"; gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; 5ghz-2 { label = "bcm53xx:white:5ghz-2"; gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb3 { label = "bcm53xx:white:usb3"; gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb2 { label = "bcm53xx:white:usb2"; gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; @@ -105,6 +118,12 @@ linux,code = <KEY_RESTART>; gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>; }; + + brightness { + label = "Backlight"; + linux,code = <KEY_BRIGHTNESS_ZERO>; + gpios = <&chipcommon 19 GPIO_ACTIVE_LOW>; + }; }; }; diff --git a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts index c67bfaa0c8e8..97aa5d59a1d8 100644 --- a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts +++ b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts @@ -26,49 +26,41 @@ lan { label = "bcm53xx:blue:lan"; gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wps { label = "bcm53xx:blue:wps"; gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; 2ghz { label = "bcm53xx:blue:2ghz"; gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; 5ghz { label = "bcm53xx:blue:5ghz"; gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; usb3 { label = "bcm53xx:blue:usb3"; gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; usb2 { label = "bcm53xx:blue:usb2"; gpios = <&chipcommon 7 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan-blue { label = "bcm53xx:blue:wan"; gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wan-amber { label = "bcm53xx:amber:wan"; gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; power { diff --git a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts index 64ded7643e9f..51b0641b5f79 100644 --- a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts +++ b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts @@ -4,7 +4,17 @@ * * Copyright (C) 2016 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> * - * Licensed under the GNU/GPL. See COPYING for details. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ /dts-v1/; @@ -46,37 +56,31 @@ wan-white { label = "bcm53xx:white:wan"; gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; power-amber { label = "bcm53xx:amber:power"; gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wan-amber { label = "bcm53xx:amber:wan"; gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb3-white { label = "bcm53xx:white:usb3"; gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 2ghz { label = "bcm53xx:white:2ghz"; gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 5ghz { label = "bcm53xx:white:5ghz"; gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts new file mode 100644 index 000000000000..b6750f70dffb --- /dev/null +++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> + * + * Licensed under the ISC license. + */ + +/dts-v1/; + +#include "bcm47094.dtsi" +#include "bcm5301x-nand-cs0-bch8.dtsi" + +/ { + compatible = "linksys,panamera", "brcm,bcm47094", "brcm,bcm4708"; + model = "Linksys EA9500"; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + memory { + reg = <0x00000000 0x08000000 + 0x88000000 0x08000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + wps { + label = "WPS"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; + }; + }; +}; diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts index 5cf4ab1ebe85..5f8621d00c50 100644 --- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts +++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts @@ -34,37 +34,31 @@ lan3 { label = "bcm53xx:green:lan3"; gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; lan4 { label = "bcm53xx:green:lan4"; gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; wan { label = "bcm53xx:green:wan"; gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; lan1 { label = "bcm53xx:green:lan1"; gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; lan2 { label = "bcm53xx:green:lan2"; gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb3 { label = "bcm53xx:green:usb3"; gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; status { @@ -76,13 +70,11 @@ 2ghz { label = "bcm53xx:green:2ghz"; gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 5ghz { label = "bcm53xx:green:5ghz"; gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts index 600795ee1aed..859929973158 100644 --- a/arch/arm/boot/dts/bcm47094-netgear-r8500.dts +++ b/arch/arm/boot/dts/bcm47094-netgear-r8500.dts @@ -34,37 +34,31 @@ power1 { label = "bcm53xx:amber:power"; gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 5ghz-1 { label = "bcm53xx:white:5ghz-1"; gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 5ghz-2 { label = "bcm53xx:white:5ghz-2"; gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; 2ghz { label = "bcm53xx:white:2ghz"; gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb2 { label = "bcm53xx:white:usb2"; gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; usb3 { label = "bcm53xx:white:usb3"; gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-off"; }; }; diff --git a/arch/arm/boot/dts/bcm47189-tenda-ac9.dts b/arch/arm/boot/dts/bcm47189-tenda-ac9.dts index 4403ae8790c2..34417dac1cd0 100644 --- a/arch/arm/boot/dts/bcm47189-tenda-ac9.dts +++ b/arch/arm/boot/dts/bcm47189-tenda-ac9.dts @@ -26,19 +26,16 @@ usb { label = "bcm53xx:blue:usb"; gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; wps { label = "bcm53xx:blue:wps"; gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; 5ghz { label = "bcm53xx:blue:5ghz"; gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-off"; }; system { @@ -48,6 +45,15 @@ }; }; + pcie0_leds { + compatible = "gpio-leds"; + + 2ghz { + label = "bcm53xx:blue:2ghz"; + gpios = <&pcie0_chipcommon 3 GPIO_ACTIVE_HIGH>; + }; + }; + gpio-keys { compatible = "gpio-keys"; #address-cells = <1>; @@ -72,3 +78,30 @@ }; }; }; + +&pcie0 { + ranges = <0x00000000 0 0 0 0 0x00100000>; + #address-cells = <3>; + #size-cells = <2>; + + bridge@0,0,0 { + reg = <0x0000 0 0 0 0>; + ranges = <0x00000000 0 0 0 0 0 0 0x00100000>; + #address-cells = <3>; + #size-cells = <2>; + + wifi@0,1,0 { + reg = <0x0000 0 0 0 0>; + ranges = <0x00000000 0 0 0 0x00100000>; + #address-cells = <1>; + #size-cells = <1>; + + pcie0_chipcommon: chipcommon@0 { + reg = <0 0x1000>; + + gpio-controller; + #gpio-cells = <2>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi index 00de62dc0042..acee36a61004 100644 --- a/arch/arm/boot/dts/bcm5301x.dtsi +++ b/arch/arm/boot/dts/bcm5301x.dtsi @@ -18,10 +18,6 @@ / { interrupt-parent = <&gic>; - chosen { - stdout-path = &uart0; - }; - chipcommonA { compatible = "simple-bus"; ranges = <0x00000000 0x18000000 0x00001000>; @@ -70,10 +66,19 @@ clocks = <&periph_clk>; }; - local-timer@20600 { + timer@20600 { compatible = "arm,cortex-a9-twd-timer"; - reg = <0x20600 0x100>; - interrupts = <GIC_PPI 13 IRQ_TYPE_EDGE_RISING>; + reg = <0x20600 0x20>; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | + IRQ_TYPE_EDGE_RISING)>; + clocks = <&periph_clk>; + }; + + watchdog@20620 { + compatible = "arm,cortex-a9-twd-wdt"; + reg = <0x20620 0x20>; + interrupts = <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | + IRQ_TYPE_EDGE_RISING)>; clocks = <&periph_clk>; }; @@ -298,20 +303,6 @@ }; }; - spi@29000 { - reg = <0x00029000 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - - spi_nor: spi-nor@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <20000000>; - linux,part-probe = "ofpart", "bcm47xxpart"; - status = "disabled"; - }; - }; - gmac0: ethernet@24000 { reg = <0x24000 0x800>; }; @@ -329,6 +320,16 @@ }; }; + i2c0: i2c@18009000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18009000 0x50>; + interrupts = <GIC_SPI 121 IRQ_TYPE_NONE>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + status = "disabled"; + }; + lcpll0: lcpll0@1800c100 { #clock-cells = <1>; compatible = "brcm,nsp-lcpll0"; @@ -375,4 +376,40 @@ brcm,nand-has-wp; }; + + spi@18029200 { + compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi"; + reg = <0x18029200 0x184>, + <0x18029000 0x124>, + <0x1811b408 0x004>, + <0x180293a0 0x01c>; + reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg"; + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "spi_lr_fullness_reached", + "spi_lr_session_aborted", + "spi_lr_impatient", + "spi_lr_session_done", + "spi_lr_overhead", + "mspi_done", + "mspi_halted"; + clocks = <&iprocmed>; + clock-names = "iprocmed"; + num-cs = <2>; + #address-cells = <1>; + #size-cells = <0>; + + spi_nor: spi-nor@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <20000000>; + linux,part-probe = "ofpart", "bcm47xxpart"; + status = "disabled"; + }; + }; }; diff --git a/arch/arm/boot/dts/bcm53573.dtsi b/arch/arm/boot/dts/bcm53573.dtsi index 2da04d0a7348..eae623f76401 100644 --- a/arch/arm/boot/dts/bcm53573.dtsi +++ b/arch/arm/boot/dts/bcm53573.dtsi @@ -13,8 +13,12 @@ / { interrupt-parent = <&gic>; + aliases { + serial0 = &uart0; + }; + chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; cpus { @@ -113,6 +117,10 @@ }; }; + pcie0: pcie@2000 { + reg = <0x00002000 0x1000>; + }; + usb2: usb2@4000 { reg = <0x4000 0x1000>; ranges; diff --git a/arch/arm/boot/dts/bcm94708.dts b/arch/arm/boot/dts/bcm94708.dts index 42855a7c1bfa..2e08c895f281 100644 --- a/arch/arm/boot/dts/bcm94708.dts +++ b/arch/arm/boot/dts/bcm94708.dts @@ -38,14 +38,6 @@ model = "NorthStar SVK (BCM94708)"; compatible = "brcm,bcm94708", "brcm,bcm4708"; - aliases { - serial0 = &uart0; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - memory { reg = <0x00000000 0x08000000>; }; diff --git a/arch/arm/boot/dts/bcm94709.dts b/arch/arm/boot/dts/bcm94709.dts index 95e8be65f2f1..c37616c67edc 100644 --- a/arch/arm/boot/dts/bcm94709.dts +++ b/arch/arm/boot/dts/bcm94709.dts @@ -38,14 +38,6 @@ model = "NorthStar SVK (BCM94709)"; compatible = "brcm,bcm94709", "brcm,bcm4709", "brcm,bcm4708"; - aliases { - serial0 = &uart0; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - memory { reg = <0x00000000 0x08000000>; }; diff --git a/arch/arm/boot/dts/bcm953012er.dts b/arch/arm/boot/dts/bcm953012er.dts index decd86bae901..40e694bfe5ca 100644 --- a/arch/arm/boot/dts/bcm953012er.dts +++ b/arch/arm/boot/dts/bcm953012er.dts @@ -39,14 +39,6 @@ model = "NorthStar Enterprise Router (BCM953012ER)"; compatible = "brcm,bcm953012er", "brcm,brcm53012", "brcm,bcm4708"; - aliases { - serial0 = &uart0; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - memory { reg = <0x00000000 0x8000000>; }; diff --git a/arch/arm/boot/dts/bcm953012hr.dts b/arch/arm/boot/dts/bcm953012hr.dts new file mode 100644 index 000000000000..3076e81699cf --- /dev/null +++ b/arch/arm/boot/dts/bcm953012hr.dts @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2017 Broadcom + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Broadcom nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/dts-v1/; + +#include "bcm4708.dtsi" +#include "bcm5301x-nand-cs0-bch4.dtsi" + +/ { + model = "NorthStar HR (BCM953012HR)"; + compatible = "brcm,bcm953012hr", "brcm,brcm53012", "brcm,bcm4708"; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + ethernet2 = &gmac2; + }; + + memory@80000000 { + reg = <0x80000000 0x10000000>; + }; +}; + +&nandcs { + partition@0 { + label = "nboot"; + reg = <0x00000000 0x00200000>; + read-only; + }; + partition@200000 { + label = "nenv"; + reg = <0x00200000 0x00400000>; + }; + partition@600000 { + label = "nsystem"; + reg = <0x00600000 0x00a00000>; + }; + partition@1000000 { + label = "nrootfs"; + reg = <0x01000000 0x07000000>; + }; +}; + +&spi_nor { + status = "okay"; + spi-max-frequency = <62500000>; + m25p,default-addr-width = <3>; + + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot"; + reg = <0x00000000 0x000d0000>; + }; + partition@d000 { + label = "env"; + reg = <0x000d0000 0x00030000>; + }; + partition@100000 { + label = "system"; + reg = <0x00100000 0x00600000>; + }; + partition@700000 { + label = "rootfs"; + reg = <0x00700000 0x00900000>; + }; +}; diff --git a/arch/arm/boot/dts/bcm953012k.dts b/arch/arm/boot/dts/bcm953012k.dts index ae31a5826e91..79c168e2714b 100644 --- a/arch/arm/boot/dts/bcm953012k.dts +++ b/arch/arm/boot/dts/bcm953012k.dts @@ -43,15 +43,69 @@ serial1 = &uart1; }; - chosen { - stdout-path = "serial0:115200n8"; - }; - memory { reg = <0x80000000 0x10000000>; }; }; +&nand { + nandcs@0 { + compatible = "brcm,nandcs"; + reg = <0>; + nand-on-flash-bbt; + + #address-cells = <1>; + #size-cells = <1>; + + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + + partition@0 { + label = "nboot"; + reg = <0x00000000 0x00200000>; + read-only; + }; + partition@200000 { + label = "nenv"; + reg = <0x00200000 0x00400000>; + }; + partition@600000 { + label = "nsystem"; + reg = <0x00600000 0x00a00000>; + }; + partition@1000000 { + label = "nrootfs"; + reg = <0x01000000 0x07000000>; + }; + }; +}; + +&spi_nor { + status = "okay"; + spi-max-frequency = <62500000>; + m25p,default-addr-width = <3>; + + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot"; + reg = <0x00000000 0x000d0000>; + }; + partition@d000 { + label = "env"; + reg = <0x000d0000 0x00030000>; + }; + partition@100000 { + label = "system"; + reg = <0x00100000 0x00600000>; + }; + partition@700000 { + label = "rootfs"; + reg = <0x00700000 0x00900000>; + }; +}; + &uart0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm958522er.dts b/arch/arm/boot/dts/bcm958522er.dts index df05e7f568af..f5c42962c201 100644 --- a/arch/arm/boot/dts/bcm958522er.dts +++ b/arch/arm/boot/dts/bcm958522er.dts @@ -60,7 +60,7 @@ }; }; -/* USB 2/3 support needed to be complete */ +/* USB 3 support needed to be complete */ &amac0 { status = "okay"; @@ -70,6 +70,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &nand { nandcs@0 { compatible = "brcm,nandcs"; @@ -108,6 +112,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm958525er.dts b/arch/arm/boot/dts/bcm958525er.dts index 4a3ab19c6281..efcb1f67bdad 100644 --- a/arch/arm/boot/dts/bcm958525er.dts +++ b/arch/arm/boot/dts/bcm958525er.dts @@ -60,7 +60,7 @@ }; }; -/* USB 2/3 support needed to be complete */ +/* USB 3 support needed to be complete */ &amac0 { status = "okay"; @@ -70,6 +70,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &nand { nandcs@0 { compatible = "brcm,nandcs"; @@ -108,6 +112,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts index 81f78435d8c7..b335ce02e32f 100644 --- a/arch/arm/boot/dts/bcm958525xmc.dts +++ b/arch/arm/boot/dts/bcm958525xmc.dts @@ -66,7 +66,13 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &i2c0 { + status = "okay"; + temperature-sensor@4c { compatible = "adi,adt7461a"; reg = <0x4c>; @@ -122,6 +128,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm958622hr.dts b/arch/arm/boot/dts/bcm958622hr.dts index c88b8fefcb2f..16ab2d82a14b 100644 --- a/arch/arm/boot/dts/bcm958622hr.dts +++ b/arch/arm/boot/dts/bcm958622hr.dts @@ -60,7 +60,7 @@ }; }; -/* USB 2/3 and SLIC support needed to be complete */ +/* USB 3 and SLIC support needed to be complete */ &amac0 { status = "okay"; @@ -74,6 +74,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &nand { nandcs@0 { compatible = "brcm,nandcs"; @@ -112,6 +116,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts index d503fa0dde31..9b921c6aa8f8 100644 --- a/arch/arm/boot/dts/bcm958623hr.dts +++ b/arch/arm/boot/dts/bcm958623hr.dts @@ -60,7 +60,7 @@ }; }; -/* USB 2/3 and SLIC support needed to be complete */ +/* USB 3 and SLIC support needed to be complete */ &amac0 { status = "okay"; @@ -74,6 +74,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &nand { nandcs@0 { compatible = "brcm,nandcs"; @@ -112,6 +116,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts index cc0363b843c1..006b08e41a3b 100644 --- a/arch/arm/boot/dts/bcm958625hr.dts +++ b/arch/arm/boot/dts/bcm958625hr.dts @@ -72,6 +72,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &nand { nandcs@0 { compatible = "brcm,nandcs"; @@ -110,6 +114,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts index f8d47e517e18..64740f85cf4c 100644 --- a/arch/arm/boot/dts/bcm958625k.dts +++ b/arch/arm/boot/dts/bcm958625k.dts @@ -65,6 +65,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &nand { nandcs@0 { compatible = "brcm,nandcs"; @@ -103,6 +107,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm988312hr.dts b/arch/arm/boot/dts/bcm988312hr.dts index 74e15a3cd9f8..bce251a68591 100644 --- a/arch/arm/boot/dts/bcm988312hr.dts +++ b/arch/arm/boot/dts/bcm988312hr.dts @@ -60,7 +60,7 @@ }; }; -/* USB 2/3 support needed to be complete */ +/* USB 3 support needed to be complete */ &amac0 { status = "okay"; @@ -74,6 +74,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &nand { nandcs@0 { compatible = "brcm,nandcs"; @@ -112,6 +116,10 @@ }; }; +&ohci0 { + status = "okay"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts index d15107cba765..8d244cd76c36 100644 --- a/arch/arm/boot/dts/da850-evm.dts +++ b/arch/arm/boot/dts/da850-evm.dts @@ -9,6 +9,7 @@ */ /dts-v1/; #include "da850.dtsi" +#include <dt-bindings/gpio/gpio.h> / { compatible = "ti,da850-evm", "ti,da850"; @@ -78,7 +79,10 @@ DRVDD-supply = <&vbat>; DVDD-supply = <&vbat>; }; - + tca6416: gpio@20 { + compatible = "ti,tca6416"; + reg = <0x20>; + }; }; wdt: wdt@21000 { status = "okay"; @@ -293,20 +297,27 @@ &vpif { pinctrl-names = "default"; - pinctrl-0 = <&vpif_capture_pins>; + pinctrl-0 = <&vpif_capture_pins>, <&vpif_display_pins>; status = "okay"; /* VPIF capture port */ - port { - vpif_ch0: endpoint@0 { - reg = <0>; - bus-width = <8>; + port@0 { + vpif_input_ch0: endpoint@0 { + reg = <0>; + bus-width = <8>; }; - vpif_ch1: endpoint@1 { - reg = <1>; - bus-width = <8>; - data-shift = <8>; + vpif_input_ch1: endpoint@1 { + reg = <1>; + bus-width = <8>; + data-shift = <8>; + }; + }; + + /* VPIF display port */ + port@1 { + vpif_output_ch0: endpoint { + bus-width = <8>; }; }; }; diff --git a/arch/arm/boot/dts/da850-lego-ev3.dts b/arch/arm/boot/dts/da850-lego-ev3.dts index 112ec92064ce..512604ad8b71 100644 --- a/arch/arm/boot/dts/da850-lego-ev3.dts +++ b/arch/arm/boot/dts/da850-lego-ev3.dts @@ -123,6 +123,14 @@ pinctrl-0 = <&system_power_pin>; }; + sound { + compatible = "pwm-beeper"; + pinctrl-names = "default"; + pinctrl-0 = <&ehrpwm0b_pins>; + pwms = <&ehrpwm0 1 1000000 0>; + amp-supply = <&>; + }; + /* * This is a 5V current limiting regulator that is shared by USB, * the sensor (input) ports, the motor (output) ports and the A/DC. @@ -139,18 +147,36 @@ enable-active-high; regulator-boot-on; }; + + /* + * This is a simple voltage divider on VCC5V to provide a 2.5V + * reference signal to the ADC. + */ + adc_ref: regulator2 { + compatible = "regulator-fixed"; + regulator-name = "adc ref"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-boot-on; + vin-supply = <&vcc5v>; + }; + + /* + * This is the amplifier for the speaker. + */ + amp: regulator3 { + pinctrl-names = "default"; + pinctrl-0 = <&_pins>; + compatible = "regulator-fixed"; + regulator-name = "amp"; + gpio = <&gpio 111 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; }; &pmx_core { status = "okay"; - spi0_cs3_pin: pinmux_spi0_cs3_pin { - pinctrl-single,bits = < - /* CS3 */ - 0xc 0x01000000 0x0f000000 - >; - }; - mmc0_cd_pin: pinmux_mmc0_cd { pinctrl-single,bits = < /* GP5[14] */ @@ -195,6 +221,13 @@ 0x4c 0x00008000 0x0000f000 >; }; + + amp_pins: pinmux_amp_pins { + pinctrl-single,bits = < + /* GP6[15] */ + 0x34 0x00000008 0x0000000f + >; + }; }; &pinconf { @@ -293,6 +326,18 @@ }; }; }; + + adc: adc@3 { + compatible = "ti,ads7957"; + reg = <3>; + #io-channel-cells = <1>; + spi-max-frequency = <10000000>; + vref-supply = <&adc_ref>; + }; +}; + +&ehrpwm0 { + status = "okay"; }; &gpio { diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi index 92d633d1da68..941d455000a7 100644 --- a/arch/arm/boot/dts/da850.dtsi +++ b/arch/arm/boot/dts/da850.dtsi @@ -153,6 +153,12 @@ 0x10 0x00000010 0x000000f0 >; }; + spi0_cs3_pin: pinmux_spi0_cs3_pin { + pinctrl-single,bits = < + /* CS3 */ + 0xc 0x01000000 0x0f000000 + >; + }; spi1_pins: pinmux_spi1_pins { pinctrl-single,bits = < /* SIMO, SOMI, CLK */ @@ -216,8 +222,21 @@ 0x3c 0x11111111 0xffffffff /* VP_DIN[8..9] */ 0x40 0x00000011 0x000000ff - /* VP_CLKIN3, VP_CLKIN2 */ - 0x4c 0x00010100 0x000f0f00 + >; + }; + vpif_display_pins: vpif_display_pins { + pinctrl-single,bits = < + /* VP_DOUT[2..7] */ + 0x40 0x11111100 0xffffff00 + /* VP_DOUT[10..15,0..1] */ + 0x44 0x11111111 0xffffffff + /* VP_DOUT[8..9] */ + 0x48 0x00000011 0x000000ff + /* + * VP_CLKOUT3, VP_CLKIN3, + * VP_CLKOUT2, VP_CLKIN2 + */ + 0x4c 0x00111100 0x00ffff00 >; }; }; @@ -345,7 +364,13 @@ status = "disabled"; /* VPIF capture port */ - port { + port@0 { + #address-cells = <1>; + #size-cells = <0>; + }; + + /* VPIF display port */ + port@1 { #address-cells = <1>; #size-cells = <0>; }; diff --git a/arch/arm/boot/dts/dm8168-evm.dts b/arch/arm/boot/dts/dm8168-evm.dts index 0bf55fa72dea..1865976db5f9 100644 --- a/arch/arm/boot/dts/dm8168-evm.dts +++ b/arch/arm/boot/dts/dm8168-evm.dts @@ -25,6 +25,12 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; + + sata_refclk: fixedclock0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; }; &dm816x_pinmux { @@ -173,3 +179,7 @@ pinctrl-0 = <&usb1_pins>; mentor,multipoint = <0>; }; + +&sata { + clocks = <&sysclk5_ck>, <&sata_refclk>; +}; diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index 276211e1ee53..59cbf958fcc3 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -293,6 +293,13 @@ phy-handle = <&phy1>; }; + sata: sata@4a140000 { + compatible = "ti,dm816-ahci"; + reg = <0x4a140000 0x10000>; + interrupts = <16>; + ti,hwmods = "sata"; + }; + mcspi1: spi@48030000 { compatible = "ti,omap4-mcspi"; reg = <0x48030000 0x1000>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index bbfb9d5a70a9..57892f264cea 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -81,11 +81,7 @@ compatible = "arm,cortex-a15"; reg = <0>; - operating-points = < - /* kHz uV */ - 1000000 1060000 - 1176000 1160000 - >; + operating-points-v2 = <&cpu0_opp_table>; clocks = <&dpll_mpu_ck>; clock-names = "cpu"; @@ -99,6 +95,24 @@ }; }; + cpu0_opp_table: opp-table { + compatible = "operating-points-v2-ti-cpu"; + syscon = <&scm_wkup>; + + opp_nom@1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <1060000 850000 1150000>; + opp-supported-hw = <0xFF 0x01>; + opp-suspend; + }; + + opp_od@1176000000 { + opp-hz = /bits/ 64 <1176000000>; + opp-microvolt = <1160000 885000 1160000>; + opp-supported-hw = <0xFF 0x02>; + }; + }; + /* * The soc node represents the soc top level view. It is used for IPs * that are not memory mapped in the MPU view or for the MPU itself. @@ -1984,6 +1998,23 @@ &cpu_thermal { polling-delay = <500>; /* milliseconds */ + coefficients = <0 2000>; +}; + +&gpu_thermal { + coefficients = <0 2000>; +}; + +&core_thermal { + coefficients = <0 2000>; +}; + +&dspeve_thermal { + coefficients = <0 2000>; +}; + +&iva_thermal { + coefficients = <0 2000>; }; /include/ "dra7xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi index 0a78347e6615..24e6746c5b26 100644 --- a/arch/arm/boot/dts/dra74x.dtsi +++ b/arch/arm/boot/dts/dra74x.dtsi @@ -17,6 +17,7 @@ device_type = "cpu"; compatible = "arm,cortex-a15"; reg = <1>; + operating-points-v2 = <&cpu0_opp_table>; }; }; @@ -79,6 +80,10 @@ }; }; +&cpu0_opp_table { + opp-shared; +}; + &dss { reg = <0x58000000 0x80>, <0x58004054 0x4>, diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts index 548413e23c47..c9f191ca7b9c 100644 --- a/arch/arm/boot/dts/exynos3250-rinato.dts +++ b/arch/arm/boot/dts/exynos3250-rinato.dts @@ -215,6 +215,8 @@ &dsi_0 { vddcore-supply = <&ldo6_reg>; vddio-supply = <&ldo6_reg>; + samsung,burst-clock-frequency = <250000000>; + samsung,esc-clock-frequency = <20000000>; samsung,pll-clock-frequency = <24000000>; status = "okay"; diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index 9c28ef4508e0..590ee442d0ae 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi @@ -745,23 +745,23 @@ compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; opp-microvolt = <800000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <800000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <800000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <825000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <875000>; }; @@ -835,23 +835,23 @@ compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; opp-microvolt = <900000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; opp-microvolt = <900000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <1000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <1000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <1000000>; }; @@ -861,19 +861,19 @@ compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; }; }; @@ -882,19 +882,19 @@ compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; }; }; @@ -903,13 +903,13 @@ compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; }; - opp@80000000 { + opp-80000000 { opp-hz = /bits/ 64 <80000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; }; diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 84fcdff140ae..497a9470c888 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -283,15 +283,6 @@ }; }; - watchdog: watchdog@10060000 { - compatible = "samsung,s3c2410-wdt"; - reg = <0x10060000 0x100>; - interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clock CLK_WDT>; - clock-names = "watchdog"; - status = "disabled"; - }; - rtc: rtc@10070000 { compatible = "samsung,s3c6410-rtc"; reg = <0x10070000 0x100>; diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index a2c6a13fe67b..312650e2450f 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -328,7 +328,3 @@ &tmu { status = "okay"; }; - -&watchdog { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts index 0ca1b4d355f2..1743ca850070 100644 --- a/arch/arm/boot/dts/exynos4210-trats.dts +++ b/arch/arm/boot/dts/exynos4210-trats.dts @@ -197,6 +197,8 @@ &dsi_0 { vddcore-supply = <&vusb_reg>; vddio-supply = <&vmipi_reg>; + samsung,burst-clock-frequency = <500000000>; + samsung,esc-clock-frequency = <20000000>; samsung,pll-clock-frequency = <24000000>; status = "okay"; diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index f9408188f97f..768fb075b1fd 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -119,6 +119,14 @@ }; }; + watchdog: watchdog@10060000 { + compatible = "samsung,s3c6410-wdt"; + reg = <0x10060000 0x100>; + interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clock CLK_WDT>; + clock-names = "watchdog"; + }; + clock: clock-controller@10030000 { compatible = "samsung,exynos4210-clock"; reg = <0x10030000 0x20000>; @@ -335,15 +343,15 @@ compatible = "operating-points-v2"; opp-shared; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <1025000>; }; - opp@267000000 { + opp-267000000 { opp-hz = /bits/ 64 <267000000>; opp-microvolt = <1050000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <1150000>; }; @@ -353,13 +361,13 @@ compatible = "operating-points-v2"; opp-shared; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; }; @@ -368,10 +376,10 @@ compatible = "operating-points-v2"; opp-shared; - opp@5000000 { + opp-5000000 { opp-hz = /bits/ 64 <5000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; }; @@ -380,10 +388,10 @@ compatible = "operating-points-v2"; opp-shared; - opp@10000000 { + opp-10000000 { opp-hz = /bits/ 64 <10000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; }; @@ -392,13 +400,13 @@ compatible = "operating-points-v2"; opp-shared; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; }; }; @@ -407,13 +415,13 @@ compatible = "operating-points-v2"; opp-shared; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; }; diff --git a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi index a36cd36a26b8..4cd62487bb16 100644 --- a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi +++ b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi @@ -495,7 +495,3 @@ vtmu-supply = <&ldo16_reg>; status = "okay"; }; - -&watchdog { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 78f118cb73d4..0f1ff792fe44 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -555,7 +555,3 @@ vtmu-supply = <&ldo10_reg>; status = "okay"; }; - -&watchdog { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts index a1ab6f94bb64..7a83e2df18a6 100644 --- a/arch/arm/boot/dts/exynos4412-origen.dts +++ b/arch/arm/boot/dts/exynos4412-origen.dts @@ -541,7 +541,3 @@ &serial_3 { status = "okay"; }; - -&watchdog { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/exynos4412-prime.dtsi b/arch/arm/boot/dts/exynos4412-prime.dtsi index e75bc170c89c..a67bd953d754 100644 --- a/arch/arm/boot/dts/exynos4412-prime.dtsi +++ b/arch/arm/boot/dts/exynos4412-prime.dtsi @@ -20,12 +20,12 @@ }; &cpu0_opp_table { - opp@1600000000 { + opp-1600000000 { opp-hz = /bits/ 64 <1600000000>; opp-microvolt = <1350000>; clock-latency-ns = <200000>; }; - opp@1704000000 { + opp-1704000000 { opp-hz = /bits/ 64 <1704000000>; opp-microvolt = <1350000>; clock-latency-ns = <200000>; diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 41ecd6d465a7..82221a00444d 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -385,6 +385,8 @@ &dsi_0 { vddcore-supply = <&ldo8_reg>; vddio-supply = <&ldo10_reg>; + samsung,burst-clock-frequency = <500000000>; + samsung,esc-clock-frequency = <20000000>; samsung,pll-clock-frequency = <24000000>; status = "okay"; diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index 235bbb69ad7c..7ff03a7e8fb9 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi @@ -76,73 +76,73 @@ compatible = "operating-points-v2"; opp-shared; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <900000>; clock-latency-ns = <200000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; opp-microvolt = <900000>; clock-latency-ns = <200000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <925000>; clock-latency-ns = <200000>; }; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <950000>; clock-latency-ns = <200000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <975000>; clock-latency-ns = <200000>; }; - opp@700000000 { + opp-700000000 { opp-hz = /bits/ 64 <700000000>; opp-microvolt = <987500>; clock-latency-ns = <200000>; }; - opp@800000000 { + opp-800000000 { opp-hz = /bits/ 64 <800000000>; opp-microvolt = <1000000>; clock-latency-ns = <200000>; opp-suspend; }; - opp@900000000 { + opp-900000000 { opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1037500>; clock-latency-ns = <200000>; }; - opp@1000000000 { + opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <1087500>; clock-latency-ns = <200000>; }; - opp@1100000000 { + opp-1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <1137500>; clock-latency-ns = <200000>; }; - opp@1200000000 { + opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1187500>; clock-latency-ns = <200000>; }; - opp@1300000000 { + opp-1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1250000>; clock-latency-ns = <200000>; }; - opp@1400000000 { + opp-1400000000 { opp-hz = /bits/ 64 <1400000000>; opp-microvolt = <1287500>; clock-latency-ns = <200000>; }; - cpu0_opp_1500: opp@1500000000 { + cpu0_opp_1500: opp-1500000000 { opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1350000>; clock-latency-ns = <200000>; @@ -215,6 +215,15 @@ }; }; + watchdog: watchdog@10060000 { + compatible = "samsung,exynos5250-wdt"; + reg = <0x10060000 0x100>; + interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clock CLK_WDT>; + clock-names = "watchdog"; + samsung,syscon-phandle = <&pmu_system_controller>; + }; + adc: adc@126C0000 { compatible = "samsung,exynos-adc-v1"; reg = <0x126C0000 0x100>; @@ -433,23 +442,23 @@ compatible = "operating-points-v2"; opp-shared; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <900000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <900000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; opp-microvolt = <900000>; }; - opp@267000000 { + opp-267000000 { opp-hz = /bits/ 64 <267000000>; opp-microvolt = <950000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <1050000>; }; @@ -459,16 +468,16 @@ compatible = "operating-points-v2"; opp-shared; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; }; - opp@267000000 { + opp-267000000 { opp-hz = /bits/ 64 <267000000>; }; }; @@ -525,19 +534,19 @@ compatible = "operating-points-v2"; opp-shared; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <900000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <925000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; opp-microvolt = <950000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <1000000>; }; @@ -547,10 +556,10 @@ compatible = "operating-points-v2"; opp-shared; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; }; @@ -559,10 +568,10 @@ compatible = "operating-points-v2"; opp-shared; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; }; @@ -571,10 +580,10 @@ compatible = "operating-points-v2"; opp-shared; - opp@50000000 { + opp-50000000 { opp-hz = /bits/ 64 <50000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; }; diff --git a/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi new file mode 100644 index 000000000000..c8771c660550 --- /dev/null +++ b/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi @@ -0,0 +1,25 @@ +/* + * Device tree sources for Exynos5420 TMU sensor configuration + * + * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com> + * Copyright (c) 2017 Krzysztof Kozlowski <krzk@kernel.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <dt-bindings/thermal/thermal_exynos.h> + +#thermal-sensor-cells = <0>; +samsung,tmu_gain = <8>; +samsung,tmu_reference_voltage = <16>; +samsung,tmu_noise_cancel_mode = <4>; +samsung,tmu_efuse_value = <55>; +samsung,tmu_min_efuse_value = <0>; +samsung,tmu_max_efuse_value = <100>; +samsung,tmu_first_point_trim = <25>; +samsung,tmu_second_point_trim = <85>; +samsung,tmu_default_temp_offset = <50>; +samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 7dc9dc82afd8..0db0bcf8da36 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -49,62 +49,62 @@ cluster_a15_opp_table: opp_table0 { compatible = "operating-points-v2"; opp-shared; - opp@1800000000 { + opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1250000>; clock-latency-ns = <140000>; }; - opp@1700000000 { + opp-1700000000 { opp-hz = /bits/ 64 <1700000000>; opp-microvolt = <1212500>; clock-latency-ns = <140000>; }; - opp@1600000000 { + opp-1600000000 { opp-hz = /bits/ 64 <1600000000>; opp-microvolt = <1175000>; clock-latency-ns = <140000>; }; - opp@1500000000 { + opp-1500000000 { opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1137500>; clock-latency-ns = <140000>; }; - opp@1400000000 { + opp-1400000000 { opp-hz = /bits/ 64 <1400000000>; opp-microvolt = <1112500>; clock-latency-ns = <140000>; }; - opp@1300000000 { + opp-1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1062500>; clock-latency-ns = <140000>; }; - opp@1200000000 { + opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1037500>; clock-latency-ns = <140000>; }; - opp@1100000000 { + opp-1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <1012500>; clock-latency-ns = <140000>; }; - opp@1000000000 { + opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = < 987500>; clock-latency-ns = <140000>; }; - opp@900000000 { + opp-900000000 { opp-hz = /bits/ 64 <900000000>; opp-microvolt = < 962500>; clock-latency-ns = <140000>; }; - opp@800000000 { + opp-800000000 { opp-hz = /bits/ 64 <800000000>; opp-microvolt = < 937500>; clock-latency-ns = <140000>; }; - opp@700000000 { + opp-700000000 { opp-hz = /bits/ 64 <700000000>; opp-microvolt = < 912500>; clock-latency-ns = <140000>; @@ -114,42 +114,42 @@ cluster_a7_opp_table: opp_table1 { compatible = "operating-points-v2"; opp-shared; - opp@1300000000 { + opp-1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1275000>; clock-latency-ns = <140000>; }; - opp@1200000000 { + opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1212500>; clock-latency-ns = <140000>; }; - opp@1100000000 { + opp-1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <1162500>; clock-latency-ns = <140000>; }; - opp@1000000000 { + opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <1112500>; clock-latency-ns = <140000>; }; - opp@900000000 { + opp-900000000 { opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1062500>; clock-latency-ns = <140000>; }; - opp@800000000 { + opp-800000000 { opp-hz = /bits/ 64 <800000000>; opp-microvolt = <1025000>; clock-latency-ns = <140000>; }; - opp@700000000 { + opp-700000000 { opp-hz = /bits/ 64 <700000000>; opp-microvolt = <975000>; clock-latency-ns = <140000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <937500>; clock-latency-ns = <140000>; @@ -699,7 +699,7 @@ interrupts = <0 65 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clock CLK_TMU>; clock-names = "tmu_apbif"; - #include "exynos4412-tmu-sensor-conf.dtsi" + #include "exynos5420-tmu-sensor-conf.dtsi" }; tmu_cpu1: tmu@10064000 { @@ -708,7 +708,7 @@ interrupts = <0 183 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clock CLK_TMU>; clock-names = "tmu_apbif"; - #include "exynos4412-tmu-sensor-conf.dtsi" + #include "exynos5420-tmu-sensor-conf.dtsi" }; tmu_cpu2: tmu@10068000 { @@ -717,7 +717,7 @@ interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clock CLK_TMU>, <&clock CLK_TMU>; clock-names = "tmu_apbif", "tmu_triminfo_apbif"; - #include "exynos4412-tmu-sensor-conf.dtsi" + #include "exynos5420-tmu-sensor-conf.dtsi" }; tmu_cpu3: tmu@1006c000 { @@ -726,7 +726,7 @@ interrupts = <0 185 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clock CLK_TMU>, <&clock CLK_TMU_GPU>; clock-names = "tmu_apbif", "tmu_triminfo_apbif"; - #include "exynos4412-tmu-sensor-conf.dtsi" + #include "exynos5420-tmu-sensor-conf.dtsi" }; tmu_gpu: tmu@100a0000 { @@ -735,7 +735,7 @@ interrupts = <0 215 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clock CLK_TMU_GPU>, <&clock CLK_TMU>; clock-names = "tmu_apbif", "tmu_triminfo_apbif"; - #include "exynos4412-tmu-sensor-conf.dtsi" + #include "exynos5420-tmu-sensor-conf.dtsi" }; sysmmu_g2dr: sysmmu@0x10A60000 { diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi index 77d35bb92950..a4ea018464fc 100644 --- a/arch/arm/boot/dts/exynos5440.dtsi +++ b/arch/arm/boot/dts/exynos5440.dtsi @@ -189,7 +189,7 @@ }; watchdog@110000 { - compatible = "samsung,s3c2410-wdt"; + compatible = "samsung,s3c6410-wdt"; reg = <0x110000 0x1000>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clock CLK_B_125>; @@ -290,11 +290,22 @@ clock-names = "usbhost"; }; + pcie_phy0: pcie-phy@270000 { + #phy-cells = <0>; + compatible = "samsung,exynos5440-pcie-phy"; + reg = <0x270000 0x1000>, <0x271000 0x40>; + }; + + pcie_phy1: pcie-phy@272000 { + #phy-cells = <0>; + compatible = "samsung,exynos5440-pcie-phy"; + reg = <0x272000 0x1000>, <0x271040 0x40>; + }; + pcie_0: pcie@290000 { compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; - reg = <0x290000 0x1000 - 0x270000 0x1000 - 0x271000 0x40>; + reg = <0x290000 0x1000>, <0x40000000 0x1000>; + reg-names = "elbi", "config"; interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>; @@ -303,8 +314,8 @@ #address-cells = <3>; #size-cells = <2>; device_type = "pci"; - ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */ - 0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */ + phys = <&pcie_phy0>; + ranges = <0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */ 0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; @@ -315,9 +326,8 @@ pcie_1: pcie@2a0000 { compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; - reg = <0x2a0000 0x1000 - 0x272000 0x1000 - 0x271040 0x40>; + reg = <0x2a0000 0x1000>, <0x60000000 0x1000>; + reg-names = "elbi", "config"; interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; @@ -326,8 +336,8 @@ #address-cells = <3>; #size-cells = <2>; device_type = "pci"; - ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */ - 0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */ + phys = <&pcie_phy1>; + ranges = <0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */ 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; diff --git a/arch/arm/boot/dts/exynos5800.dtsi b/arch/arm/boot/dts/exynos5800.dtsi index 8213016803e5..9ddb6bacac5a 100644 --- a/arch/arm/boot/dts/exynos5800.dtsi +++ b/arch/arm/boot/dts/exynos5800.dtsi @@ -24,60 +24,60 @@ }; &cluster_a15_opp_table { - opp@1700000000 { + opp-1700000000 { opp-microvolt = <1250000>; }; - opp@1600000000 { + opp-1600000000 { opp-microvolt = <1250000>; }; - opp@1500000000 { + opp-1500000000 { opp-microvolt = <1100000>; }; - opp@1400000000 { + opp-1400000000 { opp-microvolt = <1100000>; }; - opp@1300000000 { + opp-1300000000 { opp-microvolt = <1100000>; }; - opp@1200000000 { + opp-1200000000 { opp-microvolt = <1000000>; }; - opp@1100000000 { + opp-1100000000 { opp-microvolt = <1000000>; }; - opp@1000000000 { + opp-1000000000 { opp-microvolt = <1000000>; }; - opp@900000000 { + opp-900000000 { opp-microvolt = <1000000>; }; - opp@800000000 { + opp-800000000 { opp-microvolt = <900000>; }; - opp@700000000 { + opp-700000000 { opp-microvolt = <900000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <900000>; clock-latency-ns = <140000>; }; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <900000>; clock-latency-ns = <140000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <900000>; clock-latency-ns = <140000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; opp-microvolt = <900000>; clock-latency-ns = <140000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <900000>; clock-latency-ns = <140000>; @@ -85,46 +85,46 @@ }; &cluster_a7_opp_table { - opp@1300000000 { + opp-1300000000 { opp-microvolt = <1250000>; }; - opp@1200000000 { + opp-1200000000 { opp-microvolt = <1250000>; }; - opp@1100000000 { + opp-1100000000 { opp-microvolt = <1250000>; }; - opp@1000000000 { + opp-1000000000 { opp-microvolt = <1100000>; }; - opp@900000000 { + opp-900000000 { opp-microvolt = <1100000>; }; - opp@800000000 { + opp-800000000 { opp-microvolt = <1100000>; }; - opp@700000000 { + opp-700000000 { opp-microvolt = <1000000>; }; - opp@600000000 { + opp-600000000 { opp-microvolt = <1000000>; }; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <1000000>; clock-latency-ns = <140000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <1000000>; clock-latency-ns = <140000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; opp-microvolt = <900000>; clock-latency-ns = <140000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <900000>; clock-latency-ns = <140000>; diff --git a/arch/arm/boot/dts/gemini-nas4220b.dts b/arch/arm/boot/dts/gemini-nas4220b.dts new file mode 100644 index 000000000000..7668ba52158e --- /dev/null +++ b/arch/arm/boot/dts/gemini-nas4220b.dts @@ -0,0 +1,102 @@ +/* + * Device Tree file for the Gemini-based Raidsonic NAS IB-4220-B + */ + +/dts-v1/; + +#include "gemini.dtsi" +#include <dt-bindings/input/input.h> + +/ { + model = "Raidsonic NAS IB-4220-B"; + compatible = "raidsonic,ib-4220-b", "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { /* 128 MB */ + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,19200n8"; + stdout-path = &uart0; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@29 { + debounce_interval = <50>; + wakeup-source; + linux,code = <KEY_SETUP>; + label = "Backup button"; + gpios = <&gpio1 29 GPIO_ACTIVE_LOW>; + }; + button@31 { + debounce_interval = <50>; + wakeup-source; + linux,code = <KEY_RESTART>; + label = "Softreset button"; + gpios = <&gpio1 31 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + led@28 { + label = "nas4220b:orange:hdd"; + gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + led@30 { + label = "nas4220b:green:os"; + gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + }; + + soc { + flash@30000000 { + status = "okay"; + /* 16MB of flash */ + reg = <0x30000000 0x01000000>; + + partition@0 { + label = "RedBoot"; + reg = <0x00000000 0x00020000>; + read-only; + }; + partition@20000 { + label = "Kernel"; + reg = <0x00020000 0x00300000>; + }; + partition@320000 { + label = "Ramdisk"; + reg = <0x00320000 0x00600000>; + }; + partition@920000 { + label = "Application"; + reg = <0x00920000 0x00600000>; + }; + partition@f20000 { + label = "VCTL"; + reg = <0x00f20000 0x00020000>; + read-only; + }; + partition@f40000 { + label = "CurConf"; + reg = <0x00f40000 0x000a0000>; + read-only; + }; + partition@fe0000 { + label = "FIS directory"; + reg = <0x00fe0000 0x00020000>; + read-only; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/gemini-rut1xx.dts b/arch/arm/boot/dts/gemini-rut1xx.dts new file mode 100644 index 000000000000..7b920bfbda32 --- /dev/null +++ b/arch/arm/boot/dts/gemini-rut1xx.dts @@ -0,0 +1,65 @@ +/* + * Device Tree file for Teltonika RUT1xx + */ + +/dts-v1/; + +#include "gemini.dtsi" +#include <dt-bindings/input/input.h> + +/ { + model = "Teltonika RUT1xx"; + compatible = "teltonika,rut1xx", "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { /* 128 MB */ + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@28 { + debounce_interval = <50>; + wakeup-source; + linux,code = <KEY_SETUP>; + label = "Reset to defaults"; + gpios = <&gpio1 28 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + led@7 { + /* FIXME: add the LED color */ + label = "rut1xx::gsm"; + gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + led@31 { + /* FIXME: add the LED color */ + label = "rut1xx::power"; + gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "heartbeat"; + }; + }; + + soc { + flash@30000000 { + status = "okay"; + /* 8MB of flash */ + reg = <0x30000000 0x00800000>; + /* TODO: add flash partitions here */ + }; + }; +}; diff --git a/arch/arm/boot/dts/gemini-sq201.dts b/arch/arm/boot/dts/gemini-sq201.dts new file mode 100644 index 000000000000..46309e79cc7b --- /dev/null +++ b/arch/arm/boot/dts/gemini-sq201.dts @@ -0,0 +1,118 @@ +/* + * Device Tree file for ITian Square One SQ201 NAS + */ + +/dts-v1/; + +#include "gemini.dtsi" +#include <dt-bindings/input/input.h> + +/ { + model = "ITian Square One SQ201"; + compatible = "itian,sq201", "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { /* 128 MB */ + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@18 { + debounce_interval = <50>; + wakeup-source; + linux,code = <KEY_SETUP>; + label = "factory reset"; + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + led@20 { + label = "sq201:green:info"; + gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + led@31 { + label = "sq201:green:usb"; + gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "usb-host"; + }; + }; + + soc { + flash@30000000 { + status = "okay"; + /* 16MB of flash */ + reg = <0x30000000 0x01000000>; + + partition@0 { + label = "RedBoot"; + reg = <0x00000000 0x00120000>; + read-only; + }; + partition@120000 { + label = "Kernel"; + reg = <0x00120000 0x00200000>; + }; + partition@320000 { + label = "Ramdisk"; + reg = <0x00320000 0x00600000>; + }; + partition@920000 { + label = "Application"; + reg = <0x00920000 0x00600000>; + }; + partition@f20000 { + label = "VCTL"; + reg = <0x00f20000 0x00020000>; + read-only; + }; + partition@f40000 { + label = "CurConf"; + reg = <0x00f40000 0x000a0000>; + read-only; + }; + partition@fe0000 { + label = "FIS directory"; + reg = <0x00fe0000 0x00020000>; + read-only; + }; + }; + + pci@50000000 { + status = "okay"; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + <0x4800 0 0 1 &pci_intc 0>, /* Slot 9 */ + <0x4800 0 0 2 &pci_intc 1>, + <0x4800 0 0 3 &pci_intc 2>, + <0x4800 0 0 4 &pci_intc 3>, + <0x5000 0 0 1 &pci_intc 1>, /* Slot 10 */ + <0x5000 0 0 2 &pci_intc 2>, + <0x5000 0 0 3 &pci_intc 3>, + <0x5000 0 0 4 &pci_intc 0>, + <0x5800 0 0 1 &pci_intc 2>, /* Slot 11 */ + <0x5800 0 0 2 &pci_intc 3>, + <0x5800 0 0 3 &pci_intc 0>, + <0x5800 0 0 4 &pci_intc 1>, + <0x6000 0 0 1 &pci_intc 3>, /* Slot 12 */ + <0x6000 0 0 2 &pci_intc 0>, + <0x6000 0 0 3 &pci_intc 1>, + <0x6000 0 0 4 &pci_intc 2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/gemini-wbd111.dts b/arch/arm/boot/dts/gemini-wbd111.dts new file mode 100644 index 000000000000..63b756e3bf5a --- /dev/null +++ b/arch/arm/boot/dts/gemini-wbd111.dts @@ -0,0 +1,102 @@ +/* + * Device Tree file for Wiliboard WBD-111 + */ + +/dts-v1/; + +#include "gemini.dtsi" +#include <dt-bindings/input/input.h> + +/ { + model = "Wiliboard WBD-111"; + compatible = "wiliboard,wbd111", "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { /* 128 MB */ + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@5 { + debounce_interval = <50>; + wakeup-source; + linux,code = <KEY_SETUP>; + label = "reset"; + gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + + led@1 { + label = "wbd111:red:L3"; + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + led@2 { + label = "wbd111:green:L4"; + gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + led@3 { + label = "wbd111:red:L4"; + gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + led@5 { + label = "wbd111:green:L3"; + gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + }; + + soc { + flash@30000000 { + status = "okay"; + /* 8MB of flash */ + reg = <0x30000000 0x00800000>; + + partition@0 { + label = "RedBoot"; + reg = <0x00000000 0x00020000>; + read-only; + }; + partition@20000 { + label = "kernel"; + reg = <0x00020000 0x00100000>; + }; + partition@120000 { + label = "rootfs"; + reg = <0x00120000 0x006a0000>; + }; + partition@7c0000 { + label = "VCTL"; + reg = <0x007c0000 0x00010000>; + read-only; + }; + partition@7d0000 { + label = "cfg"; + reg = <0x007d0000 0x00010000>; + read-only; + }; + partition@7e0000 { + label = "FIS"; + reg = <0x007e0000 0x00010000>; + read-only; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/gemini-wbd222.dts b/arch/arm/boot/dts/gemini-wbd222.dts new file mode 100644 index 000000000000..9747f5a47807 --- /dev/null +++ b/arch/arm/boot/dts/gemini-wbd222.dts @@ -0,0 +1,102 @@ +/* + * Device Tree file for Wiliboard WBD-222 + */ + +/dts-v1/; + +#include "gemini.dtsi" +#include <dt-bindings/input/input.h> + +/ { + model = "Wiliboard WBD-222"; + compatible = "wiliboard,wbd222", "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { /* 128 MB */ + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@5 { + debounce_interval = <50>; + wakeup-source; + linux,code = <KEY_SETUP>; + label = "reset"; + gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + + led@1 { + label = "wbd111:red:L3"; + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + led@2 { + label = "wbd111:green:L4"; + gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + led@3 { + label = "wbd111:red:L4"; + gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + led@5 { + label = "wbd111:green:L3"; + gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + }; + + soc { + flash@30000000 { + status = "okay"; + /* 8MB of flash */ + reg = <0x30000000 0x00800000>; + + partition@0 { + label = "RedBoot"; + reg = <0x00000000 0x00020000>; + read-only; + }; + partition@20000 { + label = "kernel"; + reg = <0x00020000 0x00100000>; + }; + partition@120000 { + label = "rootfs"; + reg = <0x00120000 0x006a0000>; + }; + partition@7c0000 { + label = "VCTL"; + reg = <0x007c0000 0x00010000>; + read-only; + }; + partition@7d0000 { + label = "cfg"; + reg = <0x007d0000 0x00010000>; + read-only; + }; + partition@7e0000 { + label = "FIS"; + reg = <0x007e0000 0x00010000>; + read-only; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/gemini.dtsi b/arch/arm/boot/dts/gemini.dtsi new file mode 100644 index 000000000000..b8d011bdcc76 --- /dev/null +++ b/arch/arm/boot/dts/gemini.dtsi @@ -0,0 +1,156 @@ +/* + * Device Tree file for Cortina systems Gemini SoC + */ + +/include/ "skeleton.dtsi" + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/gpio/gpio.h> + +/ { + soc { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "simple-bus"; + interrupt-parent = <&intcon>; + + flash@30000000 { + compatible = "cortina,gemini-flash", "cfi-flash"; + syscon = <&syscon>; + bank-width = <2>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + + syscon: syscon@40000000 { + compatible = "cortina,gemini-syscon", "syscon", "simple-mfd"; + reg = <0x40000000 0x1000>; + + syscon-reboot { + compatible = "syscon-reboot"; + regmap = <&syscon>; + /* GLOBAL_RESET register */ + offset = <0x0c>; + /* RESET_GLOBAL | RESET_CPU1 */ + mask = <0xC0000000>; + }; + }; + + watchdog@41000000 { + compatible = "cortina,gemini-watchdog"; + reg = <0x41000000 0x1000>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0: serial@42000000 { + compatible = "ns16550a"; + reg = <0x42000000 0x100>; + clock-frequency = <48000000>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + }; + + timer@43000000 { + compatible = "cortina,gemini-timer"; + reg = <0x43000000 0x1000>; + interrupt-parent = <&intcon>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>, /* Timer 1 */ + <15 IRQ_TYPE_EDGE_FALLING>, /* Timer 2 */ + <16 IRQ_TYPE_EDGE_FALLING>; /* Timer 3 */ + syscon = <&syscon>; + }; + + rtc@45000000 { + compatible = "cortina,gemini-rtc"; + reg = <0x45000000 0x100>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + }; + + intcon: interrupt-controller@48000000 { + compatible = "faraday,ftintc010"; + reg = <0x48000000 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + power-controller@4b000000 { + compatible = "cortina,gemini-power-controller"; + reg = <0x4b000000 0x100>; + interrupts = <26 IRQ_TYPE_EDGE_RISING>; + }; + + gpio0: gpio@4d000000 { + compatible = "cortina,gemini-gpio", "faraday,ftgpio010"; + reg = <0x4d000000 0x100>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@4e000000 { + compatible = "cortina,gemini-gpio", "faraday,ftgpio010"; + reg = <0x4e000000 0x100>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@4f000000 { + compatible = "cortina,gemini-gpio", "faraday,ftgpio010"; + reg = <0x4f000000 0x100>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pci@50000000 { + compatible = "cortina,gemini-pci", "faraday,ftpci100"; + /* + * The first 256 bytes in the IO range is actually used + * to configure the host bridge. + */ + reg = <0x50000000 0x100>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + status = "disabled"; + + bus-range = <0x00 0xff>; + /* PCI ranges mappings */ + ranges = + /* 1MiB I/O space 0x50000000-0x500fffff */ + <0x01000000 0 0 0x50000000 0 0x00100000>, + /* 128MiB non-prefetchable memory 0x58000000-0x5fffffff */ + <0x02000000 0 0x58000000 0x58000000 0 0x08000000>; + + /* DMA ranges */ + dma-ranges = + /* 128MiB at 0x00000000-0x07ffffff */ + <0x02000000 0 0x00000000 0x00000000 0 0x08000000>, + /* 64MiB at 0x00000000-0x03ffffff */ + <0x02000000 0 0x00000000 0x00000000 0 0x04000000>, + /* 64MiB at 0x00000000-0x03ffffff */ + <0x02000000 0 0x00000000 0x00000000 0 0x04000000>; + + /* + * This PCI host bridge variant has a cascaded interrupt + * controller embedded in the host bridge. + */ + pci_intc: interrupt-controller { + interrupt-parent = <&intcon>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts index 9300711f1ea3..db39bd6b8e00 100644 --- a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts +++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts @@ -179,8 +179,6 @@ }; &usbotg { - phy_type = "utmi"; - dr_mode = "otg"; external-vbus-divider; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx25-pdk.dts b/arch/arm/boot/dts/imx25-pdk.dts index 70292101ba03..d921dd2ed676 100644 --- a/arch/arm/boot/dts/imx25-pdk.dts +++ b/arch/arm/boot/dts/imx25-pdk.dts @@ -309,8 +309,6 @@ }; &usbotg { - phy_type = "utmi"; - dr_mode = "otg"; external-vbus-divider; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx25-pinfunc.h b/arch/arm/boot/dts/imx25-pinfunc.h index f840f03ad171..6c63dca1b9b8 100644 --- a/arch/arm/boot/dts/imx25-pinfunc.h +++ b/arch/arm/boot/dts/imx25-pinfunc.h @@ -17,8 +17,6 @@ * <mux_reg conf_reg input_reg mux_mode input_val> */ -#define MX25_PAD_TDO__TDO 0x000 0x3e8 0x000 0x00 0x000 - #define MX25_PAD_A10__A10 0x008 0x000 0x000 0x00 0x000 #define MX25_PAD_A10__GPIO_4_0 0x008 0x000 0x000 0x05 0x000 @@ -68,7 +66,6 @@ #define MX25_PAD_A22__A22 0x030 0x000 0x000 0x00 0x000 #define MX25_PAD_A22__GPIO_2_8 0x030 0x000 0x000 0x05 0x000 -#define MX25_PAD_A22__FEC_TDATA2 0x030 0x000 0x000 0x07 0x000 #define MX25_PAD_A22__SIM2_VEN1 0x030 0x000 0x000 0x06 0x000 #define MX25_PAD_A22__FEC_TDATA2 0x030 0x000 0x000 0x07 0x000 @@ -542,6 +539,8 @@ #define MX25_PAD_RTCK__OWIRE 0x1ec 0x3e4 0x000 0x01 0x000 #define MX25_PAD_RTCK__GPIO_3_14 0x1ec 0x3e4 0x000 0x05 0x000 +#define MX25_PAD_TDO__TDO 0x000 0x3e8 0x000 0x00 0x000 + #define MX25_PAD_DE_B__DE_B 0x1f0 0x3ec 0x000 0x00 0x000 #define MX25_PAD_DE_B__GPIO_2_20 0x1f0 0x3ec 0x000 0x05 0x000 diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index e0ba55016a04..0cdf333336cd 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -93,6 +93,11 @@ reg = <0x43f00000 0x100000>; ranges; + aips1: bridge@43f00000 { + compatible = "fsl,imx25-aips"; + reg = <0x43f00000 0x4000>; + }; + i2c1: i2c@43f80000 { #address-cells = <1>; #size-cells = <0>; @@ -342,6 +347,11 @@ reg = <0x53f00000 0x100000>; ranges; + aips2: bridge@53f00000 { + compatible = "fsl,imx25-aips"; + reg = <0x53f00000 0x4000>; + }; + clks: ccm@53f80000 { compatible = "fsl,imx25-ccm"; reg = <0x53f80000 0x4000>; @@ -544,6 +554,8 @@ clock-names = "ipg", "ahb", "per"; fsl,usbmisc = <&usbmisc 0>; fsl,usbphy = <&usbphy0>; + phy_type = "utmi"; + dr_mode = "otg"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx28-duckbill-2-485.dts b/arch/arm/boot/dts/imx28-duckbill-2-485.dts new file mode 100644 index 000000000000..bd3fd470f9c3 --- /dev/null +++ b/arch/arm/boot/dts/imx28-duckbill-2-485.dts @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2015-2017 I2SE GmbH <info@i2se.com> + * Copyright (C) 2016 Michael Heimpold <mhei@heimpold.de> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/gpio/gpio.h> +#include "imx28.dtsi" + +/ { + model = "I2SE Duckbill 2 485"; + compatible = "i2se,duckbill-2-485", "i2se,duckbill-2", "fsl,imx28"; + + memory { + reg = <0x40000000 0x08000000>; + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a + &mmc0_cd_cfg &mmc0_sck_cfg>; + bus-width = <8>; + vmmc-supply = <®_3p3v>; + status = "okay"; + non-removable; + }; + + ssp2: ssp@80014000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_4bit_pins_b + &mmc2_cd_cfg &mmc2_sck_cfg_b>; + bus-width = <4>; + vmmc-supply = <®_3p3v>; + status = "okay"; + }; + + pinctrl@80018000 { + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_a>; + + hog_pins_a: hog@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D17__GPIO_1_17 /* Revision detection */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_reset_pin: mac0-phy-reset@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_ALE__GPIO_0_26 /* PHY Reset */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_int_pin: mac0-phy-int@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_D07__GPIO_0_7 /* PHY Interrupt */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + led_pins: leds@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_SAIF0_MCLK__GPIO_3_20 + MX28_PAD_SAIF0_LRCLK__GPIO_3_21 + MX28_PAD_I2C0_SCL__GPIO_3_24 + MX28_PAD_I2C0_SDA__GPIO_3_25 + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + }; + }; + + apbx@80040000 { + lradc@80050000 { + status = "okay"; + }; + + auart0: serial@8006a000 { + pinctrl-names = "default"; + pinctrl-0 = <&auart0_2pins_a>; + status = "okay"; + }; + + duart: serial@80074000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + + usbphy0: usbphy@8007c000 { + status = "okay"; + }; + }; + }; + + ahb@80080000 { + usb0: usb@80080000 { + status = "okay"; + dr_mode = "peripheral"; + }; + + mac0: ethernet@800f0000 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>, <&mac0_phy_reset_pin>; + phy-supply = <®_3p3v>; + phy-reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + phy-reset-duration = <25>; + phy-handle = <ðphy>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_phy_int_pin>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + max-speed = <100>; + }; + }; + }; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + + status-red { + label = "duckbill:red:status"; + gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + status-green { + label = "duckbill:green:status"; + gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + rs485-red { + label = "duckbill:red:rs485"; + gpios = <&gpio3 24 GPIO_ACTIVE_LOW>; + }; + + rs485-green { + label = "duckbill:green:rs485"; + gpios = <&gpio3 25 GPIO_ACTIVE_LOW>; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx28-duckbill-2-enocean.dts b/arch/arm/boot/dts/imx28-duckbill-2-enocean.dts new file mode 100644 index 000000000000..4450047885eb --- /dev/null +++ b/arch/arm/boot/dts/imx28-duckbill-2-enocean.dts @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2015-2017 I2SE GmbH <info@i2se.com> + * Copyright (C) 2016 Michael Heimpold <mhei@heimpold.de> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/input/input.h> +#include <dt-bindings/gpio/gpio.h> +#include "imx28.dtsi" + +/ { + model = "I2SE Duckbill 2 EnOcean"; + compatible = "i2se,duckbill-2-enocean", "i2se,duckbill-2", "fsl,imx28"; + + memory { + reg = <0x40000000 0x08000000>; + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a + &mmc0_cd_cfg &mmc0_sck_cfg>; + bus-width = <8>; + vmmc-supply = <®_3p3v>; + status = "okay"; + non-removable; + }; + + ssp2: ssp@80014000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_4bit_pins_b + &mmc2_cd_cfg &mmc2_sck_cfg_b>; + bus-width = <4>; + vmmc-supply = <®_3p3v>; + status = "okay"; + }; + + pinctrl@80018000 { + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_a>; + + hog_pins_a: hog@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D17__GPIO_1_17 /* Revision detection */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_reset_pin: mac0-phy-reset@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_ALE__GPIO_0_26 /* PHY Reset */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_int_pin: mac0-phy-int@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_D07__GPIO_0_7 /* PHY Interrupt */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + led_pins: leds@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_SAIF0_MCLK__GPIO_3_20 + MX28_PAD_SAIF0_LRCLK__GPIO_3_21 + MX28_PAD_AUART0_CTS__GPIO_3_2 + MX28_PAD_I2C0_SCL__GPIO_3_24 + MX28_PAD_I2C0_SDA__GPIO_3_25 + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + enocean_button: enocean-button@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_AUART0_RTS__GPIO_3_3 + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + }; + }; + + apbx@80040000 { + lradc@80050000 { + status = "okay"; + }; + + auart0: serial@8006a000 { + pinctrl-names = "default"; + pinctrl-0 = <&auart0_2pins_a>; + status = "okay"; + }; + + duart: serial@80074000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + + usbphy0: usbphy@8007c000 { + status = "okay"; + }; + }; + }; + + ahb@80080000 { + usb0: usb@80080000 { + status = "okay"; + dr_mode = "peripheral"; + }; + + mac0: ethernet@800f0000 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>, <&mac0_phy_reset_pin>; + phy-supply = <®_3p3v>; + phy-reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + phy-reset-duration = <25>; + phy-handle = <ðphy>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_phy_int_pin>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + max-speed = <100>; + }; + }; + }; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + + status-red { + label = "duckbill:red:status"; + gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + status-green { + label = "duckbill:green:status"; + gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + enocean-blue { + label = "duckbill:blue:enocean"; + gpios = <&gpio3 24 GPIO_ACTIVE_LOW>; + }; + + enocean-red { + label = "duckbill:red:enocean"; + gpios = <&gpio3 25 GPIO_ACTIVE_LOW>; + }; + + enocean-green { + label = "duckbill:green:enocean"; + gpios = <&gpio3 2 GPIO_ACTIVE_LOW>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&enocean_button>; + + enocean { + label = "EnOcean"; + linux,code = <KEY_NEW>; + gpios = <&gpio3 3 GPIO_ACTIVE_HIGH>; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx28-duckbill-2-spi.dts b/arch/arm/boot/dts/imx28-duckbill-2-spi.dts new file mode 100644 index 000000000000..927732efca98 --- /dev/null +++ b/arch/arm/boot/dts/imx28-duckbill-2-spi.dts @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2015-2017 I2SE GmbH <info@i2se.com> + * Copyright (C) 2016 Michael Heimpold <mhei@heimpold.de> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/gpio/gpio.h> +#include "imx28.dtsi" + +/ { + model = "I2SE Duckbill 2 SPI"; + compatible = "i2se,duckbill-2-spi", "i2se,duckbill-2", "fsl,imx28"; + + aliases { + ethernet1 = &qca7000; + }; + + memory { + reg = <0x40000000 0x08000000>; + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a + &mmc0_cd_cfg &mmc0_sck_cfg>; + bus-width = <8>; + vmmc-supply = <®_3p3v>; + status = "okay"; + non-removable; + }; + + ssp2: ssp@80014000 { + compatible = "fsl,imx28-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi2_pins_a>; + status = "okay"; + + qca7000: ethernet@0 { + reg = <0>; + compatible = "qca,qca7000"; + pinctrl-names = "default"; + pinctrl-0 = <&qca7000_pins>; + interrupt-parent = <&gpio3>; + interrupts = <3 IRQ_TYPE_EDGE_RISING>; + spi-cpha; + spi-cpol; + spi-max-frequency = <8000000>; + }; + }; + + pinctrl@80018000 { + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_a>; + + hog_pins_a: hog@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D17__GPIO_1_17 /* Revision detection */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_reset_pin: mac0-phy-reset@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_ALE__GPIO_0_26 /* PHY Reset */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_int_pin: mac0-phy-int@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_D07__GPIO_0_7 /* PHY Interrupt */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + led_pins: led@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_SAIF0_MCLK__GPIO_3_20 + MX28_PAD_SAIF0_LRCLK__GPIO_3_21 + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + qca7000_pins: qca7000@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_AUART0_RTS__GPIO_3_3 /* Interrupt */ + MX28_PAD_LCD_D13__GPIO_1_13 /* QCA7K reset */ + MX28_PAD_LCD_D14__GPIO_1_14 /* GPIO 0 */ + MX28_PAD_LCD_D15__GPIO_1_15 /* GPIO 1 */ + MX28_PAD_LCD_D18__GPIO_1_18 /* GPIO 2 */ + MX28_PAD_LCD_D21__GPIO_1_21 /* GPIO 3 */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + }; + }; + + apbx@80040000 { + lradc@80050000 { + status = "okay"; + }; + + duart: serial@80074000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + + usbphy0: usbphy@8007c000 { + status = "okay"; + }; + }; + }; + + ahb@80080000 { + usb0: usb@80080000 { + status = "okay"; + dr_mode = "peripheral"; + }; + + mac0: ethernet@800f0000 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>, <&mac0_phy_reset_pin>; + phy-supply = <®_3p3v>; + phy-reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + phy-reset-duration = <25>; + phy-handle = <ðphy>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_phy_int_pin>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + max-speed = <100>; + }; + }; + }; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + + status-red { + label = "duckbill:red:status"; + gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + status-green { + label = "duckbill:green:status"; + gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx28-duckbill-2.dts b/arch/arm/boot/dts/imx28-duckbill-2.dts new file mode 100644 index 000000000000..7fa3d759505c --- /dev/null +++ b/arch/arm/boot/dts/imx28-duckbill-2.dts @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015-2017 I2SE GmbH <info@i2se.com> + * Copyright (C) 2016 Michael Heimpold <mhei@heimpold.de> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/gpio/gpio.h> +#include "imx28.dtsi" + +/ { + model = "I2SE Duckbill 2"; + compatible = "i2se,duckbill-2", "fsl,imx28"; + + memory { + reg = <0x40000000 0x08000000>; + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a + &mmc0_cd_cfg &mmc0_sck_cfg>; + bus-width = <8>; + vmmc-supply = <®_3p3v>; + status = "okay"; + non-removable; + }; + + ssp2: ssp@80014000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_4bit_pins_b + &mmc2_cd_cfg &mmc2_sck_cfg_b>; + bus-width = <4>; + vmmc-supply = <®_3p3v>; + status = "okay"; + }; + + pinctrl@80018000 { + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_a>; + + hog_pins_a: hog@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D17__GPIO_1_17 /* Revision detection */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_reset_pin: mac0-phy-reset@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_ALE__GPIO_0_26 /* PHY Reset */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_int_pin: mac0-phy-int@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_D07__GPIO_0_7 /* PHY Interrupt */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + led_pins: leds@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_SAIF0_MCLK__GPIO_3_20 + MX28_PAD_SAIF0_LRCLK__GPIO_3_21 + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + }; + }; + + apbx@80040000 { + lradc@80050000 { + status = "okay"; + }; + + i2c0: i2c@80058000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + }; + + auart0: serial@8006a000 { + pinctrl-names = "default"; + pinctrl-0 = <&auart0_2pins_a>; + status = "okay"; + }; + + duart: serial@80074000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + + usbphy0: usbphy@8007c000 { + status = "okay"; + }; + }; + }; + + ahb@80080000 { + usb0: usb@80080000 { + status = "okay"; + dr_mode = "peripheral"; + }; + + mac0: ethernet@800f0000 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>, <&mac0_phy_reset_pin>; + phy-supply = <®_3p3v>; + phy-reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + phy-reset-duration = <25>; + phy-handle = <ðphy>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_phy_int_pin>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + max-speed = <100>; + }; + }; + }; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + + status-red { + label = "duckbill:red:status"; + gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + status-green { + label = "duckbill:green:status"; + gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx28-duckbill.dts b/arch/arm/boot/dts/imx28-duckbill.dts index ce1a7effba37..3e4385d4ed78 100644 --- a/arch/arm/boot/dts/imx28-duckbill.dts +++ b/arch/arm/boot/dts/imx28-duckbill.dts @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Michael Heimpold <mhei@heimpold.de> + * Copyright (C) 2013-2014,2016 Michael Heimpold <mhei@heimpold.de> + * Copyright (C) 2015-2017 I2SE GmbH <info@i2se.com> * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License @@ -10,6 +11,7 @@ */ /dts-v1/; +#include <dt-bindings/gpio/gpio.h> #include "imx28.dtsi" / { @@ -32,6 +34,13 @@ status = "okay"; }; + ssp2: ssp@80014000 { + compatible = "fsl,imx28-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi2_pins_a>; + status = "okay"; + }; + pinctrl@80018000 { pinctrl-names = "default"; pinctrl-0 = <&hog_pins_a>; @@ -39,14 +48,24 @@ hog_pins_a: hog@0 { reg = <0>; fsl,pinmux-ids = < - MX28_PAD_SSP0_DATA7__GPIO_2_7 /* PHY Reset */ + MX28_PAD_LCD_D17__GPIO_1_17 /* Revision detection */ + >; + fsl,drive-strength = <MXS_DRIVE_4mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + + mac0_phy_reset_pin: mac0-phy-reset@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_SSP0_DATA7__GPIO_2_7 /* PHY Reset */ >; fsl,drive-strength = <MXS_DRIVE_4mA>; fsl,voltage = <MXS_VOLTAGE_HIGH>; fsl,pull-up = <MXS_PULL_DISABLE>; }; - led_pins_a: led_gpio@0 { + led_pins: leds@0 { reg = <0>; fsl,pinmux-ids = < MX28_PAD_AUART1_RX__GPIO_3_4 @@ -60,6 +79,22 @@ }; apbx@80040000 { + lradc@80050000 { + status = "okay"; + }; + + i2c0: i2c@80058000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + }; + + auart0: serial@8006a000 { + pinctrl-names = "default"; + pinctrl-0 = <&auart0_2pins_a>; + status = "okay"; + }; + duart: serial@80074000 { pinctrl-names = "default"; pinctrl-0 = <&duart_pins_a>; @@ -75,47 +110,43 @@ ahb@80080000 { usb0: usb@80080000 { status = "okay"; + dr_mode = "peripheral"; }; mac0: ethernet@800f0000 { phy-mode = "rmii"; pinctrl-names = "default"; - pinctrl-0 = <&mac0_pins_a>; + pinctrl-0 = <&mac0_pins_a>, <&mac0_phy_reset_pin>; phy-supply = <®_3p3v>; phy-reset-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>; - phy-reset-duration = <100>; + phy-reset-duration = <25>; status = "okay"; }; }; - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - reg_3p3v: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - regulator-name = "3P3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; }; leds { compatible = "gpio-leds"; pinctrl-names = "default"; - pinctrl-0 = <&led_pins_a>; + pinctrl-0 = <&led_pins>; - status { - label = "duckbill:green:status"; - gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; - }; - - failure { + status-red { label = "duckbill:red:status"; gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + status-green { + label = "duckbill:green:status"; + gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; }; }; }; diff --git a/arch/arm/boot/dts/imx28-m28cu3.dts b/arch/arm/boot/dts/imx28-m28cu3.dts index 2df63bee6f4e..bb5329479c62 100644 --- a/arch/arm/boot/dts/imx28-m28cu3.dts +++ b/arch/arm/boot/dts/imx28-m28cu3.dts @@ -57,7 +57,7 @@ pinctrl-names = "default"; pinctrl-0 = <&mmc2_4bit_pins_a &mmc2_cd_cfg - &mmc2_sck_cfg>; + &mmc2_sck_cfg_a>; bus-width = <4>; vmmc-supply = <®_vddio_sd1>; status = "okay"; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 148fcf4d3b98..2f4ebe0318d3 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -590,6 +590,22 @@ fsl,pull-up = <MXS_PULL_ENABLE>; }; + mmc2_4bit_pins_b: mmc2-4bit@1 { + reg = <1>; + fsl,pinmux-ids = < + MX28_PAD_SSP2_SCK__SSP2_SCK + MX28_PAD_SSP2_MOSI__SSP2_CMD + MX28_PAD_SSP2_MISO__SSP2_D0 + MX28_PAD_SSP2_SS0__SSP2_D3 + MX28_PAD_SSP2_SS1__SSP2_D1 + MX28_PAD_SSP2_SS2__SSP2_D2 + MX28_PAD_AUART1_RX__SSP2_CARD_DETECT + >; + fsl,drive-strength = <MXS_DRIVE_8mA>; + fsl,voltage = <MXS_VOLTAGE_HIGH>; + fsl,pull-up = <MXS_PULL_ENABLE>; + }; + mmc2_cd_cfg: mmc2-cd-cfg { fsl,pinmux-ids = < MX28_PAD_AUART1_RX__SSP2_CARD_DETECT @@ -597,7 +613,8 @@ fsl,pull-up = <MXS_PULL_DISABLE>; }; - mmc2_sck_cfg: mmc2-sck-cfg { + mmc2_sck_cfg_a: mmc2-sck-cfg@0 { + reg = <0>; fsl,pinmux-ids = < MX28_PAD_SSP0_DATA7__SSP2_SCK >; @@ -605,6 +622,15 @@ fsl,pull-up = <MXS_PULL_DISABLE>; }; + mmc2_sck_cfg_b: mmc2-sck-cfg@1 { + reg = <1>; + fsl,pinmux-ids = < + MX28_PAD_SSP2_SCK__SSP2_SCK + >; + fsl,drive-strength = <MXS_DRIVE_12mA>; + fsl,pull-up = <MXS_PULL_DISABLE>; + }; + i2c0_pins_a: i2c0@0 { reg = <0>; fsl,pinmux-ids = < diff --git a/arch/arm/boot/dts/imx50.dtsi b/arch/arm/boot/dts/imx50.dtsi index ceae909e2201..2a98afcd8a4e 100644 --- a/arch/arm/boot/dts/imx50.dtsi +++ b/arch/arm/boot/dts/imx50.dtsi @@ -109,7 +109,7 @@ ranges; esdhc1: esdhc@50004000 { - compatible = "fsl,imx50-esdhc"; + compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc"; reg = <0x50004000 0x4000>; interrupts = <1>; clocks = <&clks IMX5_CLK_ESDHC1_IPG_GATE>, @@ -121,7 +121,7 @@ }; esdhc2: esdhc@50008000 { - compatible = "fsl,imx50-esdhc"; + compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc"; reg = <0x50008000 0x4000>; interrupts = <2>; clocks = <&clks IMX5_CLK_ESDHC2_IPG_GATE>, @@ -170,7 +170,7 @@ }; esdhc3: esdhc@50020000 { - compatible = "fsl,imx50-esdhc"; + compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc"; reg = <0x50020000 0x4000>; interrupts = <3>; clocks = <&clks IMX5_CLK_ESDHC3_IPG_GATE>, @@ -182,7 +182,7 @@ }; esdhc4: esdhc@50024000 { - compatible = "fsl,imx50-esdhc"; + compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc"; reg = <0x50024000 0x4000>; interrupts = <4>; clocks = <&clks IMX5_CLK_ESDHC4_IPG_GATE>, diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index f4c158cce908..d3d662e37677 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -88,8 +88,8 @@ }; ldo7_reg: ldo7 { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3600000>; + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; }; ldo8_reg: ldo8 { diff --git a/arch/arm/boot/dts/imx53-qsrb.dts b/arch/arm/boot/dts/imx53-qsrb.dts index 479ca4c9e384..de2215832372 100644 --- a/arch/arm/boot/dts/imx53-qsrb.dts +++ b/arch/arm/boot/dts/imx53-qsrb.dts @@ -128,8 +128,8 @@ vdac_reg: vdac { regulator-name = "VDAC"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2775000>; + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; }; vgen1_reg: vgen1 { diff --git a/arch/arm/boot/dts/imx6dl-gw5903.dts b/arch/arm/boot/dts/imx6dl-gw5903.dts new file mode 100644 index 000000000000..103261ea9334 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-gw5903.dts @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Gateworks Corporation + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file 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. + * + * You should have received a copy of the GNU General Public + * License along with this file; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-gw5903.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 Duallite/Solo GW5903"; + compatible = "gw,imx6dl-gw5903", "gw,ventana", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-gw5904.dts b/arch/arm/boot/dts/imx6dl-gw5904.dts new file mode 100644 index 000000000000..9c6d3cd3d6a7 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-gw5904.dts @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Gateworks Corporation + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file 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. + * + * You should have received a copy of the GNU General Public + * License along with this file; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-gw5904.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 DualLite/Solo GW5904"; + compatible = "gw,imx6dl-gw5904", "gw,ventana", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6q-b450v3.dts b/arch/arm/boot/dts/imx6q-b450v3.dts index 116bebb5e435..404a93d9596b 100644 --- a/arch/arm/boot/dts/imx6q-b450v3.dts +++ b/arch/arm/boot/dts/imx6q-b450v3.dts @@ -104,4 +104,11 @@ output-low; line-name = "PCA9539-P05"; }; + + P07 { + gpio-hog; + gpios = <7 0>; + output-low; + line-name = "PCA9539-P07"; + }; }; diff --git a/arch/arm/boot/dts/imx6q-b650v3.dts b/arch/arm/boot/dts/imx6q-b650v3.dts index 33f5c436c09f..7f9f176901d4 100644 --- a/arch/arm/boot/dts/imx6q-b650v3.dts +++ b/arch/arm/boot/dts/imx6q-b650v3.dts @@ -97,6 +97,13 @@ output-low; line-name = "PCA9539-P05"; }; + + P07 { + gpio-hog; + gpios = <7 0>; + output-low; + line-name = "PCA9539-P07"; + }; }; &usbphy1 { diff --git a/arch/arm/boot/dts/imx6q-b850v3.dts b/arch/arm/boot/dts/imx6q-b850v3.dts index d78514c92349..2c1e98e0cf7b 100644 --- a/arch/arm/boot/dts/imx6q-b850v3.dts +++ b/arch/arm/boot/dts/imx6q-b850v3.dts @@ -72,6 +72,14 @@ fsl,data-mapping = "spwg"; fsl,data-width = <24>; status = "okay"; + + port@4 { + reg = <4>; + + lvds0_out: endpoint { + remote-endpoint = <&stdp4028_in>; + }; + }; }; }; @@ -142,3 +150,65 @@ reg = <0x4a>; }; }; + +&mux2_i2c2 { + clock-frequency = <100000>; + + stdp2690@72 { + compatible = "megachips,stdp2690-ge-b850v3-fw"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x72>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + stdp2690_in: endpoint { + remote-endpoint = <&stdp4028_out>; + }; + }; + + port@1 { + reg = <1>; + + stdp2690_out: endpoint { + /* Connector for external display */ + }; + }; + }; + }; + + stdp4028@73 { + compatible = "megachips,stdp4028-ge-b850v3-fw"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x73>; + interrupt-parent = <&gpio2>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + stdp4028_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + + port@1 { + reg = <1>; + + stdp4028_out: endpoint { + remote-endpoint = <&stdp2690_in>; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-bx50v3.dtsi b/arch/arm/boot/dts/imx6q-bx50v3.dtsi index 36d6bb39593a..c90b26f00e24 100644 --- a/arch/arm/boot/dts/imx6q-bx50v3.dtsi +++ b/arch/arm/boot/dts/imx6q-bx50v3.dtsi @@ -102,7 +102,7 @@ m25_eeprom: m25p80@0 { compatible = "atmel,at25"; - spi-max-frequency = <20000000>; + spi-max-frequency = <10000000>; size = <0x8000>; pagesize = <64>; reg = <0>; @@ -183,20 +183,6 @@ interrupt-parent = <&gpio2>; interrupts = <3 IRQ_TYPE_LEVEL_LOW>; - P06 { - gpio-hog; - gpios = <6 0>; - output-low; - line-name = "PCA9539-P06"; - }; - - P07 { - gpio-hog; - gpios = <7 0>; - output-low; - line-name = "PCA9539-P07"; - }; - P10 { gpio-hog; gpios = <8 0>; diff --git a/arch/arm/boot/dts/imx6q-cm-fx6.dts b/arch/arm/boot/dts/imx6q-cm-fx6.dts index d8a5789a4bc8..66cac5328b86 100644 --- a/arch/arm/boot/dts/imx6q-cm-fx6.dts +++ b/arch/arm/boot/dts/imx6q-cm-fx6.dts @@ -43,6 +43,7 @@ /dts-v1/; #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/sound/fsl-imx-audmux.h> #include "imx6q.dtsi" / { @@ -90,6 +91,34 @@ enable-active-high; }; + sound-analog { + compatible = "simple-audio-card"; + simple-audio-card,name = "On-board analog audio"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Line", "Line Out", + "Microphone", "Mic Jack", + "Line", "Line In"; + simple-audio-card,routing = + "Headphone Jack", "RHPOUT", + "Headphone Jack", "LHPOUT", + "MICIN", "Mic Bias", + "Mic Bias", "Mic Jack"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&sound_master>; + simple-audio-card,frame-master = <&sound_master>; + simple-audio-card,bitclock-inversion; + + sound_master: simple-audio-card,cpu { + sound-dai = <&ssi2>; + system-clock-frequency = <2822400>; + }; + + simple-audio-card,codec { + sound-dai = <&wm8731>; + }; + }; + sound-spdif { compatible = "fsl,imx-audio-spdif"; model = "imx-spdif"; @@ -99,6 +128,36 @@ }; }; +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; + + ssi2 { + fsl,audmux-port = <1>; + fsl,port-config = < + (IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_RCSEL(3 | 0x8) | + IMX_AUDMUX_V2_PTCR_TCLKDIR | + IMX_AUDMUX_V2_PTCR_TCSEL(3)) + IMX_AUDMUX_V2_PDCR_RXDSEL(3) + >; + }; + + audmux4 { + fsl,audmux-port = <3>; + fsl,port-config = < + (IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TFSEL(1) | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_RCSEL(1 | 0x8) | + IMX_AUDMUX_V2_PTCR_TCLKDIR | + IMX_AUDMUX_V2_PTCR_TCSEL(1)) + IMX_AUDMUX_V2_PDCR_RXDSEL(1) + >; + }; +}; + &cpu0 { /* * Although the imx6q fuse indicates that 1.2GHz operation is possible, @@ -160,9 +219,25 @@ reg = <0x50>; pagesize = <16>; }; + + wm8731: codec@1a { + #sound-dai-cells = <0>; + compatible = "wlf,wm8731"; + reg = <0x1a>; + }; }; &iomuxc { + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__AUD4_RXC 0x17059 + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x17059 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x17059 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x17059 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x17059 + >; + }; + pinctrl_ecspi1: ecspi1grp { fsl,pins = < MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 @@ -279,6 +354,14 @@ status = "okay"; }; +&ssi2 { + assigned-clocks = <&clks IMX6QDL_CLK_SSI2_SEL>, + <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <0>, <786432000>; + status = "okay"; +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart4>; diff --git a/arch/arm/boot/dts/imx6q-gw5903.dts b/arch/arm/boot/dts/imx6q-gw5903.dts new file mode 100644 index 000000000000..a182e4cb0e6e --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gw5903.dts @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Gateworks Corporation + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file 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. + * + * You should have received a copy of the GNU General Public + * License along with this file; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-gw5903.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 Dual/Quad GW5903"; + compatible = "gw,imx6q-gw5903", "gw,ventana", "fsl,imx6q"; +}; diff --git a/arch/arm/boot/dts/imx6q-gw5904.dts b/arch/arm/boot/dts/imx6q-gw5904.dts new file mode 100644 index 000000000000..ca1e2ae3341e --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gw5904.dts @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Gateworks Corporation + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file 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. + * + * You should have received a copy of the GNU General Public + * License along with this file; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-gw5904.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 Dual/Quad GW5904"; + compatible = "gw,imx6q-gw5904", "gw,ventana", "fsl,imx6q"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-icore-ofcap10.dts b/arch/arm/boot/dts/imx6q-icore-ofcap10.dts new file mode 100644 index 000000000000..49b60ca20e6d --- /dev/null +++ b/arch/arm/boot/dts/imx6q-icore-ofcap10.dts @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Amarula Solutions B.V. + * Copyright (C) 2016 Engicam S.r.l. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-icore.dtsi" + +/ { + model = "Engicam i.CoreM6 Quad/Dual OpenFrame Capacitive touch 10.1 Kit"; + compatible = "engicam,imx6-icore", "fsl,imx6q"; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <24>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <60000000>; + hactive = <1280>; + vactive = <800>; + hback-porch = <40>; + hfront-porch = <40>; + vback-porch = <10>; + vfront-porch = <3>; + hsync-len = <80>; + vsync-len = <10>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-icore-ofcap12.dts b/arch/arm/boot/dts/imx6q-icore-ofcap12.dts new file mode 100644 index 000000000000..9e230f56c5fb --- /dev/null +++ b/arch/arm/boot/dts/imx6q-icore-ofcap12.dts @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Amarula Solutions B.V. + * Copyright (C) 2016 Engicam S.r.l. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-icore.dtsi" + +/ { + model = "Engicam i.CoreM6 Quad/Dual OpenFrame Capacitive touch 12 Kit"; + compatible = "engicam,imx6-icore", "fsl,imx6q"; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <46800000>; + hactive = <1280>; + vactive = <480>; + hback-porch = <353>; + hfront-porch = <47>; + vback-porch = <39>; + vfront-porch = <4>; + hsync-len = <8>; + vsync-len = <2>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-icore.dts b/arch/arm/boot/dts/imx6q-icore.dts index 59eb7adc2472..5613dd9dc469 100644 --- a/arch/arm/boot/dts/imx6q-icore.dts +++ b/arch/arm/boot/dts/imx6q-icore.dts @@ -57,3 +57,37 @@ &can2 { status = "okay"; }; + +&i2c1 { + max11801: touchscreen@48 { + compatible = "maxim,max11801"; + reg = <0x48>; + interrupt-parent = <&gpio3>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <60000000>; + hactive = <800>; + vactive = <480>; + hback-porch = <30>; + hfront-porch = <30>; + vback-porch = <5>; + vfront-porch = <5>; + hsync-len = <64>; + vsync-len = <20>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-utilite-pro.dts b/arch/arm/boot/dts/imx6q-utilite-pro.dts index 69bdd82ce21f..d900ad6ec5f8 100644 --- a/arch/arm/boot/dts/imx6q-utilite-pro.dts +++ b/arch/arm/boot/dts/imx6q-utilite-pro.dts @@ -101,9 +101,11 @@ hdmi-connector { compatible = "hdmi-connector"; - + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hpd>; type = "a"; ddc-i2c-bus = <&i2c_dvi_ddc>; + hpd-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; port { hdmi_connector_in: endpoint { @@ -209,6 +211,12 @@ >; }; + pinctrl_hpd: hpdgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 diff --git a/arch/arm/boot/dts/imx6q-zii-rdu2.dts b/arch/arm/boot/dts/imx6q-zii-rdu2.dts new file mode 100644 index 000000000000..b2d346640fd7 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-zii-rdu2.dts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016-2017 Zodiac Inflight Innovations + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include <imx6q.dtsi> +#include <imx6qdl-zii-rdu2.dtsi> + +/ { + model = "ZII RDU2 Board"; + compatible = "zii,imx6q-zii-rdu2", "fsl,imx6q"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-gw5903.dtsi b/arch/arm/boot/dts/imx6qdl-gw5903.dtsi new file mode 100644 index 000000000000..444425153fc7 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-gw5903.dtsi @@ -0,0 +1,654 @@ +/* + * Copyright 2017 Gateworks Corporation + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file 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. + * + * You should have received a copy of the GNU General Public + * License along with this file; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/gpio/gpio.h> + +/ { + chosen { + stdout-path = &uart2; + }; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <100>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + led0: user1 { + label = "user1"; + gpios = <&gpio6 14 GPIO_ACTIVE_LOW>; /* MX6_LOCLED# */ + default-state = "off"; + }; + }; + + memory { + reg = <0x10000000 0x40000000>; + }; + + reg_5p0v: regulator-5p0v { + compatible = "regulator-fixed"; + regulator-name = "5P0V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_2p5v: regulator-2p5v { + compatible = "regulator-fixed"; + regulator-name = "2P5V"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + reg_usb_h1_vbus: regulator-usb-h1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 30 0>; + enable-active-high; + }; + + reg_usb_otg_vbus: regulator-usb-otg-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_12p0: regulator-12p0v { + compatible = "regulator-fixed"; + regulator-name = "12P0V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + sound { + compatible = "fsl,imx-audio-tlv320"; + model = "imx-tlv320"; + ssi-controller = <&ssi1>; + audio-codec = <&tlv320aic3105>; + /* routing of sink, source */ + audio-routing = + /* TLV320 LINE1L pin <-> Mic Jack connector */ + "LINE1L", "Mic Jack", + /* board Headphone Jack <-> HPOUT */ + "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "Mic Jack", "Mic Bias"; + mux-int-port = <1>; + mux-ext-port = <6>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&clks { + assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, + <&clks IMX6QDL_CLK_LDB_DI1_SEL>; + assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>, + <&clks IMX6QDL_CLK_PLL3_USB_OTG>; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pca9555: gpio@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + + eeprom1: eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom2: eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom3: eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom4: eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + dts1672: rtc@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + ltc3676: pmic@3c { + compatible = "lltc,ltc3676"; + reg = <0x3c>; + interrupt-parent = <&gpio1>; + interrupts = <8 IRQ_TYPE_EDGE_FALLING>; + + regulators { + /* VDD_1P8 (1+R1/R2 = 2.505): Aud/eMMC/microSD/Touch */ + reg_1p8v: sw1 { + regulator-name = "vdd1p8"; + regulator-min-microvolt = <1033310>; + regulator-max-microvolt = <2004000>; + lltc,fb-voltage-divider = <301000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_DDR (1+R1/R2 = 2.105) */ + reg_vdd_ddr: sw2 { + regulator-name = "vddddr"; + regulator-min-microvolt = <868310>; + regulator-max-microvolt = <1684000>; + lltc,fb-voltage-divider = <221000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_ARM (1+R1/R2 = 1.635) */ + reg_vdd_arm: sw3 { + regulator-name = "vddarm"; + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <1308000>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + linux,phandle = <®_vdd_arm>; + }; + + /* VDD_SOC (1+R1/R2 = 1.635) */ + reg_vdd_soc: sw4 { + regulator-name = "vddsoc"; + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <1308000>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + linux,phandle = <®_vdd_soc>; + }; + + /* VDD_1P0 (1+R1/R2 = 1.38): */ + reg_1p0v: ldo2 { + regulator-name = "vdd1p0"; + regulator-min-microvolt = <1002777>; + regulator-max-microvolt = <1002777>; + lltc,fb-voltage-divider = <100000 261000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_HIGH (1+R1/R2 = 4.17) */ + reg_3p0v: ldo4 { + regulator-name = "vdd3p0"; + regulator-min-microvolt = <3023250>; + regulator-max-microvolt = <3023250>; + lltc,fb-voltage-divider = <634000 200000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + tlv320aic3105: codec@18 { + compatible = "ti,tlv320aic3x"; + reg = <0x18>; + gpio-reset = <&gpio5 17 GPIO_ACTIVE_LOW>; + clocks = <&clks IMX6QDL_CLK_CKO>; + ai3x-micbias-vg = <2>; /* MICBIAS_2_5V */ + /* Regulators */ + DRVDD-supply = <®_3p3v>; + AVDD-supply = <®_3p3v>; + IOVDD-supply = <®_3p3v>; + DVDD-supply = <®_1p8v>; + }; + + accelerometer@1d { + compatible = "fsl,mma8451"; + reg = <0x1d>; + interrupt-parent = <&gpio7>; + interrupts = <11 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT2"; + }; + + /* headphone detect */ + ts3a227e@3b { + compatible = "ti,ts3a227e"; + reg = <0x3b>; + interrupt-parent = <&gpio5>; + interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + ti,micbias = <4>; /* 2.5V micbias */ + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: g101evn010 { + clock-frequency = <68930000>; + hactive = <1280>; + vactive = <800>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&ssi1 { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1_200mhz>; + vmmc-supply = <®_3p3v>; + non-removable; + bus-width = <4>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + cd-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_3p3v>; + max-frequency = <100000000>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + non-removable; + vmmc-supply = <®_3p3v>; + keep-power-in-suspend; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; +}; + +&iomuxc { + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x130b0 + MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x130b0 + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x130b0 + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x130b0 + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 /* MCK */ + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x4001b0b0 /* PHY_RST# */ + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x4001b0b0 /* PHY_EN */ + >; + }; + + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x1b0b0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x0001b0b0 /* GSC_IRQ# */ + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x0001b0b0 /* PMIC_IRQ# */ + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + /* I2C3 */ + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + + /* Headphone Detect */ + MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x0001b0b0 /* HPDET_IRQ# */ + MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16 0x0001b0b0 /* HPDET_MIC# */ + + /* Codec */ + MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x0001b0b0 /* CODEC_RST# */ + + /* Touch Controller */ + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x0001b0b0 /* TOUCH_IRQ# */ + MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x0001b0b0 /* TOUCH_RST */ + + /* Stow Sensor */ + MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x0001b0b0 /* ACCEL_IRQ2 */ + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x0001b0b0 /* ACCEL_IRQ1 */ + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_9__PWM1_OUT 0x1b0b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 0x1b0b1 /* TXEN */ + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x4001b0b0 /* PWR_EN */ + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 /* OC */ + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x4001b0b0 /* EMMY_EN */ + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x4001b0b0 /* EMMY_CFG1# */ + MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x4001b0b0 /* EMMY_CFG2# */ + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x0001b0b0 /* EMMY_BTWAKE# */ + MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x0001b0b0 /* EMMY_WFWAKE# */ + + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x100f9 + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x100f9 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170f9 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170f9 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170f9 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x17059 /* CD */ + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x17059 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2grp100mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x170b9 /* CD */ + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x170b9 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2grp200mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x170f9 /* CD */ + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x170f9 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3grp100mhz { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x100b9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp200mhz { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x100f9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6qdl-gw5904.dtsi b/arch/arm/boot/dts/imx6qdl-gw5904.dtsi new file mode 100644 index 000000000000..fd4b68be9fe9 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-gw5904.dtsi @@ -0,0 +1,641 @@ +/* + * Copyright 2017 Gateworks Corporation + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file 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. + * + * You should have received a copy of the GNU General Public + * License along with this file; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/gpio/gpio.h> + +/ { + /* these are used by bootloader for disabling nodes */ + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + usb0 = &usbh1; + usb1 = &usbotg; + }; + + chosen { + stdout-path = &uart2; + }; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm4 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + led0: user1 { + label = "user1"; + gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>; /* MX6_PANLEDG */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led1: user2 { + label = "user2"; + gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>; /* MX6_PANLEDR */ + default-state = "off"; + }; + + led2: user3 { + label = "user3"; + gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; /* MX6_LOCLED# */ + default-state = "off"; + }; + }; + + memory { + reg = <0x10000000 0x40000000>; + }; + + pps { + compatible = "pps-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pps>; + gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>; + }; + + reg_1p0v: regulator-1p0v { + compatible = "regulator-fixed"; + regulator-name = "1P0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_h1_vbus: regulator-usb-h1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator-usb-otg-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&clks { + assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, + <&clks IMX6QDL_CLK_LDB_DI1_SEL>; + assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>, + <&clks IMX6QDL_CLK_PLL3_USB_OTG>; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii-id"; + status = "okay"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch@0 { + compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan4"; + }; + + port@1 { + reg = <1>; + label = "lan3"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan1"; + }; + + port@5 { + reg = <5>; + label = "cpu"; + ethernet = <&fec>; + }; + }; + }; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pca9555: gpio@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + + eeprom1: eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom2: eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom3: eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom4: eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + dts1672: rtc@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + ltc3676: pmic@3c { + compatible = "lltc,ltc3676"; + reg = <0x3c>; + interrupt-parent = <&gpio1>; + interrupts = <8 IRQ_TYPE_EDGE_FALLING>; + + regulators { + /* VDD_SOC (1+R1/R2 = 1.635) */ + reg_vdd_soc: sw1 { + regulator-name = "vddsoc"; + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <1308000>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_1P8 (1+R1/R2 = 2.505): GbE switch */ + reg_1p8v: sw2 { + regulator-name = "vdd1p8"; + regulator-min-microvolt = <1033310>; + regulator-max-microvolt = <2004000>; + lltc,fb-voltage-divider = <301000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_ARM (1+R1/R2 = 1.635) */ + reg_vdd_arm: sw3 { + regulator-name = "vddarm"; + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <1308000>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_DDR (1+R1/R2 = 2.105) */ + reg_vdd_ddr: sw4 { + regulator-name = "vddddr"; + regulator-min-microvolt = <868310>; + regulator-max-microvolt = <1684000>; + lltc,fb-voltage-divider = <221000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_2P5 (1+R1/R2 = 3.435): PCIe/ENET-PHY */ + reg_2p5v: ldo2 { + regulator-name = "vdd2p5"; + regulator-min-microvolt = <2490375>; + regulator-max-microvolt = <2490375>; + lltc,fb-voltage-divider = <487000 200000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_HIGH (1+R1/R2 = 4.17) */ + reg_3p0v: ldo4 { + regulator-name = "vdd3p0"; + regulator-min-microvolt = <3023250>; + regulator-max-microvolt = <3023250>; + lltc,fb-voltage-divider = <634000 200000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + egalax_ts: touchscreen@4 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + interrupt-parent = <&gpio1>; + interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + wakeup-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie>; + reset-gpio = <&gpio1 0 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&pwm2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */ + status = "disabled"; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */ + status = "disabled"; +}; + +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + uart-has-rtscts; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + uart-has-rtscts; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + non-removable; + vmmc-supply = <®_3p3v>; + keep-power-in-suspend; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; +}; + +&iomuxc { + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x4001b0b0 /* PHY_RST# */ + >; + }; + + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x1b0b0 + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0 + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x1b0b0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_pcie: pciegrp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 /* PCIE RST */ + >; + }; + + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x1b0b0 /* PMIC_IRQ# */ + >; + }; + + pinctrl_pps: ppsgrp { + fsl,pins = < + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x1b0b1 + >; + }; + + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1 + >; + }; + + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; + + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 + MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 /* PWR_EN */ + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 /* OC */ + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3grp100mhz { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x100b9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp200mhz { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x100f9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6qdl-icore.dtsi b/arch/arm/boot/dts/imx6qdl-icore.dtsi index 55bebfc9ad94..56d0c5d21cd0 100644 --- a/arch/arm/boot/dts/imx6qdl-icore.dtsi +++ b/arch/arm/boot/dts/imx6qdl-icore.dtsi @@ -48,6 +48,13 @@ reg = <0x10000000 0x80000000>; }; + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm3 0 100000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + }; + reg_3p3v: regulator-3p3v { compatible = "regulator-fixed"; regulator-name = "3P3V"; @@ -136,6 +143,12 @@ status = "okay"; }; +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; + status = "okay"; +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart4>; @@ -246,6 +259,12 @@ >; }; + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 + >; + }; + pinctrl_usbotg: usbotggrp { fsl,pins = < MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index 63bf95ed8c88..58055ceec6dc 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -548,6 +548,18 @@ status = "okay"; }; +®_arm { + vin-supply = <&sw1a_reg>; +}; + +®_pu { + vin-supply = <&sw1c_reg>; +}; + +®_soc { + vin-supply = <&sw1c_reg>; +}; + &snvs_poweroff { status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi new file mode 100644 index 000000000000..5d94b5ee6aa0 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi @@ -0,0 +1,932 @@ +/* + * Copyright (C) 2016-2017 Zodiac Inflight Innovations + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/sound/fsl-imx-audmux.h> + +/ { + chosen { + stdout-path = &uart1; + }; + + aliases { + mdio-gpio0 = &mdio1; + }; + + mdio1: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mdio1>; + gpios = <&gpio6 5 GPIO_ACTIVE_HIGH + &gpio6 4 GPIO_ACTIVE_HIGH>; + }; + + reg_28p0v: regulator-28p0v { + compatible = "regulator-fixed"; + regulator-name = "28V_IN"; + regulator-min-microvolt = <28000000>; + regulator-max-microvolt = <28000000>; + regulator-always-on; + }; + + reg_12p0v: regulator-12p0v { + compatible = "regulator-fixed"; + vin-supply = <®_28p0v>; + regulator-name = "12V_MAIN"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + }; + + reg_5p0v_main: regulator-5p0v-main { + compatible = "regulator-fixed"; + vin-supply = <®_12p0v>; + regulator-name = "5V_MAIN"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_5p0v_user_usb: regulator-5p0v-user-usb { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_user_usb>; + vin-supply = <®_5p0v_main>; + regulator-name = "5V_USER_USB"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 GPIO_ACTIVE_LOW>; + startup-delay-us = <1000>; + }; + + reg_3p3v_pmic: regulator-3p3v-pmic { + compatible = "regulator-fixed"; + vin-supply = <®_12p0v>; + regulator-name = "PMIC_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + vin-supply = <®_3p3v_pmic>; + regulator-name = "GEN_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_3p3v_sd: regulator-3p3v-sd { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_3p3v_sd>; + vin-supply = <®_3p3v>; + regulator-name = "3V3_SD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio7 8 GPIO_ACTIVE_HIGH>; + startup-delay-us = <1000>; + enable-active-high; + regulator-always-on; + }; + + reg_3p3v_display: regulator-3p3v-display { + compatible = "regulator-fixed"; + vin-supply = <®_12p0v>; + regulator-name = "3V3_DISPLAY"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_3p3v_ssd: regulator-3p3v-ssd { + compatible = "regulator-fixed"; + vin-supply = <®_12p0v>; + regulator-name = "3V3_SSD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + sound1 { + compatible = "simple-audio-card"; + simple-audio-card,name = "Front"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&sound1_codec>; + simple-audio-card,frame-master = <&sound1_codec>; + simple-audio-card,widgets = + "Headphone", "Headphone Jack"; + simple-audio-card,routing = + "Headphone Jack", "HPLEFT", + "Headphone Jack", "HPRIGHT", + "LEFTIN", "HPL", + "RIGHTIN", "HPR"; + simple-audio-card,aux-devs = <&hpa1>; + + sound1_cpu: simple-audio-card,cpu { + sound-dai = <&ssi2>; + }; + + sound1_codec: simple-audio-card,codec { + sound-dai = <&codec1>; + clocks = <&cs2000>; + }; + }; + + sound2 { + compatible = "simple-audio-card"; + simple-audio-card,name = "Back"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&sound2_codec>; + simple-audio-card,frame-master = <&sound2_codec>; + simple-audio-card,widgets = + "Headphone", "Headphone Jack"; + simple-audio-card,routing = + "Headphone Jack", "HPLEFT", + "Headphone Jack", "HPRIGHT", + "LEFTIN", "HPL", + "RIGHTIN", "HPR"; + simple-audio-card,aux-devs = <&hpa2>; + + sound2_cpu: simple-audio-card,cpu { + sound-dai = <&ssi1>; + }; + + sound2_codec: simple-audio-card,codec { + sound-dai = <&codec2>; + clocks = <&cs2000>; + }; + }; + + panel { + power-supply = <®_3p3v_display>; + status = "disabled"; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + }; + + disp0: disp0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx-parallel-display"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_disp0>; + status = "disabled"; + + port@0 { + reg = <0>; + + disp0_in_0: endpoint { + remote-endpoint = <&ipu1_di0_disp0>; + }; + }; + + port@1 { + reg = <1>; + + disp0_out: endpoint { + remote-endpoint = <&tc358767_in>; + }; + }; + }; + + cs2000_ref: cs2000-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24576000>; + }; + + cs2000_in_dummy: cs2000-in-dummy { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + edp_refclk: edp-refclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <19200000>; + }; +}; + +®_arm { + vin-supply = <&sw1a_reg>; +}; + +®_pu { + vin-supply = <&sw1c_reg>; +}; + +®_soc { + vin-supply = <&sw1c_reg>; +}; + +&ldb { + lvds-channel@0 { + port@4 { + reg = <4>; + + lvds0_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + uart-has-rtscts; + linux,rs485-enabled-at-boot-time; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + cs-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>; + status = "okay"; + + flash@0 { + compatible = "st,m25p128", "jedec,spi-nor"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + clock-frequency = <100000>; + status = "okay"; + + codec2: codec@18 { + compatible = "ti,tlv320dac3100"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_codec2>; + reg = <0x18>; + #sound-dai-cells = <0>; + HPVDD-supply = <®_3p3v>; + SPRVDD-supply = <®_3p3v>; + SPLVDD-supply = <®_3p3v>; + AVDD-supply = <®_3p3v>; + IOVDD-supply = <®_3p3v>; + DVDD-supply = <&vgen4_reg>; + gpio-reset = <&gpio1 2 GPIO_ACTIVE_HIGH>; + }; + + accel@1c { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_accel>; + compatible = "fsl,mma8451"; + reg = <0x1c>; + interrupt-parent = <&gpio1>; + interrupt-names = "int1", "int2"; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>, <20 IRQ_TYPE_LEVEL_LOW>; + }; + + hpa2: amp@60 { + compatible = "ti,tpa6130a2"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpa2>; + reg = <0x60>; + power-gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>; + Vdd-supply = <®_5p0v_main>; + }; + + edp-bridge@68 { + compatible = "toshiba,tc358767"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tc358767>; + reg = <0x68>; + shutdown-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + clock-names = "ref"; + clocks = <&edp_refclk>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + tc358767_in: endpoint { + remote-endpoint = <&disp0_out>; + }; + }; + }; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + clock-frequency = <100000>; + status = "okay"; + + pmic@08 { + compatible = "fsl,pfuze100"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pfuze100_irq>; + reg = <0x08>; + interrupt-parent = <&gpio7>; + interrupts = <13 IRQ_TYPE_LEVEL_LOW>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + }; + }; + + temp-sense@48 { + compatible = "national,lm75"; + reg = <0x48>; + }; + + cs2000: clkgen@4e { + compatible = "cirrus,cs2000-cp"; + reg = <0x4e>; + #clock-cells = <0>; + clock-names = "clk_in", "ref_clk"; + clocks = <&cs2000_in_dummy>, <&cs2000_ref>; + assigned-clocks = <&cs2000>; + assigned-clock-rates = <24000000>; + }; + + eeprom@54 { + compatible = "at,24c128"; + reg = <0x54>; + }; + + rtc@68 { + compatible = "dallas,ds1341"; + reg = <0x68>; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + clock-frequency = <400000>; + status = "okay"; + + codec1: codec@18 { + compatible = "ti,tlv320dac3100"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_codec1>; + reg = <0x18>; + #sound-dai-cells = <0>; + HPVDD-supply = <®_3p3v>; + SPRVDD-supply = <®_3p3v>; + SPLVDD-supply = <®_3p3v>; + AVDD-supply = <®_3p3v>; + IOVDD-supply = <®_3p3v>; + DVDD-supply = <&vgen4_reg>; + gpio-reset = <&gpio1 0 GPIO_ACTIVE_HIGH>; + }; + + touchscreen@20 { + compatible = "syna,rmi4-i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ts>; + reg = <0x20>; + interrupt-parent = <&gpio1>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + vdd-supply = <®_5p0v_main>; + vio-supply = <®_3p3v>; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep-mode = <1>; + }; + + rmi4-f11@11 { + reg = <0x11>; + touchscreen-inverted-y; + touchscreen-swapped-x-y; + syna,sensor-type = <1>; + }; + + rmi4-f12@12 { + reg = <0x12>; + touchscreen-inverted-y; + touchscreen-swapped-x-y; + syna,sensor-type = <1>; + }; + }; + + hpa1: amp@60 { + compatible = "ti,tpa6130a2"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpa1>; + reg = <0x60>; + power-gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>; + Vdd-supply = <®_5p0v_main>; + }; +}; + +&ipu1_di0_disp0 { + remote-endpoint = <&disp0_in_0>; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie>; + reset-gpio = <&gpio7 12 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + bus-width = <4>; + cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>; + vmmc-supply = <®_3p3v_sd>; + vqmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + bus-width = <4>; + cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; + vmmc-supply = <®_3p3v_sd>; + vqmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&usdhc4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4>; + bus-width = <8>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + non-removable; + status = "okay"; +}; + +&sata { + target-supply = <®_3p3v_ssd>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rmii"; + phy-reset-gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; + phy-reset-duration = <100>; + phy-supply = <®_3p3v>; + status = "okay"; + + fixed-link { + speed = <100>; + full-duplex; + }; +}; + +&usbh1 { + vbus-supply = <®_5p0v_main>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_5p0v_user_usb>; + disable-over-current; + dr_mode = "host"; + status = "okay"; +}; + +&ssi1 { + status = "okay"; +}; + +&ssi2 { + status = "okay"; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; + + ssi1 { + fsl,audmux-port = <0>; + fsl,port-config = < + (IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSEL(2) | + IMX_AUDMUX_V2_PTCR_TCSEL(2) | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR) + IMX_AUDMUX_V2_PDCR_RXDSEL(2) + >; + }; + + aud3 { + fsl,audmux-port = <2>; + fsl,port-config = < + IMX_AUDMUX_V2_PTCR_SYN + IMX_AUDMUX_V2_PDCR_RXDSEL(0) + >; + }; + + ssi2 { + fsl,audmux-port = <1>; + fsl,port-config = < + (IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSEL(4) | + IMX_AUDMUX_V2_PTCR_TCSEL(4) | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR) + IMX_AUDMUX_V2_PDCR_RXDSEL(4) + >; + }; + + aud5 { + fsl,audmux-port = <4>; + fsl,port-config = < + IMX_AUDMUX_V2_PTCR_SYN + IMX_AUDMUX_V2_PDCR_RXDSEL(1) + >; + }; +}; + +&iomuxc { + pinctrl_accel: accelgrp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0x4001b000 + MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x4001b000 + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 + MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x130b0 + MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x130b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; + + pinctrl_codec1: dac1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x40000038 + >; + }; + + pinctrl_codec2: dac2grp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x40000038 + >; + }; + + pinctrl_disp0: disp0grp { + fsl,pins = < + MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x100f9 + MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x100f9 + MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x100f9 + MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x100f9 + MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x100f9 + MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x100f9 + MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x100f9 + MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x100f9 + MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x100f9 + MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x100f9 + MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x100f9 + MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x100f9 + MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x100f9 + MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x100f9 + MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x100f9 + MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x100f9 + MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x100f9 + MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x100f9 + MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x100f9 + MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x100f9 + MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x100f9 + MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x100f9 + MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x100f9 + MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x100f9 + MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x100f9 + MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x100f9 + MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x100f9 + MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x100f9 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b1 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x000b1 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b1 + MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN 0x100f5 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x100f5 + MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x100c0 + MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1 0x100c0 + MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0 0x100f5 + MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1 0x100f5 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x40010040 + MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER 0x100b0 + MX6QDL_PAD_ENET_REF_CLK__GPIO1_IO23 0x1b0b0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_mdio1: bitbangmdiogrp { + fsl,pins = < + /* Bitbang MDIO for DEB Switch */ + MX6QDL_PAD_CSI0_DAT19__GPIO6_IO05 0x4001b030 + MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40018830 + >; + }; + + pinctrl_pcie: pciegrp { + fsl,pins = < + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x10038 + >; + }; + + pinctrl_pfuze100_irq: pfuze100grp { + fsl,pins = < + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x40010000 + >; + }; + + pinctrl_reg_3p3v_sd: mmcsupply1grp { + fsl,pins = < + MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x858 + >; + }; + + pinctrl_reg_user_usb: usbotggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x40000038 + >; + }; + + pinctrl_rmii_phy_irq: phygrp { + fsl,pins = < + MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x40010000 + >; + }; + + pinctrl_tc358767: tc358767grp { + fsl,pins = < + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x10 + >; + }; + + pinctrl_tpa1: tpa6130-1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x40000038 + >; + }; + + pinctrl_tpa2: tpa6130-2grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x40000038 + >; + }; + + pinctrl_ts: tsgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x1b0b0 + MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x1b0b0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x10059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10069 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x40010040 + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x40010040 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x10059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10069 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x40010040 + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x40010040 + + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + MX6QDL_PAD_NANDF_ALE__SD4_RESET 0x1b0b1 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 6d7bf6496117..e426faa9c243 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -197,7 +197,7 @@ arm,shared-override; }; - pcie: pcie@0x01000000 { + pcie: pcie@1ffc000 { compatible = "fsl,imx6q-pcie", "snps,dw-pcie"; reg = <0x01ffc000 0x04000>, <0x01f00000 0x80000>; @@ -205,6 +205,7 @@ #address-cells = <3>; #size-cells = <2>; device_type = "pci"; + bus-range = <0x00 0xff>; ranges = <0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */ 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */ num-lanes = <1>; diff --git a/arch/arm/boot/dts/imx6qp-nitrogen6_som2.dts b/arch/arm/boot/dts/imx6qp-nitrogen6_som2.dts new file mode 100644 index 000000000000..011726c836cd --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-nitrogen6_som2.dts @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Boundary Devices, Inc. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "imx6qp.dtsi" +#include "imx6qdl-nitrogen6_som2.dtsi" + +/ { + model = "Boundary Devices i.MX6 Quad Plus Nitrogen6_SOM2 Board"; + compatible = "boundary,imx6qp-nitrogen6_som2", "fsl,imx6qp"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qp-sabresd.dts b/arch/arm/boot/dts/imx6qp-sabresd.dts index b23458062f5e..a8a5004dd9c8 100644 --- a/arch/arm/boot/dts/imx6qp-sabresd.dts +++ b/arch/arm/boot/dts/imx6qp-sabresd.dts @@ -50,8 +50,8 @@ compatible = "fsl,imx6qp-sabresd", "fsl,imx6qp"; }; -&cpu0 { - arm-supply = <&sw2_reg>; +®_arm { + vin-supply = <&sw2_reg>; }; &iomuxc { diff --git a/arch/arm/boot/dts/imx6qp-zii-rdu2.dts b/arch/arm/boot/dts/imx6qp-zii-rdu2.dts new file mode 100644 index 000000000000..882b3bd97e07 --- /dev/null +++ b/arch/arm/boot/dts/imx6qp-zii-rdu2.dts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016-2017 Zodiac Inflight Innovations + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include <imx6qp.dtsi> +#include <imx6qdl-zii-rdu2.dtsi> + +/ { + model = "ZII RDU2+ Board"; + compatible = "zii,imx6qp-zii-rdu2", "fsl,imx6qp"; +}; diff --git a/arch/arm/boot/dts/imx6qp.dtsi b/arch/arm/boot/dts/imx6qp.dtsi index 24d071f5d9cd..59453f2ac4ba 100644 --- a/arch/arm/boot/dts/imx6qp.dtsi +++ b/arch/arm/boot/dts/imx6qp.dtsi @@ -56,40 +56,59 @@ clocks = <&clks IMX6QDL_CLK_OCRAM>; }; - ipu1: ipu@02400000 { - compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu"; - clocks = <&clks IMX6QDL_CLK_IPU1>, - <&clks IMX6QDL_CLK_IPU1_DI0>, <&clks IMX6QDL_CLK_IPU1_DI1>, - <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, - <&clks IMX6QDL_CLK_LDB_DI0_PODF>, <&clks IMX6QDL_CLK_LDB_DI1_PODF>, - <&clks IMX6QDL_CLK_PRG0_APB>; - clock-names = "bus", - "di0", "di1", - "di0_sel", "di1_sel", - "ldb_di0", "ldb_di1", "prg"; - }; + aips-bus@02100000 { + pre1: pre@21c8000 { + compatible = "fsl,imx6qp-pre"; + reg = <0x021c8000 0x1000>; + interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>; + clocks = <&clks IMX6QDL_CLK_PRE0>; + clock-names = "axi"; + fsl,iram = <&ocram2>; + }; - ipu2: ipu@02800000 { - compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu"; - clocks = <&clks IMX6QDL_CLK_IPU2>, - <&clks IMX6QDL_CLK_IPU2_DI0>, <&clks IMX6QDL_CLK_IPU2_DI1>, - <&clks IMX6QDL_CLK_IPU2_DI0_SEL>, <&clks IMX6QDL_CLK_IPU2_DI1_SEL>, - <&clks IMX6QDL_CLK_LDB_DI0_PODF>, <&clks IMX6QDL_CLK_LDB_DI1_PODF>, - <&clks IMX6QDL_CLK_PRG1_APB>; - clock-names = "bus", - "di0", "di1", - "di0_sel", "di1_sel", - "ldb_di0", "ldb_di1", "prg"; - }; + pre2: pre@21c9000 { + compatible = "fsl,imx6qp-pre"; + reg = <0x021c9000 0x1000>; + interrupts = <GIC_SPI 97 IRQ_TYPE_EDGE_RISING>; + clocks = <&clks IMX6QDL_CLK_PRE1>; + clock-names = "axi"; + fsl,iram = <&ocram2>; + }; - pcie: pcie@0x01000000 { - compatible = "fsl,imx6qp-pcie", "snps,dw-pcie"; - }; + pre3: pre@21ca000 { + compatible = "fsl,imx6qp-pre"; + reg = <0x021ca000 0x1000>; + interrupts = <GIC_SPI 98 IRQ_TYPE_EDGE_RISING>; + clocks = <&clks IMX6QDL_CLK_PRE2>; + clock-names = "axi"; + fsl,iram = <&ocram3>; + }; - aips-bus@02100000 { - mmdc0: mmdc@021b0000 { /* MMDC0 */ - compatible = "fsl,imx6qp-mmdc", "fsl,imx6q-mmdc"; - reg = <0x021b0000 0x4000>; + pre4: pre@21cb000 { + compatible = "fsl,imx6qp-pre"; + reg = <0x021cb000 0x1000>; + interrupts = <GIC_SPI 99 IRQ_TYPE_EDGE_RISING>; + clocks = <&clks IMX6QDL_CLK_PRE3>; + clock-names = "axi"; + fsl,iram = <&ocram3>; + }; + + prg1: prg@21cc000 { + compatible = "fsl,imx6qp-prg"; + reg = <0x021cc000 0x1000>; + clocks = <&clks IMX6QDL_CLK_PRG0_APB>, + <&clks IMX6QDL_CLK_PRG0_AXI>; + clock-names = "ipg", "axi"; + fsl,pres = <&pre1>, <&pre2>, <&pre3>; + }; + + prg2: prg@21cd000 { + compatible = "fsl,imx6qp-prg"; + reg = <0x021cd000 0x1000>; + clocks = <&clks IMX6QDL_CLK_PRG1_APB>, + <&clks IMX6QDL_CLK_PRG1_AXI>; + clock-names = "ipg", "axi"; + fsl,pres = <&pre4>, <&pre2>, <&pre3>; }; }; }; @@ -101,6 +120,16 @@ <0 119 IRQ_TYPE_LEVEL_HIGH>; }; +&ipu1 { + compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu"; + fsl,prg = <&prg1>; +}; + +&ipu2 { + compatible = "fsl,imx6qp-ipu", "fsl,imx6q-ipu"; + fsl,prg = <&prg2>; +}; + &ldb { clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_SEL>, <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>, @@ -110,3 +139,11 @@ "di0_sel", "di1_sel", "di2_sel", "di3_sel", "di0", "di1"; }; + +&mmdc0 { + compatible = "fsl,imx6qp-mmdc", "fsl,imx6q-mmdc"; +}; + +&pcie { + compatible = "fsl,imx6qp-pcie", "snps,dw-pcie"; +}; diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index dd4ec85ecbaa..3f1416be4c36 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -297,7 +297,8 @@ }; uart1: serial@02020000 { - compatible = "fsl,imx6sx-uart", "fsl,imx21-uart"; + compatible = "fsl,imx6sx-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02020000 0x4000>; interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_UART_IPG>, @@ -1053,7 +1054,8 @@ }; uart2: serial@021e8000 { - compatible = "fsl,imx6sx-uart", "fsl,imx21-uart"; + compatible = "fsl,imx6sx-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021e8000 0x4000>; interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_UART_IPG>, @@ -1065,7 +1067,8 @@ }; uart3: serial@021ec000 { - compatible = "fsl,imx6sx-uart", "fsl,imx21-uart"; + compatible = "fsl,imx6sx-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021ec000 0x4000>; interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_UART_IPG>, @@ -1077,7 +1080,8 @@ }; uart4: serial@021f0000 { - compatible = "fsl,imx6sx-uart", "fsl,imx21-uart"; + compatible = "fsl,imx6sx-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f0000 0x4000>; interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_UART_IPG>, @@ -1089,7 +1093,8 @@ }; uart5: serial@021f4000 { - compatible = "fsl,imx6sx-uart", "fsl,imx21-uart"; + compatible = "fsl,imx6sx-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f4000 0x4000>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_UART_IPG>, @@ -1229,7 +1234,8 @@ }; uart6: serial@022a0000 { - compatible = "fsl,imx6sx-uart", "fsl,imx21-uart"; + compatible = "fsl,imx6sx-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x022a0000 0x4000>; interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_UART_IPG>, @@ -1281,7 +1287,7 @@ }; }; - pcie: pcie@0x08000000 { + pcie: pcie@8ffc000 { compatible = "fsl,imx6sx-pcie", "snps,dw-pcie"; reg = <0x08ffc000 0x4000>; /* DBI */ #address-cells = <3>; @@ -1293,6 +1299,7 @@ 0x81000000 0 0 0x08f80000 0 0x00010000 /* non-prefetchable memory */ 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; + bus-range = <0x00 0xff>; num-lanes = <1>; interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>, diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dts b/arch/arm/boot/dts/imx6ul-14x14-evk.dts index 00f98e5bfcaf..f18e1f1d0ce2 100644 --- a/arch/arm/boot/dts/imx6ul-14x14-evk.dts +++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dts @@ -85,11 +85,6 @@ assigned-clock-rates = <786432000>; }; -&cpu0 { - arm-supply = <®_arm>; - soc-supply = <®_soc>; -}; - &i2c2 { clock_frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6ul-geam.dtsi b/arch/arm/boot/dts/imx6ul-geam.dtsi index 940aef67313b..eb94d956808b 100644 --- a/arch/arm/boot/dts/imx6ul-geam.dtsi +++ b/arch/arm/boot/dts/imx6ul-geam.dtsi @@ -49,6 +49,23 @@ reg = <0x80000000 0x08000000>; }; + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm8 0 100000>; + brightness-levels = < 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100>; + default-brightness-level = <100>; + }; + chosen { stdout-path = &uart1; }; @@ -143,12 +160,24 @@ display = <&display0>; }; +&pwm8 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm8>; + status = "okay"; +}; + &tsc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tsc>; xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; }; +&sai2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2>; + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; @@ -290,6 +319,12 @@ >; }; + pinctrl_pwm8: pwm8grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_ER__PWM8_OUT 0x110b0 + >; + }; + pinctrl_tsc: tscgrp { fsl,pin = < MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 @@ -299,6 +334,16 @@ >; }; + pinctrl_sai2: sai2grp { + fsl,pins = < + MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA 0x130b0 + MX6UL_PAD_JTAG_TMS__CCM_CLKO1 0x4001b031 + MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK 0x17088 + MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC 0x17088 + MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x120b0 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1 diff --git a/arch/arm/boot/dts/imx6ul-isiot-common.dtsi b/arch/arm/boot/dts/imx6ul-isiot-common.dtsi new file mode 100644 index 000000000000..2beaab6e272e --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-isiot-common.dtsi @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016 Amarula Solutions B.V. + * Copyright (C) 2016 Engicam S.r.l. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +&i2c1 { + stmpe811: gpio-expander@44 { + compatible = "st,stmpe811"; + reg = <0x44>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_stmpe>; + interrupt-parent = <&gpio1>; + interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + + stmpe: touchscreen { + compatible = "st,stmpe-ts"; + st,sample-time = <4>; + st,mod-12b = <1>; + st,ref-sel = <0>; + st,adc-freq = <1>; + st,ave-ctrl = <1>; + st,touch-det-delay = <2>; + st,settling = <2>; + st,fraction-z = <7>; + st,i-drive = <1>; + }; + }; +}; + +&lcdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcdif_dat + &pinctrl_lcdif_ctrl>; + display = <&display0>; + status = "okay"; + + display0: display { + bits-per-pixel = <16>; + bus-width = <18>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <28000000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <30>; + hback-porch = <30>; + hsync-len = <64>; + vback-porch = <5>; + vfront-porch = <5>; + vsync-len = <20>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; + +&iomuxc { + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79 + MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79 + MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79 + MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79 + >; + }; + + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79 + MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79 + MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79 + MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79 + MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79 + MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79 + MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79 + MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79 + MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79 + MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79 + MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79 + MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79 + MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79 + MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79 + MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79 + MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79 + MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79 + MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79 + >; + }; + + pinctrl_stmpe: stmpegrp { + fsl,pins = < + MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x1b0b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6ul-isiot-emmc.dts b/arch/arm/boot/dts/imx6ul-isiot-emmc.dts index f5b422898e61..73a1d0f0b9d5 100644 --- a/arch/arm/boot/dts/imx6ul-isiot-emmc.dts +++ b/arch/arm/boot/dts/imx6ul-isiot-emmc.dts @@ -43,6 +43,7 @@ /dts-v1/; #include "imx6ul-isiot.dtsi" +#include "imx6ul-isiot-common.dtsi" / { model = "Engicam Is.IoT MX6UL eMMC Starter kit"; diff --git a/arch/arm/boot/dts/imx6ul-isiot-nand.dts b/arch/arm/boot/dts/imx6ul-isiot-nand.dts index de15e1c75dd1..da29a86eb6a8 100644 --- a/arch/arm/boot/dts/imx6ul-isiot-nand.dts +++ b/arch/arm/boot/dts/imx6ul-isiot-nand.dts @@ -43,6 +43,7 @@ /dts-v1/; #include "imx6ul-isiot.dtsi" +#include "imx6ul-isiot-common.dtsi" / { model = "Engicam Is.IoT MX6UL NAND Starter kit"; diff --git a/arch/arm/boot/dts/imx6ul-isiot.dtsi b/arch/arm/boot/dts/imx6ul-isiot.dtsi index 0b43699af3e3..ea30380ad7a4 100644 --- a/arch/arm/boot/dts/imx6ul-isiot.dtsi +++ b/arch/arm/boot/dts/imx6ul-isiot.dtsi @@ -52,6 +52,49 @@ chosen { stdout-path = &uart1; }; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm8 0 100000>; + brightness-levels = < 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100>; + default-brightness-level = <100>; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; +}; + +&i2c2 { + clock_frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; +}; + +&pwm8 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm8>; + status = "okay"; +}; + +&sai2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2>; + status = "okay"; }; &uart1 { @@ -72,6 +115,36 @@ }; &iomuxc { + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0 + MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO00__I2C2_SCL 0x4001b8b0 + MX6UL_PAD_GPIO1_IO01__I2C2_SDA 0x4001b8b0 + >; + }; + + pinctrl_pwm8: pwm8grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_ER__PWM8_OUT 0x110b0 + >; + }; + + pinctrl_sai2: sai2grp { + fsl,pins = < + MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA 0x130b0 + MX6UL_PAD_JTAG_TMS__CCM_CLKO1 0x4001b031 + MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK 0x17088 + MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC 0x17088 + MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x120b0 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1 diff --git a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi index 373ee19196a6..18bebd6d8d47 100644 --- a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi +++ b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi @@ -44,11 +44,39 @@ chosen { stdout-path = "serial0:115200n8"; }; + + panel: panel { + compatible = "edt,et057090dhu"; + backlight = <&bl>; + power-supply = <®_3v3>; + + port { + panel_in: endpoint { + remote-endpoint = <&lcdif_out>; + }; + }; + }; + + reg_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_5v0: regulator-5v0 { + compatible = "regulator-fixed"; + regulator-name = "5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; }; &bl { brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; + power-supply = <®_3v3>; + status = "okay"; }; @@ -75,32 +103,11 @@ }; &lcdif { - display = <&display0>; status = "okay"; - display0: lcd-display { - bits-per-pixel = <16>; - bus-width = <18>; - - display-timings { - native-mode = <&timing_vga>; - - /* Standard VGA timing */ - timing_vga: 640x480 { - clock-frequency = <25175000>; - hactive = <640>; - vactive = <480>; - hback-porch = <40>; - hfront-porch = <24>; - vback-porch = <32>; - vfront-porch = <11>; - hsync-len = <96>; - vsync-len = <2>; - de-active = <1>; - hsync-active = <0>; - vsync-active = <0>; - pixelclk-active = <0>; - }; + port { + lcdif_out: endpoint { + remote-endpoint = <&panel_in>; }; }; }; diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi index a171545478be..2d87489f9105 100644 --- a/arch/arm/boot/dts/imx7-colibri.dtsi +++ b/arch/arm/boot/dts/imx7-colibri.dtsi @@ -60,13 +60,6 @@ regulator-max-microvolt = <3300000>; }; - reg_vref_1v8: regulator-vref-1v8 { - compatible = "regulator-fixed"; - regulator-name = "vref-1v8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - sound { compatible = "simple-audio-card"; simple-audio-card,name = "imx7-sgtl5000"; @@ -85,11 +78,11 @@ }; &adc1 { - vref-supply = <®_vref_1v8>; + vref-supply = <®_DCDC3>; }; &adc2 { - vref-supply = <®_vref_1v8>; + vref-supply = <®_DCDC3>; }; &cpu0 { @@ -151,29 +144,29 @@ regulators { reg_DCDC1: DCDC1 { /* V1.0_SOC */ - regulator-min-microvolt = <975000>; - regulator-max-microvolt = <1125000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; regulator-boot-on; regulator-always-on; }; reg_DCDC2: DCDC2 { /* V1.1_ARM */ - regulator-min-microvolt = <975000>; - regulator-max-microvolt = <1125000>; + regulator-min-microvolt = <975000>; + regulator-max-microvolt = <1100000>; regulator-boot-on; regulator-always-on; }; reg_DCDC3: DCDC3 { /* V1.8 */ - regulator-min-microvolt = <1775000>; - regulator-max-microvolt = <1825000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; regulator-boot-on; regulator-always-on; }; reg_DCDC4: DCDC4 { /* V1.35_DRAM */ - regulator-min-microvolt = <1325000>; - regulator-max-microvolt = <1375000>; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; regulator-boot-on; regulator-always-on; }; @@ -181,33 +174,33 @@ reg_LDO1: LDO1 { /* PWR_EN_+V3.3_ETH */ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; - regulator-always-on; + regulator-boot-on; }; reg_LDO2: LDO2 { /* +V1.8_SD */ - regulator-min-microvolt = <1775000>; - regulator-max-microvolt = <3325000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; regulator-boot-on; regulator-always-on; }; reg_LDO3: LDO3 { /* PWR_EN_+V3.3_LPSR */ - regulator-min-microvolt = <3275000>; - regulator-max-microvolt = <3325000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-boot-on; regulator-always-on; }; reg_LDO4: LDO4 { /* V1.8_LPSR */ - regulator-min-microvolt = <1775000>; - regulator-max-microvolt = <1825000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; regulator-boot-on; regulator-always-on; }; reg_LDO5: LDO5 { /* PWR_EN_+V3.3 */ - regulator-min-microvolt = <1775000>; - regulator-max-microvolt = <1825000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-boot-on; regulator-always-on; }; diff --git a/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts b/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts index bd01d2cc642d..a608a14d8c85 100644 --- a/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts +++ b/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts @@ -57,6 +57,7 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio4 7 GPIO_ACTIVE_LOW>; + vin-supply = <®_5v0>; }; }; diff --git a/arch/arm/boot/dts/imx7d-sdb-sht11.dts b/arch/arm/boot/dts/imx7d-sdb-sht11.dts new file mode 100644 index 000000000000..64a20ed1713a --- /dev/null +++ b/arch/arm/boot/dts/imx7d-sdb-sht11.dts @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "imx7d-sdb.dts" + +/ { + sensor { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor>; + compatible = "sensirion,sht15"; + clk-gpios = <&gpio4 12 0>; + data-gpios = <&gpio4 13 0>; + vcc-supply = <®_sht15>; + }; + + reg_sht15: regulator-sht15 { + compatible = "regulator-fixed"; + regulator-name = "reg_sht15"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&i2c3 { + status = "disabled"; +}; + +&iomuxc { + pinctrl_sensor: sensorgrp { + fsl,pins = < + MX7D_PAD_I2C3_SDA__GPIO4_IO13 0x4000007f + MX7D_PAD_I2C3_SCL__GPIO4_IO12 0x4000007f + >; + }; +}; diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi index 5d3a43b8de20..c4f12fd2e044 100644 --- a/arch/arm/boot/dts/imx7s.dtsi +++ b/arch/arm/boot/dts/imx7s.dtsi @@ -493,10 +493,9 @@ }; ocotp: ocotp-ctrl@30350000 { - compatible = "syscon"; + compatible = "fsl,imx7d-ocotp", "syscon"; reg = <0x30350000 0x10000>; - clocks = <&clks IMX7D_CLK_DUMMY>; - status = "disabled"; + clocks = <&clks IMX7D_OCOTP_CLK>; }; anatop: anatop@30360000 { @@ -559,7 +558,7 @@ }; src: src@30390000 { - compatible = "fsl,imx7d-src", "fsl,imx51-src", "syscon"; + compatible = "fsl,imx7d-src", "syscon"; reg = <0x30390000 0x10000>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; #reset-cells = <1>; diff --git a/arch/arm/boot/dts/include/arm b/arch/arm/boot/dts/include/arm new file mode 120000 index 000000000000..a96aa0ea9d8c --- /dev/null +++ b/arch/arm/boot/dts/include/arm @@ -0,0 +1 @@ +..
\ No newline at end of file diff --git a/arch/arm/boot/dts/include/arm64 b/arch/arm/boot/dts/include/arm64 new file mode 120000 index 000000000000..074a835fca3e --- /dev/null +++ b/arch/arm/boot/dts/include/arm64 @@ -0,0 +1 @@ +../../../../arm64/boot/dts
\ No newline at end of file diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi index 45619f6162c5..ebc763eab195 100644 --- a/arch/arm/boot/dts/meson8.dtsi +++ b/arch/arm/boot/dts/meson8.dtsi @@ -106,6 +106,7 @@ reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_cbus 0 0 120>; }; spi_nor_pins: nor { @@ -148,6 +149,7 @@ reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aobus 0 120 16>; }; uart_ao_a_pins: uart_ao_a { diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi index 41fd53671859..828aa49c678c 100644 --- a/arch/arm/boot/dts/meson8b.dtsi +++ b/arch/arm/boot/dts/meson8b.dtsi @@ -198,6 +198,7 @@ reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_cbus 0 0 130>; }; }; @@ -215,6 +216,7 @@ reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aobus 0 130 16>; }; uart_ao_a_pins: uart_ao_a { diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi new file mode 100644 index 000000000000..f5aeb3959afd --- /dev/null +++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi @@ -0,0 +1,243 @@ +/* + * Common CPCAP configuration used on Motorola phones + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +&mcspi1 { + cpcap: pmic@0 { + compatible = "motorola,cpcap", "st,6556002"; + reg = <0>; /* cs0 */ + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <3000000>; + spi-cs-high; + + cpcap_adc: adc { + compatible = "motorola,mapphone-cpcap-adc"; + interrupts-extended = <&cpcap 8 0>; + interrupt-names = "adcdone"; + #io-channel-cells = <1>; + }; + + cpcap_charger: charger { + compatible = "motorola,mapphone-cpcap-charger"; + interrupts-extended = < + &cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0 + &cpcap 22 0 &cpcap 20 0 &cpcap 19 0 &cpcap 54 0 + >; + interrupt-names = + "chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn", + "rvrs_mode", "chrgcurr1", "vbusvld", "battdetb"; + mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW + &gpio3 23 GPIO_ACTIVE_LOW>; + io-channels = <&cpcap_adc 0 &cpcap_adc 1 + &cpcap_adc 2 &cpcap_adc 5 + &cpcap_adc 6>; + io-channel-names = "battdetb", "battp", + "vbus", "chg_isense", + "batti"; + }; + + cpcap_regulator: regulator { + compatible = "motorola,mapphone-cpcap-regulator"; + + cpcap_regulators: regulators { + }; + }; + + cpcap_rtc: rtc { + compatible = "motorola,cpcap-rtc"; + + interrupt-parent = <&cpcap>; + interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>; + }; + + power_button: button { + compatible = "motorola,cpcap-pwrbutton"; + + interrupts = <23 IRQ_TYPE_NONE>; + }; + + cpcap_usb2_phy: phy { + compatible = "motorola,mapphone-cpcap-usb-phy"; + pinctrl-0 = <&usb_gpio_mux_sel1 &usb_gpio_mux_sel2>; + pinctrl-1 = <&usb_ulpi_pins>; + pinctrl-2 = <&usb_utmi_pins>; + pinctrl-3 = <&uart3_pins>; + pinctrl-names = "default", "ulpi", "utmi", "uart"; + #phy-cells = <0>; + interrupts-extended = < + &cpcap 15 0 &cpcap 14 0 &cpcap 28 0 &cpcap 19 0 + &cpcap 18 0 &cpcap 17 0 &cpcap 16 0 &cpcap 49 0 + &cpcap 48 1 + >; + interrupt-names = + "id_ground", "id_float", "se0conn", "vbusvld", + "sessvld", "sessend", "se1", "dm", "dp"; + mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH + &gpio1 0 GPIO_ACTIVE_HIGH>; + io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>; + io-channel-names = "vbus", "id"; + vusb-supply = <&vusb>; + }; + + led_red: led-red { + compatible = "motorola,cpcap-led-red"; + vdd-supply = <&sw5>; + label = "status-led:red"; + }; + + led_green: led-green { + compatible = "motorola,cpcap-led-green"; + vdd-supply = <&sw5>; + label = "status-led:green"; + }; + + led_blue: led-blue { + compatible = "motorola,cpcap-led-blue"; + vdd-supply = <&sw5>; + label = "status-led:blue"; + }; + + led_adl: led-adl { + compatible = "motorola,cpcap-led-adl"; + vdd-supply = <&sw5>; + label = "button-backlight"; + }; + + led_cp: led-cp { + compatible = "motorola,cpcap-led-cp"; + vdd-supply = <&sw5>; + label = "shift-key-light"; + }; + }; +}; + +&cpcap_regulators { + sw5: SW5 { + regulator-min-microvolt = <5050000>; + regulator-max-microvolt = <5050000>; + regulator-enable-ramp-delay = <50000>; + regulator-boot-on; + }; + + vcam: VCAM { + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + regulator-enable-ramp-delay = <1000>; + }; + + /* Used by DSS */ + vcsi: VCSI { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <1000>; + regulator-boot-on; + }; + + vdac: VDAC { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <1000>; + }; + + vdig: VDIG { + regulator-min-microvolt = <1875000>; + regulator-max-microvolt = <1875000>; + regulator-enable-ramp-delay = <1000>; + }; + + vfuse: VFUSE { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3150000>; + regulator-enable-ramp-delay = <1000>; + }; + + vhvio: VHVIO { + regulator-min-microvolt = <2775000>; + regulator-max-microvolt = <2775000>; + regulator-enable-ramp-delay = <1000>; + regulator-always-on; + }; + + /* Used by eMMC at mmc2 */ + vsdio: VSDIO { + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + regulator-enable-ramp-delay = <1000>; + }; + + vpll: VPLL { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <100>; + }; + + vrf1: VRF1 { + regulator-min-microvolt = <2775000>; + regulator-max-microvolt = <2775000>; + regulator-enable-ramp-delay = <1000>; + }; + + vrf2: VRF2 { + regulator-min-microvolt = <2775000>; + regulator-max-microvolt = <2775000>; + regulator-enable-ramp-delay = <1000>; + }; + + vrfref: VRFREF { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2775000>; + regulator-enable-ramp-delay = <100>; + }; + + vwlan1: VWLAN1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <1000>; + }; + + /* Used by micro-SDIO at mmc1 */ + vwlan2: VWLAN2 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <1000>; + }; + + vsim: VSIM { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-enable-ramp-delay = <1000>; + }; + + vsimcard: VSIMCARD { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-enable-ramp-delay = <1000>; + }; + + vvib: VVIB { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <500>; + }; + + vusb: VUSB { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <1000>; + }; + + vaudio: VAUDIO { + regulator-min-microvolt = <2775000>; + regulator-max-microvolt = <2775000>; + regulator-enable-ramp-delay = <1000>; + }; +}; diff --git a/arch/arm/boot/dts/moxart-uc7112lx.dts b/arch/arm/boot/dts/moxart-uc7112lx.dts index 10d088df0c35..4a962a26482d 100644 --- a/arch/arm/boot/dts/moxart-uc7112lx.dts +++ b/arch/arm/boot/dts/moxart-uc7112lx.dts @@ -6,7 +6,7 @@ */ /dts-v1/; -/include/ "moxart.dtsi" +#include "moxart.dtsi" / { model = "MOXA UC-7112-LX"; diff --git a/arch/arm/boot/dts/moxart.dtsi b/arch/arm/boot/dts/moxart.dtsi index 1fd27ed65a01..e86f8c905ac5 100644 --- a/arch/arm/boot/dts/moxart.dtsi +++ b/arch/arm/boot/dts/moxart.dtsi @@ -6,6 +6,7 @@ */ /include/ "skeleton.dtsi" +#include <dt-bindings/interrupt-controller/irq.h> / { compatible = "moxa,moxart"; @@ -36,8 +37,8 @@ ranges; intc: interrupt-controller@98800000 { - compatible = "moxa,moxart-ic"; - reg = <0x98800000 0x38>; + compatible = "moxa,moxart-ic", "faraday,ftintc010"; + reg = <0x98800000 0x100>; interrupt-controller; #interrupt-cells = <2>; interrupt-mask = <0x00080000>; @@ -59,15 +60,15 @@ timer: timer@98400000 { compatible = "moxa,moxart-timer"; reg = <0x98400000 0x42>; - interrupts = <19 1>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; clocks = <&clk_apb>; }; gpio: gpio@98700000 { gpio-controller; #gpio-cells = <2>; - compatible = "moxa,moxart-gpio"; - reg = <0x98700000 0xC>; + compatible = "moxa,moxart-gpio", "faraday,ftgpio010"; + reg = <0x98700000 0x100>; }; rtc: rtc { @@ -80,7 +81,7 @@ dma: dma@90500000 { compatible = "moxa,moxart-dma"; reg = <0x90500080 0x40>; - interrupts = <24 0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; #dma-cells = <1>; }; @@ -93,7 +94,7 @@ sdhci: sdhci@98e00000 { compatible = "moxa,moxart-sdhci"; reg = <0x98e00000 0x5C>; - interrupts = <5 0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk_apb>; dmas = <&dma 5>, <&dma 5>; @@ -120,7 +121,7 @@ mac0: mac@90900000 { compatible = "moxa,moxart-mac"; reg = <0x90900000 0x90>; - interrupts = <25 0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; phy-handle = <ðphy0>; phy-mode = "mii"; status = "disabled"; @@ -129,7 +130,7 @@ mac1: mac@92000000 { compatible = "moxa,moxart-mac"; reg = <0x92000000 0x90>; - interrupts = <27 0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; phy-handle = <ðphy1>; phy-mode = "mii"; status = "disabled"; @@ -138,7 +139,7 @@ uart0: uart@98200000 { compatible = "ns16550a"; reg = <0x98200000 0x20>; - interrupts = <31 8>; + interrupts = <31 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clock-frequency = <14745600>; diff --git a/arch/arm/boot/dts/omap3-cpu-thermal.dtsi b/arch/arm/boot/dts/omap3-cpu-thermal.dtsi new file mode 100644 index 000000000000..235ecfd61e2d --- /dev/null +++ b/arch/arm/boot/dts/omap3-cpu-thermal.dtsi @@ -0,0 +1,20 @@ +/* + * Device Tree Source for OMAP3 SoC CPU thermal + * + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <dt-bindings/thermal/thermal.h> + +cpu_thermal: cpu_thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + coefficients = <0 20000>; + + /* sensor ID */ + thermal-sensors = <&bandgap 0>; +}; diff --git a/arch/arm/boot/dts/omap3-igep.dtsi b/arch/arm/boot/dts/omap3-igep.dtsi index e268efde6c6d..4ad7d5565906 100644 --- a/arch/arm/boot/dts/omap3-igep.dtsi +++ b/arch/arm/boot/dts/omap3-igep.dtsi @@ -37,6 +37,13 @@ }; &omap3_pmx_core { + gpmc_pins: pinmux_gpmc_pins { + pinctrl-single,pins = < + /* OneNAND seems to require PIN_INPUT on clock. */ + OMAP3_CORE1_IOPAD(0x20be, PIN_INPUT | MUX_MODE0) /* gpmc_clk.gpmc_clk */ + >; + }; + uart1_pins: pinmux_uart1_pins { pinctrl-single,pins = < OMAP3_CORE1_IOPAD(0x2182, PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */ @@ -98,6 +105,9 @@ }; &gpmc { + pinctrl-names = "default"; + pinctrl-0 = <&gpmc_pins>; + nand@0,0 { compatible = "ti,omap2-nand"; reg = <0 0 4>; /* CS0, offset 0, IO size 4 */ @@ -126,6 +136,48 @@ #address-cells = <1>; #size-cells = <1>; + + status = "okay"; + }; + + onenand@0,0 { + compatible = "ti,omap2-onenand"; + reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */ + + gpmc,sync-read; + gpmc,sync-write; + gpmc,burst-length = <16>; + gpmc,burst-read; + gpmc,burst-wrap; + gpmc,burst-write; + gpmc,device-width = <2>; /* GPMC_DEVWIDTH_16BIT */ + gpmc,mux-add-data = <2>; /* GPMC_MUX_AD */ + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <87>; + gpmc,cs-wr-off-ns = <87>; + gpmc,adv-on-ns = <0>; + gpmc,adv-rd-off-ns = <10>; + gpmc,adv-wr-off-ns = <10>; + gpmc,oe-on-ns = <15>; + gpmc,oe-off-ns = <87>; + gpmc,we-on-ns = <0>; + gpmc,we-off-ns = <87>; + gpmc,rd-cycle-ns = <112>; + gpmc,wr-cycle-ns = <112>; + gpmc,access-ns = <81>; + gpmc,page-burst-access-ns = <15>; + gpmc,bus-turnaround-ns = <0>; + gpmc,cycle2cycle-delay-ns = <0>; + gpmc,wait-monitoring-ns = <0>; + gpmc,clk-activation-ns = <5>; + gpmc,wr-data-mux-bus-ns = <30>; + gpmc,wr-access-ns = <81>; + gpmc,sync-clk-ps = <15000>; + + #address-cells = <1>; + #size-cells = <1>; + + status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index b64cfda8dbb7..49f37084e435 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -155,6 +155,13 @@ compatible = "nokia,n900-ir"; pwms = <&pwm9 0 26316 0>; /* 38000 Hz */ }; + + /* controlled (enabled/disabled) directly by bcm2048 and wl1251 */ + vctcxo: vctcxo { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <38400000>; + }; }; &omap3_pmx_core { @@ -162,8 +169,10 @@ uart2_pins: pinmux_uart2_pins { pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx */ + OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts */ + OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts */ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx */ + OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx */ >; }; @@ -920,6 +929,8 @@ interrupt-parent = <&gpio2>; interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */ + + clocks = <&vctcxo>; }; }; @@ -937,9 +948,17 @@ }; &uart2 { - interrupts-extended = <&intc 73 &omap3_pmx_core OMAP3_UART2_RX>; pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; + + bcm2048: bluetooth { + compatible = "brcm,bcm2048-nokia", "nokia,h4p-bluetooth"; + reset-gpios = <&gpio3 27 GPIO_ACTIVE_LOW>; /* 91 */ + host-wakeup-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* 101 */ + bluetooth-wakeup-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>; /* 37 */ + clocks = <&vctcxo>; + clock-names = "sysclk"; + }; }; &uart3 { diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi index 5d8c4b4a4205..df3366fa5409 100644 --- a/arch/arm/boot/dts/omap3-n950-n9.dtsi +++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi @@ -58,6 +58,13 @@ pinctrl-0 = <&debug_leds>; }; }; + + /* controlled (enabled/disabled) directly by wl1271 */ + vctcxo: vctcxo { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <38400000>; + }; }; &omap3_pmx_core { @@ -125,6 +132,15 @@ OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE4) /* gpio_93 (cmt_apeslpx) */ >; }; + + uart2_pins: pinmux_uart2_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts */ + OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts */ + OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx */ + OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx */ + >; + }; }; &omap3_pmx_core2 { @@ -435,3 +451,19 @@ &ssi_port2 { status = "disabled"; }; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + + bluetooth { + compatible = "ti,wl1271-bluetooth-nokia", "nokia,h4p-bluetooth"; + + reset-gpios = <&gpio1 26 GPIO_ACTIVE_LOW>; /* 26 */ + host-wakeup-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* 101 */ + bluetooth-wakeup-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>; /* 37 */ + + clocks = <&vctcxo>; + clock-names = "sysclk"; + }; +}; diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi index 834fdf13601f..ac4f8795b756 100644 --- a/arch/arm/boot/dts/omap34xx.dtsi +++ b/arch/arm/boot/dts/omap34xx.dtsi @@ -14,7 +14,7 @@ / { cpus { - cpu@0 { + cpu: cpu@0 { /* OMAP343x/OMAP35xx variants OPP1-5 */ operating-points = < /* kHz uV */ @@ -56,12 +56,16 @@ }; }; - bandgap@48002524 { + bandgap: bandgap@48002524 { reg = <0x48002524 0x4>; compatible = "ti,omap34xx-bandgap"; #thermal-sensor-cells = <0>; }; }; + + thermal_zones: thermal-zones { + #include "omap3-cpu-thermal.dtsi" + }; }; &ssi { diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index d1a3e56b50ce..ade31d74c70c 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -19,7 +19,7 @@ cpus { /* OMAP3630/OMAP37xx 'standard device' variants OPP50 to OPP130 */ - cpu@0 { + cpu: cpu@0 { operating-points = < /* kHz uV */ 300000 1012500 @@ -88,12 +88,16 @@ }; }; - bandgap@48002524 { + bandgap: bandgap@48002524 { reg = <0x48002524 0x4>; compatible = "ti,omap36xx-bandgap"; #thermal-sensor-cells = <0>; }; }; + + thermal_zones: thermal-zones { + #include "omap3-cpu-thermal.dtsi" + }; }; /* OMAP3630 needs dss_96m_fck for VENC */ diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts index f3ccb4ceed9e..89eb607f4a9e 100644 --- a/arch/arm/boot/dts/omap4-droid4-xt894.dts +++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts @@ -5,7 +5,9 @@ */ /dts-v1/; +#include <dt-bindings/input/input.h> #include "omap443x.dtsi" +#include "motorola-cpcap-mapphone.dtsi" / { model = "Motorola Droid 4 XT894"; @@ -15,35 +17,76 @@ stdout-path = &uart3; }; + aliases { + display0 = &lcd0; + display1 = &hdmi0; + }; + /* * We seem to have only 1021 MB accessible, 1021 - 1022 is locked, - * then 1023 - 1024 seems to contain mbm. For SRAM, see the notes - * below about SRAM and L3_ICLK2 being unused by default, + * then 1023 - 1024 seems to contain mbm. */ memory { device_type = "memory"; reg = <0x80000000 0x3fd00000>; /* 1021 MB */ }; - /* CPCAP really supports 1650000 to 3400000 range */ - vmmc: regulator-mmc { + /* Poweroff GPIO probably connected to CPCAP */ + gpio-poweroff { + compatible = "gpio-poweroff"; + pinctrl-0 = <&poweroff_gpio>; + pinctrl-names = "default"; + gpios = <&gpio2 18 GPIO_ACTIVE_LOW>; /* gpio50 */ + }; + + hdmi0: connector { + compatible = "hdmi-connector"; + pinctrl-0 = <&hdmi_hpd_gpio>; + pinctrl-names = "default"; + label = "hdmi"; + type = "d"; + + hpd-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>; /* gpio63 */ + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_out>; + }; + }; + }; + + /* + * HDMI 5V regulator probably sourced from battery. Let's keep + * keep this as always enabled for HDMI to work until we've + * figured what the encoder chip is. + */ + hdmi_regulator: regulator-hdmi { compatible = "regulator-fixed"; - regulator-name = "vmmc"; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; + regulator-name = "hdmi"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio2 27 GPIO_ACTIVE_HIGH>; /* gpio59 */ + enable-active-high; regulator-always-on; }; - /* CPCAP really supports 3000000 to 3100000 range */ - vemmc: regulator-emmc { + /* HS USB Host PHY on PORT 1 */ + hsusb1_phy: hsusb1_phy { + compatible = "usb-nop-xceiv"; + }; + + /* LCD regulator from sw5 source */ + lcd_regulator: regulator-lcd { compatible = "regulator-fixed"; - regulator-name = "vemmc"; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-always-on; + regulator-name = "lcd"; + regulator-min-microvolt = <5050000>; + regulator-max-microvolt = <5050000>; + gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>; /* gpio96 */ + enable-active-high; + vin-supply = <&sw5>; }; - /* CPCAP really supports 1650000 to 1950000 range */ + /* This is probably coming straight from the battery.. */ wl12xx_vmmc: regulator-wl12xx { compatible = "regulator-fixed"; regulator-name = "vwl1271"; @@ -53,21 +96,195 @@ startup-delay-us = <70000>; enable-active-high; }; + + gpio_keys { + compatible = "gpio-keys"; + + volume_down { + label = "Volume Down"; + gpios = <&gpio5 26 GPIO_ACTIVE_LOW>; /* gpio154 */ + linux,code = <KEY_VOLUMEDOWN>; + linux,can-disable; + }; + + slider { + label = "Keypad Slide"; + gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; /* gpio122 */ + linux,input-type = <EV_SW>; + linux,code = <SW_KEYPAD_SLIDE>; + linux,can-disable; + + }; + }; +}; + +&dss { + status = "okay"; +}; + +&gpio6 { + touchscreen_reset { + gpio-hog; + gpios = <13 0>; + output-high; + line-name = "touchscreen-reset"; + }; +}; + +&dsi1 { + status = "okay"; + vdd-supply = <&vcsi>; + + port { + dsi1_out_ep: endpoint { + remote-endpoint = <&lcd0_in>; + lanes = <0 1 2 3 4 5>; + }; + }; + + lcd0: display { + compatible = "panel-dsi-cm"; + label = "lcd0"; + vddi-supply = <&lcd_regulator>; + reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ + + panel-timing { + clock-frequency = <0>; /* Calculated by dsi */ + + hback-porch = <2>; + hactive = <540>; + hfront-porch = <0>; + hsync-len = <2>; + + vback-porch = <1>; + vactive = <960>; + vfront-porch = <0>; + vsync-len = <1>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + + port { + lcd0_in: endpoint { + remote-endpoint = <&dsi1_out_ep>; + }; + }; + }; }; -/* L3_2 interconnect is unused, SRAM, GPMC and L3_ICLK2 disabled */ -&gpmc { - status = "disabled"; +&hdmi { + status = "okay"; + pinctrl-0 = <&dss_hdmi_pins>; + pinctrl-names = "default"; + vdda-supply = <&vdac>; + + port { + hdmi_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + lanes = <1 0 3 2 5 4 7 6>; + }; + }; +}; + +&i2c1 { + tmp105@48 { + compatible = "ti,tmp105"; + reg = <0x48>; + pinctrl-0 = <&tmp105_irq>; + pinctrl-names = "default"; + /* kpd_row0.gpio_178 */ + interrupts-extended = <&gpio6 18 IRQ_TYPE_EDGE_FALLING + &omap4_pmx_core 0x14e>; + interrupt-names = "irq", "wakeup"; + wakeup-source; + }; +}; + +&keypad { + keypad,num-rows = <8>; + keypad,num-columns = <8>; + linux,keymap = < + + /* Row 1 */ + MATRIX_KEY(0, 2, KEY_1) + MATRIX_KEY(0, 6, KEY_2) + MATRIX_KEY(2, 3, KEY_3) + MATRIX_KEY(0, 7, KEY_4) + MATRIX_KEY(0, 4, KEY_5) + MATRIX_KEY(5, 5, KEY_6) + MATRIX_KEY(0, 1, KEY_7) + MATRIX_KEY(0, 5, KEY_8) + MATRIX_KEY(0, 0, KEY_9) + MATRIX_KEY(1, 6, KEY_0) + + /* Row 2 */ + MATRIX_KEY(3, 4, KEY_APOSTROPHE) + MATRIX_KEY(7, 6, KEY_Q) + MATRIX_KEY(7, 7, KEY_W) + MATRIX_KEY(7, 2, KEY_E) + MATRIX_KEY(1, 0, KEY_R) + MATRIX_KEY(4, 4, KEY_T) + MATRIX_KEY(1, 2, KEY_Y) + MATRIX_KEY(6, 7, KEY_U) + MATRIX_KEY(2, 2, KEY_I) + MATRIX_KEY(5, 6, KEY_O) + MATRIX_KEY(3, 7, KEY_P) + MATRIX_KEY(6, 5, KEY_BACKSPACE) + + /* Row 3 */ + MATRIX_KEY(5, 4, KEY_TAB) + MATRIX_KEY(5, 7, KEY_A) + MATRIX_KEY(2, 7, KEY_S) + MATRIX_KEY(7, 0, KEY_D) + MATRIX_KEY(2, 6, KEY_F) + MATRIX_KEY(6, 2, KEY_G) + MATRIX_KEY(6, 6, KEY_H) + MATRIX_KEY(1, 4, KEY_J) + MATRIX_KEY(3, 1, KEY_K) + MATRIX_KEY(2, 1, KEY_L) + MATRIX_KEY(4, 6, KEY_ENTER) + + /* Row 4 */ + MATRIX_KEY(3, 6, KEY_LEFTSHIFT) /* KEY_CAPSLOCK */ + MATRIX_KEY(6, 1, KEY_Z) + MATRIX_KEY(7, 4, KEY_X) + MATRIX_KEY(5, 1, KEY_C) + MATRIX_KEY(1, 7, KEY_V) + MATRIX_KEY(2, 4, KEY_B) + MATRIX_KEY(4, 1, KEY_N) + MATRIX_KEY(1, 1, KEY_M) + MATRIX_KEY(3, 5, KEY_COMMA) + MATRIX_KEY(5, 2, KEY_DOT) + MATRIX_KEY(6, 3, KEY_UP) + MATRIX_KEY(7, 3, KEY_OK) + + /* Row 5 */ + MATRIX_KEY(2, 5, KEY_LEFTCTRL) /* KEY_LEFTSHIFT */ + MATRIX_KEY(4, 5, KEY_LEFTALT) /* SYM */ + MATRIX_KEY(6, 0, KEY_MINUS) + MATRIX_KEY(4, 7, KEY_EQUAL) + MATRIX_KEY(1, 5, KEY_SPACE) + MATRIX_KEY(3, 2, KEY_SLASH) + MATRIX_KEY(4, 3, KEY_LEFT) + MATRIX_KEY(5, 3, KEY_DOWN) + MATRIX_KEY(3, 3, KEY_RIGHT) + + /* Side buttons, KEY_VOLUMEDOWN and KEY_PWER are on CPCAP? */ + MATRIX_KEY(5, 0, KEY_VOLUMEUP) + >; }; &mmc1 { - vmmc-supply = <&vmmc>; + vmmc-supply = <&vwlan2>; bus-width = <4>; - cd-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; /* gpio106 */ + cd-gpios = <&gpio6 16 GPIO_ACTIVE_LOW>; /* gpio176 */ }; &mmc2 { - vmmc-supply = <&vemmc>; + vmmc-supply = <&vsdio>; bus-width = <8>; non-removable; }; @@ -93,12 +310,78 @@ }; }; -/* L3_2 interconnect is unused, SRAM, GPMC and L3_ICLK2 disabled */ -&ocmcram { - status = "disabled"; +&i2c1 { + lm3532@38 { + compatible = "ti,lm3532"; + reg = <0x38>; + + enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>; + + backlight { + compatible = "ti,lm3532-backlight"; + + lcd { + led-sources = <0 1 2>; + ramp-up-msec = <1>; + ramp-down-msec = <0>; + }; + }; + }; +}; + +/* + * REVISIT: Add gpio173 reset pin handling to the driver, see gpio-hog above. + * If the GPIO reset is used, we probably need to have /lib/firmware/maxtouch.fw + * available. See "mxt-app" and "droid4-touchscreen-firmware" tools for more + * information. + */ +&i2c2 { + tsp@4a { + compatible = "atmel,maxtouch"; + reg = <0x4a>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + + /* gpio_183 with sys_nirq2 pad as wakeup */ + interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING + &omap4_pmx_core 0x160>; + interrupt-names = "irq", "wakeup"; + wakeup-source; + }; }; &omap4_pmx_core { + + /* hdmi_hpd.gpio_63 */ + hdmi_hpd_gpio: pinmux_hdmi_hpd_pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x098, PIN_INPUT | MUX_MODE3) + >; + }; + + /* hdmi_cec.hdmi_cec, hdmi_scl.hdmi_scl, hdmi_sda.hdmi_sda */ + dss_hdmi_pins: pinmux_dss_hdmi_pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x09a, PIN_INPUT_PULLUP | MUX_MODE0) + OMAP4_IOPAD(0x09c, PIN_INPUT | MUX_MODE0) + OMAP4_IOPAD(0x09e, PIN_INPUT | MUX_MODE0) + >; + }; + + /* gpmc_ncs0.gpio_50 */ + poweroff_gpio: pinmux_poweroff_pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x074, PIN_OUTPUT_PULLUP | MUX_MODE3) + >; + }; + + /* kpd_row0.gpio_178 */ + tmp105_irq: pinmux_tmp105_irq { + pinctrl-single,pins = < + OMAP4_IOPAD(0x18e, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + usb_gpio_mux_sel1: pinmux_usb_gpio_mux_sel1_pins { /* gpio_60 */ pinctrl-single,pins = < @@ -106,6 +389,12 @@ >; }; + touchscreen_pins: pinmux_touchscreen_pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + usb_ulpi_pins: pinmux_usb_ulpi_pins { pinctrl-single,pins = < OMAP4_IOPAD(0x196, MUX_MODE7) @@ -180,9 +469,49 @@ &omap4_pmx_core 0x17c>; }; +&usbhsehci { + phys = <&hsusb1_phy>; +}; + +&usbhshost { + port1-mode = "ohci-phy-4pin-dpdm"; + port2-mode = "ehci-tll"; +}; + /* Internal UTMI+ PHY used for OTG, CPCAP ULPI PHY for detection and charger */ &usb_otg_hs { interface-type = <1>; mode = <3>; power = <50>; }; + +&i2c4 { + ak8975: magnetometer@c { + compatible = "asahi-kasei,ak8975"; + reg = <0x0c>; + + vdd-supply = <&vhvio>; + + interrupt-parent = <&gpio6>; + interrupts = <15 IRQ_TYPE_EDGE_RISING>; /* gpio175 */ + + rotation-matrix = "-1", "0", "0", + "0", "1", "0", + "0", "0", "-1"; + + }; + + lis3dh: accelerometer@18 { + compatible = "st,lis3dh-accel"; + reg = <0x18>; + + vdd-supply = <&vhvio>; + + interrupt-parent = <&gpio2>; + interrupts = <2 IRQ_TYPE_EDGE_BOTH>; /* gpio34 */ + + rotation-matrix = "0", "-1", "0", + "1", "0", "0", + "0", "0", "1"; + }; +}; diff --git a/arch/arm/boot/dts/omap443x.dtsi b/arch/arm/boot/dts/omap443x.dtsi index fc6a8610c24c..03c8ad91ddac 100644 --- a/arch/arm/boot/dts/omap443x.dtsi +++ b/arch/arm/boot/dts/omap443x.dtsi @@ -71,4 +71,8 @@ }; +&cpu_thermal { + coefficients = <0 20000>; +}; + /include/ "omap443x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi index ef66e12e0a67..c43f2a2d0a1e 100644 --- a/arch/arm/boot/dts/omap4460.dtsi +++ b/arch/arm/boot/dts/omap4460.dtsi @@ -90,4 +90,8 @@ }; +&cpu_thermal { + coefficients = <348 (-9301)>; +}; + /include/ "omap446x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 222155ca8ad7..eaff2a5751dd 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -1127,6 +1127,15 @@ &cpu_thermal { polling-delay = <500>; /* milliseconds */ + coefficients = <65 (-1791)>; }; /include/ "omap54xx-clocks.dtsi" + +&gpu_thermal { + coefficients = <117 (-2992)>; +}; + +&core_thermal { + coefficients = <0 2000>; +}; diff --git a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts index 39d9e6ddefed..2da1413f5720 100644 --- a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts @@ -95,17 +95,17 @@ function = "sdc1"; }; clk { - pins = "gpio167"; /* SDC5 CLK */ + pins = "gpio167"; /* SDC1 CLK */ drive-strength = <16>; bias-disable; }; cmd { - pins = "gpio168"; /* SDC5 CMD */ + pins = "gpio168"; /* SDC1 CMD */ drive-strength = <10>; bias-pull-up; }; data { - /* SDC5 D0 to D7 */ + /* SDC1 D0 to D7 */ pins = "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164", "gpio165", "gpio166"; drive-strength = <10>; diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi index 91c9a62ae725..747669a62aa8 100644 --- a/arch/arm/boot/dts/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom-msm8660.dtsi @@ -392,6 +392,21 @@ cap-mmc-highspeed; }; + sdcc2: sdcc@12140000 { + status = "disabled"; + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; + reg = <0x12140000 0x8000>; + interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cmd_irq"; + clocks = <&gcc SDC2_CLK>, <&gcc SDC2_H_CLK>; + clock-names = "mclk", "apb_pclk"; + bus-width = <8>; + max-frequency = <48000000>; + cap-sd-highspeed; + cap-mmc-highspeed; + }; + sdcc3: sdcc@12180000 { compatible = "arm,pl18x", "arm,primecell"; arm,primecell-periphid = <0x00051180>; @@ -408,6 +423,21 @@ no-1-8-v; }; + sdcc4: sdcc@121c0000 { + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; + status = "disabled"; + reg = <0x121c0000 0x8000>; + interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cmd_irq"; + clocks = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>; + clock-names = "mclk", "apb_pclk"; + bus-width = <4>; + max-frequency = <48000000>; + cap-sd-highspeed; + cap-mmc-highspeed; + }; + sdcc5: sdcc@12200000 { compatible = "arm,pl18x", "arm,primecell"; arm,primecell-periphid = <0x00051180>; diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts index 96c853bab8ba..e7c1577d56f4 100644 --- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts +++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts @@ -413,14 +413,6 @@ dma-controller@f9944000 { qcom,controlled-remotely; }; - - usb-phy@f9a55000 { - status = "ok"; - }; - - usb@f9a55000 { - status = "ok"; - }; }; &spmi_bus { diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index d3e1a61b8671..307bf6a647b3 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -2,8 +2,8 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/clock/qcom,gcc-msm8974.h> +#include <dt-bindings/clock/qcom,rpmcc.h> #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/reset/qcom,gcc-msm8974.h> #include "skeleton.dtsi" / { @@ -67,7 +67,7 @@ #size-cells = <0>; interrupts = <1 9 0xf04>; - cpu@0 { + CPU0: cpu@0 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; @@ -78,7 +78,7 @@ cpu-idle-states = <&CPU_SPC>; }; - cpu@1 { + CPU1: cpu@1 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; @@ -89,7 +89,7 @@ cpu-idle-states = <&CPU_SPC>; }; - cpu@2 { + CPU2: cpu@2 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; @@ -100,7 +100,7 @@ cpu-idle-states = <&CPU_SPC>; }; - cpu@3 { + CPU3: cpu@3 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; @@ -250,6 +250,9 @@ cx-supply = <&pm8841_s2>; + clocks = <&xo_board>; + clock-names = "xo"; + memory-region = <&adsp_region>; qcom,smem-states = <&adsp_smp2p_out 0>; @@ -695,42 +698,276 @@ qcom,ee = <0>; }; - usb1_phy: usb-phy@f9a55000 { - compatible = "qcom,usb-otg-snps"; + etr@fc322000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0xfc322000 0x1000>; - reg = <0xf9a55000 0x400>; - interrupts-extended = <&intc 0 134 0>, <&intc 0 140 0>, - <&spmi_bus 0 0x9 0 0>; - interrupt-names = "core_irq", "async_irq", "pmic_id_irq"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; - vddcx-supply = <&pm8841_s2>; - v3p3-supply = <&pm8941_l24>; - v1p8-supply = <&pm8941_l6>; + port { + etr_in: endpoint { + slave-mode; + remote-endpoint = <&replicator_out0>; + }; + }; + }; - dr_mode = "otg"; - qcom,phy-init-sequence = <0x63 0x81 0xfffffff>; - qcom,otg-control = <1>; - qcom,phy-num = <0>; + tpiu@fc318000 { + compatible = "arm,coresight-tpiu", "arm,primecell"; + reg = <0xfc318000 0x1000>; - resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>; - reset-names = "phy", "link"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; - clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>, - <&gcc GCC_USB_HS_AHB_CLK>; - clock-names = "phy", "core", "iface"; + port { + tpiu_in: endpoint { + slave-mode; + remote-endpoint = <&replicator_out1>; + }; + }; + }; - status = "disabled"; + replicator@fc31c000 { + compatible = "qcom,coresight-replicator1x", "arm,primecell"; + reg = <0xfc31c000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out0: endpoint { + remote-endpoint = <&etr_in>; + }; + }; + port@1 { + reg = <1>; + replicator_out1: endpoint { + remote-endpoint = <&tpiu_in>; + }; + }; + port@2 { + reg = <0>; + replicator_in: endpoint { + slave-mode; + remote-endpoint = <&etf_out>; + }; + }; + }; }; - usb@f9a55000 { - compatible = "qcom,ci-hdrc"; - reg = <0xf9a55000 0x400>; - dr_mode = "otg"; - interrupts = <0 134 0>, <0 140 0>; - interrupt-names = "core_irq", "async_irq"; - usb-phy = <&usb1_phy>; + etf@fc307000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0xfc307000 0x1000>; - status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + etf_out: endpoint { + remote-endpoint = <&replicator_in>; + }; + }; + port@1 { + reg = <0>; + etf_in: endpoint { + slave-mode; + remote-endpoint = <&merger_out>; + }; + }; + }; + }; + + funnel@fc31b000 { + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0xfc31b000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* + * Not described input ports: + * 0 - connected trought funnel to Audio, Modem and + * Resource and Power Manager CPU's + * 2...7 - not-connected + */ + port@1 { + reg = <1>; + merger_in1: endpoint { + slave-mode; + remote-endpoint = <&funnel1_out>; + }; + }; + port@8 { + reg = <0>; + merger_out: endpoint { + remote-endpoint = <&etf_in>; + }; + }; + }; + }; + + funnel@fc31a000 { + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0xfc31a000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* + * Not described input ports: + * 0 - not-connected + * 1 - connected trought funnel to Multimedia CPU + * 2 - connected to Wireless CPU + * 3 - not-connected + * 4 - not-connected + * 6 - not-connected + * 7 - connected to STM + */ + port@5 { + reg = <5>; + funnel1_in5: endpoint { + slave-mode; + remote-endpoint = <&kpss_out>; + }; + }; + port@8 { + reg = <0>; + funnel1_out: endpoint { + remote-endpoint = <&merger_in1>; + }; + }; + }; + }; + + funnel@fc345000 { /* KPSS funnel only 4 inputs are used */ + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0xfc345000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + kpss_in0: endpoint { + slave-mode; + remote-endpoint = <&etm0_out>; + }; + }; + port@1 { + reg = <1>; + kpss_in1: endpoint { + slave-mode; + remote-endpoint = <&etm1_out>; + }; + }; + port@2 { + reg = <2>; + kpss_in2: endpoint { + slave-mode; + remote-endpoint = <&etm2_out>; + }; + }; + port@3 { + reg = <3>; + kpss_in3: endpoint { + slave-mode; + remote-endpoint = <&etm3_out>; + }; + }; + port@8 { + reg = <0>; + kpss_out: endpoint { + remote-endpoint = <&funnel1_in5>; + }; + }; + }; + }; + + etm@fc33c000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0xfc33c000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU0>; + + port { + etm0_out: endpoint { + remote-endpoint = <&kpss_in0>; + }; + }; + }; + + etm@fc33d000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0xfc33d000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU1>; + + port { + etm1_out: endpoint { + remote-endpoint = <&kpss_in1>; + }; + }; + }; + + etm@fc33e000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0xfc33e000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU2>; + + port { + etm2_out: endpoint { + remote-endpoint = <&kpss_in2>; + }; + }; + }; + + etm@fc33f000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0xfc33f000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU3>; + + port { + etm3_out: endpoint { + remote-endpoint = <&kpss_in3>; + }; + }; }; }; @@ -760,6 +997,11 @@ compatible = "qcom,rpm-msm8974"; qcom,smd-channels = "rpm_requests"; + rpmcc: clock-controller { + compatible = "qcom,rpmcc-msm8974", "qcom,rpmcc"; + #clock-cells = <1>; + }; + pm8841-regulators { compatible = "qcom,rpm-pm8841-regulators"; diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts index 118a8e2b86bd..52a7b586bac7 100644 --- a/arch/arm/boot/dts/r7s72100-genmai.dts +++ b/arch/arm/boot/dts/r7s72100-genmai.dts @@ -44,6 +44,10 @@ clock-frequency = <48000000>; }; +&rtc_x1_clk { + clock-frequency = <32768>; +}; + &mtu2 { status = "okay"; }; @@ -59,6 +63,10 @@ }; }; +&rtc { + status = "okay"; +}; + &scif2 { status = "okay"; }; diff --git a/arch/arm/boot/dts/r7s72100-rskrza1.dts b/arch/arm/boot/dts/r7s72100-rskrza1.dts index 02b59c5b3c53..72df20a04320 100644 --- a/arch/arm/boot/dts/r7s72100-rskrza1.dts +++ b/arch/arm/boot/dts/r7s72100-rskrza1.dts @@ -43,6 +43,10 @@ clock-frequency = <48000000>; }; +&rtc_x1_clk { + clock-frequency = <32768>; +}; + &mtu2 { status = "okay"; }; @@ -69,6 +73,10 @@ status = "okay"; }; +&rtc { + status = "okay"; +}; + &scif2 { status = "okay"; }; diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi index 1cf2bd038090..0423996e4dcc 100644 --- a/arch/arm/boot/dts/r7s72100.dtsi +++ b/arch/arm/boot/dts/r7s72100.dtsi @@ -51,6 +51,20 @@ clock-frequency = <0>; }; + rtc_x1_clk: rtc_x1 { + #clock-cells = <0>; + compatible = "fixed-clock"; + /* If clk present, value must be set by board to 32678 */ + clock-frequency = <0>; + }; + + rtc_x3_clk: rtc_x3 { + #clock-cells = <0>; + compatible = "fixed-clock"; + /* If clk present, value must be set by board to 4000000 */ + clock-frequency = <0>; + }; + /* Fixed factor clocks */ b_clk: b { #clock-cells = <0>; @@ -117,11 +131,20 @@ clock-output-names = "ostm0", "ostm1"; }; + mstp6_clks: mstp6_clks@fcfe042c { + #clock-cells = <1>; + compatible = "renesas,r7s72100-mstp-clocks", "renesas,cpg-mstp-clocks"; + reg = <0xfcfe042c 4>; + clocks = <&p0_clk>; + clock-indices = <R7S72100_CLK_RTC>; + clock-output-names = "rtc"; + }; + mstp7_clks: mstp7_clks@fcfe0430 { #clock-cells = <1>; compatible = "renesas,r7s72100-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0xfcfe0430 4>; - clocks = <&p0_clk>; + clocks = <&b_clk>; clock-indices = <R7S72100_CLK_ETHER>; clock-output-names = "ether"; }; @@ -162,9 +185,12 @@ #clock-cells = <1>; compatible = "renesas,r7s72100-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0xfcfe0444 4>; - clocks = <&p1_clk>, <&p1_clk>; - clock-indices = <R7S72100_CLK_SDHI1 R7S72100_CLK_SDHI0>; - clock-output-names = "sdhi1", "sdhi0"; + clocks = <&p1_clk>, <&p1_clk>, <&p1_clk>, <&p1_clk>; + clock-indices = < + R7S72100_CLK_SDHI00 R7S72100_CLK_SDHI01 + R7S72100_CLK_SDHI10 R7S72100_CLK_SDHI11 + >; + clock-output-names = "sdhi00", "sdhi01", "sdhi10", "sdhi11"; }; }; @@ -379,6 +405,13 @@ cache-level = <2>; }; + wdt: watchdog@fcfe0000 { + compatible = "renesas,r7s72100-wdt", "renesas,rza-wdt"; + reg = <0xfcfe0000 0x6>; + interrupts = <GIC_SPI 106 IRQ_TYPE_EDGE_RISING>; + clocks = <&p0_clk>; + }; + i2c0: i2c@fcfee000 { #address-cells = <1>; #size-cells = <0>; @@ -499,7 +532,10 @@ GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp12_clks R7S72100_CLK_SDHI0>; + clocks = <&mstp12_clks R7S72100_CLK_SDHI00>, + <&mstp12_clks R7S72100_CLK_SDHI01>; + clock-names = "core", "cd"; + power-domains = <&cpg_clocks>; cap-sd-highspeed; cap-sdio-irq; status = "disabled"; @@ -512,7 +548,10 @@ GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp12_clks R7S72100_CLK_SDHI1>; + clocks = <&mstp12_clks R7S72100_CLK_SDHI10>, + <&mstp12_clks R7S72100_CLK_SDHI11>; + clock-names = "core", "cd"; + power-domains = <&cpg_clocks>; cap-sd-highspeed; cap-sdio-irq; status = "disabled"; @@ -535,4 +574,18 @@ power-domains = <&cpg_clocks>; status = "disabled"; }; + + rtc: rtc@fcff1000 { + compatible = "renesas,r7s72100-rtc", "renesas,sh-rtc"; + reg = <0xfcff1000 0x2e>; + interrupts = <GIC_SPI 276 IRQ_TYPE_EDGE_RISING + GIC_SPI 277 IRQ_TYPE_EDGE_RISING + GIC_SPI 278 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "alarm", "period", "carry"; + clocks = <&mstp6_clks R7S72100_CLK_RTC>, <&rtc_x1_clk>, + <&rtc_x3_clk>, <&extal_clk>; + clock-names = "fck", "rtc_x1", "rtc_x3", "extal"; + power-domains = <&cpg_clocks>; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/r8a73a4.dtsi b/arch/arm/boot/dts/r8a73a4.dtsi index 00eb9a7114dc..1f5c9f6dddba 100644 --- a/arch/arm/boot/dts/r8a73a4.dtsi +++ b/arch/arm/boot/dts/r8a73a4.dtsi @@ -32,18 +32,16 @@ next-level-cache = <&L2_CA15>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; clocks = <&cpg_clocks R8A73A4_CLK_Z>; power-domains = <&pd_a3sm>; cache-unified; cache-level = <2>; }; - L2_CA7: cache-controller@100 { + L2_CA7: cache-controller-1 { compatible = "cache"; - reg = <0x100>; clocks = <&cpg_clocks R8A73A4_CLK_Z2>; power-domains = <&pd_a3km>; cache-unified; @@ -469,6 +467,9 @@ <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + clocks = <&mstp4_clks R8A73A4_CLK_INTC_SYS>; + clock-names = "clk"; + power-domains = <&pd_c4>; }; bsc: bus@fec10000 { @@ -727,16 +728,18 @@ mstp4_clks: mstp4_clks@e6150140 { compatible = "renesas,r8a73a4-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>; - clocks = <&main_div2_clk>, <&main_div2_clk>, + clocks = <&main_div2_clk>, <&cpg_clocks R8A73A4_CLK_ZS>, + <&main_div2_clk>, <&cpg_clocks R8A73A4_CLK_HP>, <&cpg_clocks R8A73A4_CLK_HP>; #clock-cells = <1>; clock-indices = < - R8A73A4_CLK_IRQC R8A73A4_CLK_IIC5 - R8A73A4_CLK_IIC4 R8A73A4_CLK_IIC3 + R8A73A4_CLK_IRQC R8A73A4_CLK_INTC_SYS + R8A73A4_CLK_IIC5 R8A73A4_CLK_IIC4 + R8A73A4_CLK_IIC3 >; clock-output-names = - "irqc", "iic5", "iic4", "iic3"; + "irqc", "intc-sys", "iic5", "iic4", "iic3"; }; mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a73a4-mstp-clocks", "renesas,cpg-mstp-clocks"; diff --git a/arch/arm/boot/dts/r8a7743.dtsi b/arch/arm/boot/dts/r8a7743.dtsi index d8393b97768b..0ddac81742e4 100644 --- a/arch/arm/boot/dts/r8a7743.dtsi +++ b/arch/arm/boot/dts/r8a7743.dtsi @@ -32,9 +32,8 @@ next-level-cache = <&L2_CA15>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; cache-unified; cache-level = <2>; power-domains = <&sysc R8A7743_PD_CA15_SCU>; @@ -63,6 +62,7 @@ clocks = <&cpg CPG_MOD 408>; clock-names = "clk"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 408>; }; irqc: interrupt-controller@e61c0000 { @@ -82,6 +82,7 @@ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 407>; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 407>; }; timer { @@ -103,6 +104,7 @@ clock-names = "extal", "usb_extal"; #clock-cells = <2>; #power-domain-cells = <0>; + #reset-cells = <1>; }; prr: chipid@ff000044 { @@ -149,6 +151,7 @@ clocks = <&cpg CPG_MOD 219>; clock-names = "fck"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 219>; #dma-cells = <1>; dma-channels = <15>; }; @@ -181,6 +184,7 @@ clocks = <&cpg CPG_MOD 218>; clock-names = "fck"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 218>; #dma-cells = <1>; dma-channels = <15>; }; @@ -196,6 +200,7 @@ <&dmac1 0x21>, <&dmac1 0x22>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 204>; status = "disabled"; }; @@ -210,6 +215,7 @@ <&dmac1 0x25>, <&dmac1 0x26>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 203>; status = "disabled"; }; @@ -224,6 +230,7 @@ <&dmac1 0x27>, <&dmac1 0x28>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 202>; status = "disabled"; }; @@ -238,6 +245,7 @@ <&dmac1 0x1b>, <&dmac1 0x1c>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 1106>; status = "disabled"; }; @@ -252,6 +260,7 @@ <&dmac1 0x1f>, <&dmac1 0x20>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 1107>; status = "disabled"; }; @@ -266,6 +275,7 @@ <&dmac1 0x23>, <&dmac1 0x24>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 1108>; status = "disabled"; }; @@ -277,9 +287,10 @@ clocks = <&cpg CPG_MOD 206>; clock-names = "fck"; dmas = <&dmac0 0x3d>, <&dmac0 0x3e>, - <&dmac1 0x3d>, <&dmac1 0x3e>; + <&dmac1 0x3d>, <&dmac1 0x3e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 206>; status = "disabled"; }; @@ -294,6 +305,7 @@ <&dmac1 0x19>, <&dmac1 0x1a>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 207>; status = "disabled"; }; @@ -308,6 +320,7 @@ <&dmac1 0x1d>, <&dmac1 0x1e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 216>; status = "disabled"; }; @@ -323,6 +336,7 @@ <&dmac1 0x29>, <&dmac1 0x2a>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 721>; status = "disabled"; }; @@ -338,6 +352,7 @@ <&dmac1 0x2d>, <&dmac1 0x2e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 720>; status = "disabled"; }; @@ -353,6 +368,7 @@ <&dmac1 0x2b>, <&dmac1 0x2c>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 719>; status = "disabled"; }; @@ -368,6 +384,7 @@ <&dmac1 0x2f>, <&dmac1 0x30>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 718>; status = "disabled"; }; @@ -383,6 +400,7 @@ <&dmac1 0xfb>, <&dmac1 0xfc>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 715>; status = "disabled"; }; @@ -398,6 +416,7 @@ <&dmac1 0xfd>, <&dmac1 0xfe>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 714>; status = "disabled"; }; @@ -413,6 +432,7 @@ <&dmac1 0x39>, <&dmac1 0x3a>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 717>; status = "disabled"; }; @@ -428,6 +448,7 @@ <&dmac1 0x4d>, <&dmac1 0x4e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 716>; status = "disabled"; }; @@ -443,6 +464,7 @@ <&dmac1 0x3b>, <&dmac1 0x3c>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 713>; status = "disabled"; }; @@ -452,6 +474,7 @@ interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 813>; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 813>; phy-mode = "rmii"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/r8a7745.dtsi b/arch/arm/boot/dts/r8a7745.dtsi index 1f65ff68a469..2feb0084bb3b 100644 --- a/arch/arm/boot/dts/r8a7745.dtsi +++ b/arch/arm/boot/dts/r8a7745.dtsi @@ -32,9 +32,8 @@ next-level-cache = <&L2_CA7>; }; - L2_CA7: cache-controller@0 { + L2_CA7: cache-controller-0 { compatible = "cache"; - reg = <0>; cache-unified; cache-level = <2>; power-domains = <&sysc R8A7745_PD_CA7_SCU>; @@ -63,6 +62,7 @@ clocks = <&cpg CPG_MOD 408>; clock-names = "clk"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 408>; }; irqc: interrupt-controller@e61c0000 { @@ -82,6 +82,7 @@ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 407>; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 407>; }; timer { @@ -103,6 +104,7 @@ clock-names = "extal", "usb_extal"; #clock-cells = <2>; #power-domain-cells = <0>; + #reset-cells = <1>; }; prr: chipid@ff000044 { @@ -149,6 +151,7 @@ clocks = <&cpg CPG_MOD 219>; clock-names = "fck"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 219>; #dma-cells = <1>; dma-channels = <15>; }; @@ -181,6 +184,7 @@ clocks = <&cpg CPG_MOD 218>; clock-names = "fck"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 218>; #dma-cells = <1>; dma-channels = <15>; }; @@ -196,6 +200,7 @@ <&dmac1 0x21>, <&dmac1 0x22>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 204>; status = "disabled"; }; @@ -210,6 +215,7 @@ <&dmac1 0x25>, <&dmac1 0x26>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 203>; status = "disabled"; }; @@ -224,6 +230,7 @@ <&dmac1 0x27>, <&dmac1 0x28>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 202>; status = "disabled"; }; @@ -238,6 +245,7 @@ <&dmac1 0x1b>, <&dmac1 0x1c>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 1106>; status = "disabled"; }; @@ -252,6 +260,7 @@ <&dmac1 0x1f>, <&dmac1 0x20>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 1107>; status = "disabled"; }; @@ -266,6 +275,7 @@ <&dmac1 0x23>, <&dmac1 0x24>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 1108>; status = "disabled"; }; @@ -277,9 +287,10 @@ clocks = <&cpg CPG_MOD 206>; clock-names = "fck"; dmas = <&dmac0 0x3d>, <&dmac0 0x3e>, - <&dmac1 0x3d>, <&dmac1 0x3e>; + <&dmac1 0x3d>, <&dmac1 0x3e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 206>; status = "disabled"; }; @@ -294,6 +305,7 @@ <&dmac1 0x19>, <&dmac1 0x1a>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 207>; status = "disabled"; }; @@ -308,6 +320,7 @@ <&dmac1 0x1d>, <&dmac1 0x1e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 216>; status = "disabled"; }; @@ -323,6 +336,7 @@ <&dmac1 0x29>, <&dmac1 0x2a>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 721>; status = "disabled"; }; @@ -338,6 +352,7 @@ <&dmac1 0x2d>, <&dmac1 0x2e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 720>; status = "disabled"; }; @@ -353,6 +368,7 @@ <&dmac1 0x2b>, <&dmac1 0x2c>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 719>; status = "disabled"; }; @@ -368,6 +384,7 @@ <&dmac1 0x2f>, <&dmac1 0x30>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 718>; status = "disabled"; }; @@ -383,6 +400,7 @@ <&dmac1 0xfb>, <&dmac1 0xfc>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 715>; status = "disabled"; }; @@ -398,6 +416,7 @@ <&dmac1 0xfd>, <&dmac1 0xfe>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 714>; status = "disabled"; }; @@ -413,6 +432,7 @@ <&dmac1 0x39>, <&dmac1 0x3a>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 717>; status = "disabled"; }; @@ -428,6 +448,7 @@ <&dmac1 0x4d>, <&dmac1 0x4e>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 716>; status = "disabled"; }; @@ -443,6 +464,7 @@ <&dmac1 0x3b>, <&dmac1 0x3c>; dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 713>; status = "disabled"; }; @@ -452,6 +474,7 @@ interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 813>; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 813>; phy-mode = "rmii"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/r8a7778-bockw.dts b/arch/arm/boot/dts/r8a7778-bockw.dts index 211d239d9041..c79d55eb43c5 100644 --- a/arch/arm/boot/dts/r8a7778-bockw.dts +++ b/arch/arm/boot/dts/r8a7778-bockw.dts @@ -229,5 +229,4 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts index 89c5b24a3d03..9412a86f9b30 100644 --- a/arch/arm/boot/dts/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/r8a7779-marzen.dts @@ -236,7 +236,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &sdhi0 { diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index bd512c86e852..ba100a6f67ca 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -581,7 +581,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &msiof1 { diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 6d10450de6d7..99269aaca6fc 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -129,17 +129,15 @@ next-level-cache = <&L2_CA7>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7790_PD_CA15_SCU>; cache-unified; cache-level = <2>; }; - L2_CA7: cache-controller@100 { + L2_CA7: cache-controller-1 { compatible = "cache"; - reg = <0x100>; power-domains = <&sysc R8A7790_PD_CA7_SCU>; cache-unified; cache-level = <2>; @@ -187,6 +185,9 @@ <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + clocks = <&mstp4_clks R8A7790_CLK_INTC_SYS>; + clock-names = "clk"; + power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; }; gpio0: gpio@e6050000 { @@ -1100,7 +1101,7 @@ }; /* External CAN clock */ - can_clk: can_clk { + can_clk: can { compatible = "fixed-clock"; #clock-cells = <0>; /* This value must be overridden by the board. */ @@ -1366,10 +1367,10 @@ mstp4_clks: mstp4_clks@e6150140 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>; - clocks = <&cp_clk>; + clocks = <&cp_clk>, <&zs_clk>; #clock-cells = <1>; - clock-indices = <R8A7790_CLK_IRQC>; - clock-output-names = "irqc"; + clock-indices = <R8A7790_CLK_IRQC R8A7790_CLK_INTC_SYS>; + clock-output-names = "irqc", "intc-sys"; }; mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; @@ -1442,8 +1443,11 @@ compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, @@ -1740,11 +1744,11 @@ rcar_sound,dvc { dvc0: dvc-0 { - dmas = <&audma0 0xbc>; + dmas = <&audma1 0xbc>; dma-names = "tx"; }; dvc1: dvc-1 { - dmas = <&audma0 0xbe>; + dmas = <&audma1 0xbe>; dma-names = "tx"; }; }; diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index 5405d337d744..001e6116c47c 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -292,7 +292,7 @@ x2_clk: x2-clock { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <148500000>; + clock-frequency = <74250000>; }; x13_clk: x13-clock { @@ -516,7 +516,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &sdhi0 { @@ -767,7 +766,6 @@ &pcie_bus_clk { clock-frequency = <100000000>; - status = "okay"; }; &pciec { diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts index 6761d11d3f9e..95da5cb9d37a 100644 --- a/arch/arm/boot/dts/r8a7791-porter.dts +++ b/arch/arm/boot/dts/r8a7791-porter.dts @@ -226,7 +226,7 @@ phy-handle = <&phy1>; renesas,ether-link-active-low; - status = "ok"; + status = "okay"; phy1: ethernet-phy@1 { reg = <1>; @@ -359,7 +359,7 @@ /* composite video input */ &vin0 { - status = "ok"; + status = "okay"; pinctrl-0 = <&vin0_pins>; pinctrl-names = "default"; @@ -401,7 +401,6 @@ &pcie_bus_clk { clock-frequency = <100000000>; - status = "okay"; }; &pciec { diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 9f9e48511836..4d0c2ce59900 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -74,9 +74,8 @@ next-level-cache = <&L2_CA15>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7791_PD_CA15_SCU>; cache-unified; cache-level = <2>; @@ -118,6 +117,9 @@ <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; + clocks = <&mstp4_clks R8A7791_CLK_INTC_SYS>; + clock-names = "clk"; + power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; }; gpio0: gpio@e6050000 { @@ -1124,7 +1126,7 @@ }; /* External CAN clock */ - can_clk: can_clk { + can_clk: can { compatible = "fixed-clock"; #clock-cells = <0>; /* This value must be overridden by the board. */ @@ -1366,10 +1368,10 @@ mstp4_clks: mstp4_clks@e6150140 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>; - clocks = <&cp_clk>; + clocks = <&cp_clk>, <&zs_clk>; #clock-cells = <1>; - clock-indices = <R8A7791_CLK_IRQC>; - clock-output-names = "irqc"; + clock-indices = <R8A7791_CLK_IRQC R8A7791_CLK_INTC_SYS>; + clock-output-names = "irqc", "intc-sys"; }; mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; @@ -1445,8 +1447,11 @@ compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, @@ -1777,11 +1782,11 @@ rcar_sound,dvc { dvc0: dvc-0 { - dmas = <&audma0 0xbc>; + dmas = <&audma1 0xbc>; dma-names = "tx"; }; dvc1: dvc-1 { - dmas = <&audma0 0xbe>; + dmas = <&audma1 0xbe>; dma-names = "tx"; }; }; diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi index 8ecfda7a004e..0efecb232ee5 100644 --- a/arch/arm/boot/dts/r8a7792.dtsi +++ b/arch/arm/boot/dts/r8a7792.dtsi @@ -46,7 +46,7 @@ compatible = "arm,cortex-a15"; reg = <0>; clock-frequency = <1000000000>; - clocks = <&cpg_clocks R8A7792_CLK_Z>; + clocks = <&z_clk>; power-domains = <&sysc R8A7792_PD_CA15_CPU0>; next-level-cache = <&L2_CA15>; }; @@ -60,9 +60,8 @@ next-level-cache = <&L2_CA15>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; cache-unified; cache-level = <2>; power-domains = <&sysc R8A7792_PD_CA15_SCU>; @@ -93,6 +92,9 @@ <0 0xf1006000 0 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; + clocks = <&mstp4_clks R8A7792_CLK_INTC_SYS>; + clock-names = "clk"; + power-domains = <&sysc R8A7792_PD_ALWAYS_ON>; }; irqc: interrupt-controller@e61c0000 { @@ -764,7 +766,7 @@ clocks = <&extal_clk>; #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", - "lb", "qspi", "z"; + "lb", "qspi"; #power-domain-cells = <0>; }; @@ -776,6 +778,13 @@ clock-div = <2>; clock-mult = <1>; }; + z_clk: z { + compatible = "fixed-factor-clock"; + clocks = <&cpg_clocks R8A7792_CLK_PLL0>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; zx_clk: zx { compatible = "fixed-factor-clock"; clocks = <&cpg_clocks R8A7792_CLK_PLL1>; @@ -896,10 +905,12 @@ compatible = "renesas,r8a7792-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>; - clocks = <&cp_clk>; + clocks = <&cp_clk>, <&zs_clk>; #clock-cells = <1>; - clock-indices = <R8A7792_CLK_IRQC>; - clock-output-names = "irqc"; + clock-indices = < + R8A7792_CLK_IRQC R8A7792_CLK_INTC_SYS + >; + clock-output-names = "irqc", "intc-sys"; }; mstp7_clks: mstp7_clks@e615014c { compatible = "renesas,r8a7792-mstp-clocks", diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts index 92fff07c5e2b..806c93f6ae8b 100644 --- a/arch/arm/boot/dts/r8a7793-gose.dts +++ b/arch/arm/boot/dts/r8a7793-gose.dts @@ -412,7 +412,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &sdhi0 { diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi index 48ce21c5e8db..4de6041d61f9 100644 --- a/arch/arm/boot/dts/r8a7793.dtsi +++ b/arch/arm/boot/dts/r8a7793.dtsi @@ -65,9 +65,8 @@ power-domains = <&sysc R8A7793_PD_CA15_CPU1>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7793_PD_CA15_SCU>; cache-unified; cache-level = <2>; @@ -109,6 +108,9 @@ <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; + clocks = <&mstp4_clks R8A7793_CLK_INTC_SYS>; + clock-names = "clk"; + power-domains = <&sysc R8A7793_PD_ALWAYS_ON>; }; gpio0: gpio@e6050000 { @@ -1179,10 +1181,12 @@ mstp4_clks: mstp4_clks@e6150140 { compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>; - clocks = <&cp_clk>; + clocks = <&cp_clk>, <&zs_clk>; #clock-cells = <1>; - clock-indices = <R8A7793_CLK_IRQC>; - clock-output-names = "irqc"; + clock-indices = < + R8A7793_CLK_IRQC R8A7793_CLK_INTC_SYS + >; + clock-output-names = "irqc", "intc-sys"; }; mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks"; @@ -1265,8 +1269,11 @@ compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, @@ -1426,11 +1433,11 @@ rcar_sound,dvc { dvc0: dvc-0 { - dmas = <&audma0 0xbc>; + dmas = <&audma1 0xbc>; dma-names = "tx"; }; dvc1: dvc-1 { - dmas = <&audma0 0xbe>; + dmas = <&audma1 0xbe>; dma-names = "tx"; }; }; diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts index 569e3f0e97a5..f1eea13cdf44 100644 --- a/arch/arm/boot/dts/r8a7794-alt.dts +++ b/arch/arm/boot/dts/r8a7794-alt.dts @@ -168,7 +168,7 @@ status = "okay"; clocks = <&mstp7_clks R8A7794_CLK_DU0>, - <&mstp7_clks R8A7794_CLK_DU0>, + <&mstp7_clks R8A7794_CLK_DU1>, <&x13_clk>, <&x2_clk>; clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1"; @@ -375,7 +375,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &qspi { diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts index cf880ac06f4b..4cb5278d104d 100644 --- a/arch/arm/boot/dts/r8a7794-silk.dts +++ b/arch/arm/boot/dts/r8a7794-silk.dts @@ -248,7 +248,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; ðer { @@ -425,7 +424,7 @@ status = "okay"; clocks = <&mstp7_clks R8A7794_CLK_DU0>, - <&mstp7_clks R8A7794_CLK_DU0>, + <&mstp7_clks R8A7794_CLK_DU1>, <&x2_clk>, <&x3_clk>; clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1"; diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi index 319c1069b7ee..a19b884fb258 100644 --- a/arch/arm/boot/dts/r8a7794.dtsi +++ b/arch/arm/boot/dts/r8a7794.dtsi @@ -43,6 +43,7 @@ compatible = "arm,cortex-a7"; reg = <0>; clock-frequency = <1000000000>; + clocks = <&z2_clk>; power-domains = <&sysc R8A7794_PD_CA7_CPU0>; next-level-cache = <&L2_CA7>; }; @@ -56,9 +57,8 @@ next-level-cache = <&L2_CA7>; }; - L2_CA7: cache-controller@0 { + L2_CA7: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7794_PD_CA7_SCU>; cache-unified; cache-level = <2>; @@ -75,6 +75,9 @@ <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; + clocks = <&mstp4_clks R8A7794_CLK_INTC_SYS>; + clock-names = "clk"; + power-domains = <&sysc R8A7794_PD_ALWAYS_ON>; }; gpio0: gpio@e6050000 { @@ -923,7 +926,7 @@ interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp7_clks R8A7794_CLK_DU0>, - <&mstp7_clks R8A7794_CLK_DU0>; + <&mstp7_clks R8A7794_CLK_DU1>; clock-names = "du.0", "du.1"; status = "disabled"; @@ -1062,6 +1065,13 @@ clock-div = <2>; clock-mult = <1>; }; + z2_clk: z2 { + compatible = "fixed-factor-clock"; + clocks = <&cpg_clocks R8A7794_CLK_PLL0>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; zg_clk: zg { compatible = "fixed-factor-clock"; clocks = <&cpg_clocks R8A7794_CLK_PLL1>; @@ -1248,10 +1258,10 @@ mstp4_clks: mstp4_clks@e6150140 { compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>; - clocks = <&cp_clk>; + clocks = <&cp_clk>, <&zs_clk>; #clock-cells = <1>; - clock-indices = <R8A7794_CLK_IRQC>; - clock-output-names = "irqc"; + clock-indices = <R8A7794_CLK_IRQC R8A7794_CLK_INTC_SYS>; + clock-output-names = "irqc", "intc-sys"; }; mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks"; @@ -1268,19 +1278,21 @@ clocks = <&mp_clk>, <&hp_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&zx_clk>; + <&zx_clk>, <&zx_clk>; #clock-cells = <1>; clock-indices = < R8A7794_CLK_EHCI R8A7794_CLK_HSUSB R8A7794_CLK_HSCIF2 R8A7794_CLK_SCIF5 R8A7794_CLK_SCIF4 R8A7794_CLK_HSCIF1 R8A7794_CLK_HSCIF0 R8A7794_CLK_SCIF3 R8A7794_CLK_SCIF2 R8A7794_CLK_SCIF1 - R8A7794_CLK_SCIF0 R8A7794_CLK_DU0 + R8A7794_CLK_SCIF0 + R8A7794_CLK_DU1 R8A7794_CLK_DU0 >; clock-output-names = "ehci", "hsusb", "hscif2", "scif5", "scif4", "hscif1", "hscif0", - "scif3", "scif2", "scif1", "scif0", "du0"; + "scif3", "scif2", "scif1", "scif0", + "du1", "du0"; }; mstp8_clks: mstp8_clks@e6150990 { compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks"; diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index ff9b90bfaefd..ec91325d3b6e 100644 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -250,6 +250,8 @@ clock-names = "biu", "ciu"; fifo-depth = <0x100>; interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; + resets = <&cru SRST_MMC0>; + reset-names = "reset"; status = "disabled"; }; @@ -262,6 +264,8 @@ clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + resets = <&cru SRST_SDIO>; + reset-names = "reset"; status = "disabled"; }; @@ -286,6 +290,8 @@ num-slots = <1>; pinctrl-names = "default"; pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + resets = <&cru SRST_EMMC>; + reset-names = "reset"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index 1aff4ad22fc4..1399bc04ea77 100644 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -545,12 +545,12 @@ }; &global_timer { - interrupts = <GIC_PPI 11 0xf04>; + interrupts = <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>; status = "disabled"; }; &local_timer { - interrupts = <GIC_PPI 13 0xf04>; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>; }; &i2c0 { diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi index 641607d9ad29..48a0c1cf4301 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi @@ -414,6 +414,8 @@ fifo-depth = <0x100>; pinctrl-names = "default"; pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + resets = <&cru SRST_EMMC>; + reset-names = "reset"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts index 21326f3e8564..30e93f694ae8 100644 --- a/arch/arm/boot/dts/rk3288-miqi.dts +++ b/arch/arm/boot/dts/rk3288-miqi.dts @@ -68,11 +68,9 @@ compatible = "gpio-leds"; work { - gpios = <&gpio7 RK_PA4 GPIO_ACTIVE_LOW>; + gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>; label = "miqi:green:user"; - linux,default-trigger = "default-on"; - pinctrl-names = "default"; - pinctrl-0 = <&led_ctl>; + linux,default-trigger = "timer"; }; }; @@ -363,12 +361,6 @@ }; }; - leds { - led_ctl: led-ctl { - rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - sdmmc { /* * Default drive strength isn't enough to achieve even diff --git a/arch/arm/boot/dts/rk3288-phycore-rdk.dts b/arch/arm/boot/dts/rk3288-phycore-rdk.dts new file mode 100644 index 000000000000..3dda79579b51 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-phycore-rdk.dts @@ -0,0 +1,298 @@ +/* + * Device tree file for Phytec PCM-947 carrier board + * Copyright (C) 2017 PHYTEC Messtechnik GmbH + * Author: Wadim Egorov <w.egorov@phytec.de> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include <dt-bindings/input/input.h> +#include <dt-bindings/leds/leds-pca9532.h> +#include "rk3288-phycore-som.dtsi" + +/ { + model = "Phytec RK3288 PCM-947"; + compatible = "phytec,rk3288-pcm-947", "phytec,rk3288-phycore-som", "rockchip,rk3288"; + + user_buttons: user-buttons { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&user_button_pins>; + + button@0 { + label = "home"; + linux,code = <KEY_HOME>; + gpios = <&gpio8 0 GPIO_ACTIVE_HIGH>; + wakeup-source; + }; + + button@1 { + label = "menu"; + linux,code = <KEY_MENU>; + gpios = <&gpio8 3 GPIO_ACTIVE_HIGH>; + wakeup-source; + }; + }; + + vcc_host0_5v: usb-host0-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&host0_vbus_drv>; + regulator-name = "vcc_host0_5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + vin-supply = <&vdd_in_otg_out>; + }; + + vcc_host1_5v: usb-host1-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio2 0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&host1_vbus_drv>; + regulator-name = "vcc_host1_5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + vin-supply = <&vdd_in_otg_out>; + }; + + vcc_otg_5v: usb-otg-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&otg_vbus_drv>; + regulator-name = "vcc_otg_5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + vin-supply = <&vdd_in_otg_out>; + }; +}; + +&gmac { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + touchscreen@44 { + compatible = "st,stmpe811"; + reg = <0x44>; + }; + + adc@64 { + compatible = "maxim,max1037"; + reg = <0x64>; + }; + + i2c_rtc: rtc@68 { + compatible = "rv4162"; + reg = <0x68>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_rtc_int>; + interrupt-parent = <&gpio5>; + interrupts = <10 0>; + }; +}; + +&i2c3 { + status = "okay"; + + i2c_eeprom_cb: eeprom@51 { + compatible = "atmel,24c32"; + reg = <0x51>; + pagesize = <32>; + }; +}; + +&i2c4 { + status = "okay"; + + /* PCA9533 - 4-bit LED dimmer */ + leddim: leddimmer@62 { + compatible = "nxp,pca9533"; + reg = <0x62>; + + led1 { + label = "red:user1"; + linux,default-trigger = "none"; + type = <PCA9532_TYPE_LED>; + }; + + led2 { + label = "green:user2"; + linux,default-trigger = "none"; + type = <PCA9532_TYPE_LED>; + }; + + led3 { + label = "blue:user3"; + linux,default-trigger = "none"; + type = <PCA9532_TYPE_LED>; + }; + + led4 { + label = "red:user4"; + linux,default-trigger = "none"; + type = <PCA9532_TYPE_LED>; + }; + }; +}; + +&i2c5 { + status = "okay"; +}; + +&pinctrl { + pcfg_pull_up_drv_12ma: pcfg-pull-up-drv-12ma { + bias-pull-up; + drive-strength = <12>; + }; + + buttons { + user_button_pins: user-button-pins { + /* button 1 */ + rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_pull_up>, + /* button 2 */ + <8 0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + rv4162 { + i2c_rtc_int: i2c-rtc-int { + rockchip,pins = <5 10 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdmmc { + /* + * Default drive strength isn't enough to achieve even + * high-speed mode on pcm-947 board so bump up to 12 mA. + */ + sdmmc_bus4: sdmmc-bus4 { + rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_12ma>, + <6 17 RK_FUNC_1 &pcfg_pull_up_drv_12ma>, + <6 18 RK_FUNC_1 &pcfg_pull_up_drv_12ma>, + <6 19 RK_FUNC_1 &pcfg_pull_up_drv_12ma>; + }; + + sdmmc_clk: sdmmc-clk { + rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_12ma>; + }; + + sdmmc_cmd: sdmmc-cmd { + rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_12ma>; + }; + + sdmmc_pwr: sdmmc-pwr { + rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + touchscreen { + ts_irq_pin: ts-irq-pin { + rockchip,pins = <5 15 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb_host { + host0_vbus_drv: host0-vbus-drv { + rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + host1_vbus_drv: host1-vbus-drv { + rockchip,pins = <2 0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb_otg { + otg_vbus_drv: otg-vbus-drv { + rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <200>; + disable-wp; + num-slots = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; + vmmc-supply = <&vdd_io_sd>; + vqmmc-supply = <&vdd_io_sd>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host1 { + status = "okay"; +}; + +&usb_otg { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rk3288-phycore-som.dtsi b/arch/arm/boot/dts/rk3288-phycore-som.dtsi new file mode 100644 index 000000000000..26cd3ad45160 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-phycore-som.dtsi @@ -0,0 +1,497 @@ +/* + * Device tree file for Phytec phyCORE-RK3288 SoM + * Copyright (C) 2017 PHYTEC Messtechnik GmbH + * Author: Wadim Egorov <w.egorov@phytec.de> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/net/ti-dp83867.h> +#include "rk3288.dtsi" + +/ { + model = "Phytec RK3288 phyCORE"; + compatible = "phytec,rk3288-phycore-som", "rockchip,rk3288"; + + /* + * Set the minimum memory size here and + * let the bootloader set the real size. + */ + memory { + device_type = "memory"; + reg = <0 0x8000000>; + }; + + aliases { + rtc0 = &i2c_rtc; + rtc1 = &rk818; + }; + + ext_gmac: external-gmac-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + clock-output-names = "ext_gmac"; + }; + + leds: user-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&user_led>; + + user { + label = "green_led"; + gpios = <&gpio7 2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "keep"; + }; + }; + + vdd_emmc_io: vdd-emmc-io { + compatible = "regulator-fixed"; + regulator-name = "vdd_emmc_io"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vdd_3v3_io>; + }; + + vdd_in_otg_out: vdd-in-otg-out { + compatible = "regulator-fixed"; + regulator-name = "vdd_in_otg_out"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vdd_misc_1v8: vdd-misc-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vdd_misc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; +}; + +&cpu0 { + cpu0-supply = <&vdd_cpu>; + operating-points = < + /* KHz uV */ + 1800000 1400000 + 1608000 1350000 + 1512000 1300000 + 1416000 1200000 + 1200000 1100000 + 1008000 1050000 + 816000 1000000 + 696000 950000 + 600000 900000 + 408000 900000 + 312000 900000 + 216000 900000 + 126000 900000 + >; +}; + +&emmc { + status = "okay"; + bus-width = <8>; + cap-mmc-highspeed; + disable-wp; + non-removable; + num-slots = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>; + vmmc-supply = <&vdd_3v3_io>; + vqmmc-supply = <&vdd_emmc_io>; +}; + +&gmac { + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + clock_in_out = "input"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins &phy_rst &phy_int>; + phy-handle = <&phy0>; + phy-supply = <&vdd_eth_2v5>; + phy-mode = "rgmii-id"; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_HIGH>; + tx_delay = <0x0>; + rx_delay = <0x0>; + + mdio0 { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + interrupt-parent = <&gpio4>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; + ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; + enet-phy-lane-no-swap; + }; + }; +}; + +&hdmi { + ddc-i2c-bus = <&i2c5>; +}; + +&io_domains { + status = "okay"; + sdcard-supply = <&vdd_io_sd>; + flash0-supply = <&vdd_emmc_io>; + flash1-supply = <&vdd_misc_1v8>; + gpio1830-supply = <&vdd_3v3_io>; + gpio30-supply = <&vdd_3v3_io>; + bb-supply = <&vdd_3v3_io>; + dvp-supply = <&vdd_3v3_io>; + lcdc-supply = <&vdd_3v3_io>; + wifi-supply = <&vdd_3v3_io>; + audio-supply = <&vdd_3v3_io>; +}; + +&i2c0 { + status = "okay"; + clock-frequency = <400000>; + + rk818: pmic@1c { + compatible = "rockchip,rk818"; + reg = <0x1c>; + interrupt-parent = <&gpio0>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int>; + rockchip,system-power-controller; + wakeup-source; + #clock-cells = <1>; + + vcc1-supply = <&vdd_sys>; + vcc2-supply = <&vdd_sys>; + vcc3-supply = <&vdd_sys>; + vcc4-supply = <&vdd_sys>; + boost-supply = <&vdd_in_otg_out>; + vcc6-supply = <&vdd_sys>; + vcc7-supply = <&vdd_misc_1v8>; + vcc8-supply = <&vdd_misc_1v8>; + vcc9-supply = <&vdd_3v3_io>; + vddio-supply = <&vdd_3v3_io>; + + regulators { + vdd_log: DCDC_REG1 { + regulator-name = "vdd_log"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_gpu: DCDC_REG2 { + regulator-name = "vdd_gpu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1250000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vdd_3v3_io: DCDC_REG4 { + regulator-name = "vdd_3v3_io"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vdd_sys: DCDC_BOOST { + regulator-name = "vdd_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <5000000>; + }; + }; + + /* vcc9 */ + vdd_sd: SWITCH_REG { + regulator-name = "vdd_sd"; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + /* vcc6 */ + vdd_eth_2v5: LDO_REG2 { + regulator-name = "vdd_eth_2v5"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2500000>; + }; + }; + + /* vcc7 */ + vdd_1v0: LDO_REG3 { + regulator-name = "vdd_1v0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + /* vcc8 */ + vdd_1v8_lcd_ldo: LDO_REG4 { + regulator-name = "vdd_1v8_lcd_ldo"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + /* vcc8 */ + vdd_1v0_lcd: LDO_REG6 { + regulator-name = "vdd_1v0_lcd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + /* vcc7 */ + vdd_1v8_ldo: LDO_REG7 { + regulator-name = "vdd_1v8_ldo"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + /* vcc9 */ + vdd_io_sd: LDO_REG9 { + regulator-name = "vdd_io_sd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + }; + }; + + /* M24C32-D */ + i2c_eeprom: eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + pagesize = <32>; + }; + + vdd_cpu: regulator@60 { + compatible = "fcs,fan53555"; + reg = <0x60>; + fcs,suspend-voltage-selector = <1>; + regulator-always-on; + regulator-boot-on; + regulator-enable-ramp-delay = <300>; + regulator-name = "vdd_cpu"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1430000>; + regulator-ramp-delay = <8000>; + vin-supply = <&vdd_sys>; + }; +}; + +&pinctrl { + pcfg_output_high: pcfg-output-high { + output-high; + }; + + emmc { + /* + * We run eMMC at max speed; bump up drive strength. + * We also have external pulls, so disable the internal ones. + */ + emmc_clk: emmc-clk { + rockchip,pins = <3 18 RK_FUNC_2 &pcfg_pull_none_12ma>; + }; + + emmc_cmd: emmc-cmd { + rockchip,pins = <3 16 RK_FUNC_2 &pcfg_pull_none_12ma>; + }; + + emmc_bus8: emmc-bus8 { + rockchip,pins = <3 0 RK_FUNC_2 &pcfg_pull_none_12ma>, + <3 1 RK_FUNC_2 &pcfg_pull_none_12ma>, + <3 2 RK_FUNC_2 &pcfg_pull_none_12ma>, + <3 3 RK_FUNC_2 &pcfg_pull_none_12ma>, + <3 4 RK_FUNC_2 &pcfg_pull_none_12ma>, + <3 5 RK_FUNC_2 &pcfg_pull_none_12ma>, + <3 6 RK_FUNC_2 &pcfg_pull_none_12ma>, + <3 7 RK_FUNC_2 &pcfg_pull_none_12ma>; + }; + }; + + gmac { + phy_int: phy-int { + rockchip,pins = <4 2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + phy_rst: phy-rst { + rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>; + }; + }; + + leds { + user_led: user-led { + rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_output_high>; + }; + }; + + pmic { + pmic_int: pmic-int { + rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + /* Pin for switching state between sleep and non-sleep state */ + pmic_sleep: pmic-sleep { + rockchip,pins = <RK_GPIO0 0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vdd_1v8_ldo>; +}; + +&spi2 { + status = "okay"; + + serial_flash: flash@0 { + compatible = "micron,n25q128a13", "jedec,spi-nor"; + reg = <0x0>; + spi-max-frequency = <50000000>; + m25p,fast-read; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + }; +}; + +&tsadc { + status = "okay"; + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; +}; + +&vopb { + status = "okay"; +}; + +&vopb_mmu { + status = "okay"; +}; + +&vopl { + status = "okay"; +}; + +&vopl_mmu { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rk3288-rock2-som.dtsi b/arch/arm/boot/dts/rk3288-rock2-som.dtsi index 1c0bbc9b928b..f0778a46bca9 100644 --- a/arch/arm/boot/dts/rk3288-rock2-som.dtsi +++ b/arch/arm/boot/dts/rk3288-rock2-som.dtsi @@ -136,7 +136,7 @@ regulator-always-on; }; - vcc_io: REG2 { + vcc_io: vccio_codec: REG2 { regulator-name = "VCC_IO"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/rk3288-rock2-square.dts b/arch/arm/boot/dts/rk3288-rock2-square.dts index 96a2e745bb93..a23a94811be8 100644 --- a/arch/arm/boot/dts/rk3288-rock2-square.dts +++ b/arch/arm/boot/dts/rk3288-rock2-square.dts @@ -81,11 +81,35 @@ }; }; + sata_pwr: sata-prw-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 13 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sata_pwr_en>; + /* Always turn on the 5V sata power connector */ + regulator-always-on; + regulator-name = "sata_pwr"; + }; + spdif_out: spdif-out { compatible = "linux,spdif-dit"; #sound-dai-cells = <0>; }; + sound-i2s { + compatible = "rockchip,rk3288-hdmi-analog"; + pinctrl-names = "default"; + pinctrl-0 = <&phone_ctl>, <&hp_det>; + rockchip,audio-codec = <&es8388>; + rockchip,hp-det-gpios = <&gpio7 7 GPIO_ACTIVE_HIGH>; + rockchip,hp-en-gpios = <&gpio8 0 GPIO_ACTIVE_HIGH>; + rockchip,i2s-controller = <&i2s>; + rockchip,model = "I2S"; + rockchip,routing = "Analog", "LOUT2", + "Analog", "ROUT2"; + }; + sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; clocks = <&hym8563>; @@ -173,10 +197,28 @@ }; }; +&i2c2 { + status = "okay"; + + es8388: es8388@10 { + compatible = "everest,es8388", "everest,es8328"; + reg = <0x10>; + AVDD-supply = <&vccio_codec>; + DVDD-supply = <&vccio_codec>; + HPVDD-supply = <&vccio_codec>; + PVDD-supply = <&vccio_codec>; + clocks = <&cru SCLK_I2S0_OUT>; + }; +}; + &i2c5 { status = "okay"; }; +&i2s { + status = "okay"; +}; + &pinctrl { ir { ir_int: ir-int { @@ -190,12 +232,28 @@ }; }; + headphone { + hp_det: hp-det { + rockchip,pins = <7 7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + phone_ctl: phone-ctl { + rockchip,pins = <8 0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + usb { host_vbus_drv: host-vbus-drv { rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>; }; }; + sata { + sata_pwr_en: sata-pwr-en { + rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + sdmmc { sdmmc_pwr: sdmmc-pwr { rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>; @@ -224,3 +282,7 @@ &usb_host0_ehci { status = "okay"; }; + +&usb_host1 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts new file mode 100644 index 000000000000..f601c78386a9 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-tinker.dts @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "rk3288.dtsi" +#include <dt-bindings/input/input.h> + +/ { + model = "Rockchip RK3288 Tinker Board"; + compatible = "asus,rk3288-tinker", "rockchip,rk3288"; + + memory { + reg = <0x0 0x80000000>; + device_type = "memory"; + }; + + ext_gmac: external-gmac-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + clock-output-names = "ext_gmac"; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + autorepeat; + + pinctrl-names = "default"; + pinctrl-0 = <&pwrbtn>; + + button@0 { + gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>; + linux,code = <KEY_POWER>; + label = "GPIO Key Power"; + linux,input-type = <1>; + wakeup-source; + debounce-interval = <100>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + act-led { + gpios=<&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; + linux,default-trigger="mmc0"; + }; + + heartbeat-led { + gpios=<&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>; + linux,default-trigger="heartbeat"; + }; + + pwr-led { + gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "rockchip,tinker-codec"; + simple-audio-card,mclk-fs = <512>; + + simple-audio-card,codec { + sound-dai = <&hdmi>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s>; + }; + }; + + vcc_sys: vsys-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_pwr>; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; +}; + +&cpu0 { + cpu0-supply = <&vdd_cpu>; +}; + +&gmac { + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + clock_in_out = "input"; + phy-mode = "rgmii"; + phy-supply = <&vcc33_lan>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>; + snps,reset-gpio = <&gpio4 7 0>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 1000000>; + tx_delay = <0x30>; + rx_delay = <0x10>; + status = "ok"; +}; + +&hdmi { + ddc-i2c-bus = <&i2c5>; + status = "okay"; +}; + +&i2c0 { + clock-frequency = <400000>; + status = "okay"; + + rk808: pmic@1b { + compatible = "rockchip,rk808"; + reg = <0x1b>; + interrupt-parent = <&gpio0>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + #clock-cells = <1>; + clock-output-names = "xin32k", "rk808-clkout2"; + dvs-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>, + <&gpio0 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int &global_pwroff &dvs_1 &dvs_2>; + rockchip,system-power-controller; + wakeup-source; + + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_io>; + vcc9-supply = <&vcc_io>; + vcc10-supply = <&vcc_io>; + vcc11-supply = <&vcc_sys>; + vcc12-supply = <&vcc_io>; + vddio-supply = <&vcc_io>; + + regulators { + vdd_cpu: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1350000>; + regulator-name = "vdd_arm"; + regulator-ramp-delay = <6000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_gpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1250000>; + regulator-name = "vdd_gpu"; + regulator-ramp-delay = <6000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_ddr"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_io: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_io"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc18_ldo1: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc18_ldo1"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc33_mipi: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc33_mipi"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_10: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd_10"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vcc18_codec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc18_codec"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vccio_sd: LDO_REG5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vdd10_lcd: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd10_lcd"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vcc_18: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_18"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc18_lcd: LDO_REG8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc18_lcd"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc33_sd: SWITCH_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc33_sd"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc33_lan: SWITCH_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc33_lan"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + }; + }; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2s { + #sound-dai-cells = <0>; + status = "okay"; +}; + +&io_domains { + status = "okay"; + + sdcard-supply = <&vccio_sd>; +}; + +&pinctrl { + pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma { + drive-strength = <8>; + }; + + pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma { + bias-pull-up; + drive-strength = <8>; + }; + + backlight { + bl_en: bl-en { + rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + buttons { + pwrbtn: pwrbtn { + rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + eth_phy { + eth_phy_pwr: eth-phy-pwr { + rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int: pmic-int { + rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO \ + &pcfg_pull_up>; + }; + + dvs_1: dvs-1 { + rockchip,pins = <RK_GPIO0 11 RK_FUNC_GPIO \ + &pcfg_pull_down>; + }; + + dvs_2: dvs-2 { + rockchip,pins = <RK_GPIO0 12 RK_FUNC_GPIO \ + &pcfg_pull_down>; + }; + }; + + sdmmc { + sdmmc_bus4: sdmmc-bus4 { + rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_8ma>, + <6 17 RK_FUNC_1 &pcfg_pull_up_drv_8ma>, + <6 18 RK_FUNC_1 &pcfg_pull_up_drv_8ma>, + <6 19 RK_FUNC_1 &pcfg_pull_up_drv_8ma>; + }; + + sdmmc_clk: sdmmc-clk { + rockchip,pins = <6 20 RK_FUNC_1 \ + &pcfg_pull_none_drv_8ma>; + }; + + sdmmc_cmd: sdmmc-cmd { + rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_8ma>; + }; + + sdmmc_pwr: sdmmc-pwr { + rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + host_vbus_drv: host-vbus-drv { + rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pwr_3g: pwr-3g { + rockchip,pins = <7 8 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm0 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc18_ldo1>; + status ="okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <200>; + disable-wp; /* wp not hooked up */ + num-slots = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; + status = "okay"; + vmmc-supply = <&vcc33_sd>; + vqmmc-supply = <&vccio_sd>; +}; + +&tsadc { + rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */ + rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */ + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&uart4 { + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host1 { + status = "okay"; +}; + +&usb_otg { + status= "okay"; +}; + +&vopb { + status = "okay"; +}; + +&vopb_mmu { + status = "okay"; +}; + +&vopl { + status = "okay"; +}; + +&vopl_mmu { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index df8a0dbe9d91..ad5d6022e95f 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -236,6 +236,8 @@ fifo-depth = <0x100>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0c0000 0x4000>; + resets = <&cru SRST_MMC0>; + reset-names = "reset"; status = "disabled"; }; @@ -248,6 +250,8 @@ fifo-depth = <0x100>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0d0000 0x4000>; + resets = <&cru SRST_SDIO0>; + reset-names = "reset"; status = "disabled"; }; @@ -260,6 +264,8 @@ fifo-depth = <0x100>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0e0000 0x4000>; + resets = <&cru SRST_SDIO1>; + reset-names = "reset"; status = "disabled"; }; @@ -272,6 +278,8 @@ fifo-depth = <0x100>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0f0000 0x4000>; + resets = <&cru SRST_EMMC>; + reset-names = "reset"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi index 0b45811cf28b..4aa6f60d6a22 100644 --- a/arch/arm/boot/dts/rk3xxx.dtsi +++ b/arch/arm/boot/dts/rk3xxx.dtsi @@ -132,14 +132,14 @@ global_timer: global-timer@1013c200 { compatible = "arm,cortex-a9-global-timer"; reg = <0x1013c200 0x20>; - interrupts = <GIC_PPI 11 0x304>; + interrupts = <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>; clocks = <&cru CORE_PERI>; }; local_timer: local-timer@1013c600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0x1013c600 0x20>; - interrupts = <GIC_PPI 13 0x304>; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>; clocks = <&cru CORE_PERI>; }; @@ -223,7 +223,11 @@ interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; clock-names = "biu", "ciu"; + dmas = <&dmac2 1>; + dma-names = "rx-tx"; fifo-depth = <256>; + resets = <&cru SRST_SDMMC>; + reset-names = "reset"; status = "disabled"; }; @@ -233,7 +237,11 @@ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>; clock-names = "biu", "ciu"; + dmas = <&dmac2 3>; + dma-names = "rx-tx"; fifo-depth = <256>; + resets = <&cru SRST_SDIO>; + reset-names = "reset"; status = "disabled"; }; @@ -243,7 +251,11 @@ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>; clock-names = "biu", "ciu"; + dmas = <&dmac2 4>; + dma-names = "rx-tx"; fifo-depth = <256>; + resets = <&cru SRST_EMMC>; + reset-names = "reset"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/s3c64xx.dtsi b/arch/arm/boot/dts/s3c64xx.dtsi index 0ccb414cd268..c55cbb3af2c0 100644 --- a/arch/arm/boot/dts/s3c64xx.dtsi +++ b/arch/arm/boot/dts/s3c64xx.dtsi @@ -94,13 +94,12 @@ }; watchdog: watchdog@7e004000 { - compatible = "samsung,s3c2410-wdt"; + compatible = "samsung,s3c6410-wdt"; reg = <0x7e004000 0x1000>; interrupt-parent = <&vic0>; interrupts = <26>; clock-names = "watchdog"; clocks = <&clocks PCLK_WDT>; - status = "disabled"; }; i2c0: i2c@7f004000 { diff --git a/arch/arm/boot/dts/s5pv210.dtsi b/arch/arm/boot/dts/s5pv210.dtsi index a853918be43f..726c5d0dbd5b 100644 --- a/arch/arm/boot/dts/s5pv210.dtsi +++ b/arch/arm/boot/dts/s5pv210.dtsi @@ -310,7 +310,7 @@ }; watchdog: watchdog@e2700000 { - compatible = "samsung,s3c2410-wdt"; + compatible = "samsung,s3c6410-wdt"; reg = <0xe2700000 0x1000>; interrupt-parent = <&vic0>; interrupts = <26>; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 528b4e9c6d3d..8067c71c3a38 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1305,6 +1305,11 @@ status = "okay"; }; + sfrbu: sfr@fc05c000 { + compatible = "atmel,sama5d2-sfrbu", "syscon"; + reg = <0xfc05c000 0x20>; + }; + chipid@fc069000 { compatible = "atmel,sama5d2-chipid"; reg = <0xfc069000 0x8>; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 2c43c4d85dee..b2674bdb8e6a 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -15,7 +15,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "skeleton.dtsi" #include <dt-bindings/reset/altr,rst-mgr.h> / { @@ -38,13 +37,13 @@ #size-cells = <0>; enable-method = "altr,socfpga-smp"; - cpu@0 { + cpu0: cpu@0 { compatible = "arm,cortex-a9"; device_type = "cpu"; reg = <0>; next-level-cache = <&L2>; }; - cpu@1 { + cpu1: cpu@1 { compatible = "arm,cortex-a9"; device_type = "cpu"; reg = <1>; @@ -52,6 +51,15 @@ }; }; + pmu: pmu@ff111000 { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&intc>; + interrupts = <0 176 4>, <0 177 4>; + interrupt-affinity = <&cpu0>, <&cpu1>; + reg = <0xff111000 0x1000>, + <0xff113000 0x1000>; + }; + intc: intc@fffed000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; @@ -145,7 +153,7 @@ compatible = "fixed-clock"; }; - main_pll: main_pll { + main_pll: main_pll@40 { #address-cells = <1>; #size-cells = <0>; #clock-cells = <0>; @@ -153,7 +161,7 @@ clocks = <&osc1>; reg = <0x40>; - mpuclk: mpuclk { + mpuclk: mpuclk@48 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&main_pll>; @@ -161,7 +169,7 @@ reg = <0x48>; }; - mainclk: mainclk { + mainclk: mainclk@4c { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&main_pll>; @@ -169,7 +177,7 @@ reg = <0x4C>; }; - dbg_base_clk: dbg_base_clk { + dbg_base_clk: dbg_base_clk@50 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&main_pll>, <&osc1>; @@ -177,21 +185,21 @@ reg = <0x50>; }; - main_qspi_clk: main_qspi_clk { + main_qspi_clk: main_qspi_clk@54 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&main_pll>; reg = <0x54>; }; - main_nand_sdmmc_clk: main_nand_sdmmc_clk { + main_nand_sdmmc_clk: main_nand_sdmmc_clk@58 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&main_pll>; reg = <0x58>; }; - cfg_h2f_usr0_clk: cfg_h2f_usr0_clk { + cfg_h2f_usr0_clk: cfg_h2f_usr0_clk@5c { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&main_pll>; @@ -199,7 +207,7 @@ }; }; - periph_pll: periph_pll { + periph_pll: periph_pll@80 { #address-cells = <1>; #size-cells = <0>; #clock-cells = <0>; @@ -207,42 +215,42 @@ clocks = <&osc1>, <&osc2>, <&f2s_periph_ref_clk>; reg = <0x80>; - emac0_clk: emac0_clk { + emac0_clk: emac0_clk@88 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&periph_pll>; reg = <0x88>; }; - emac1_clk: emac1_clk { + emac1_clk: emac1_clk@8c { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&periph_pll>; reg = <0x8C>; }; - per_qspi_clk: per_qsi_clk { + per_qspi_clk: per_qsi_clk@90 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&periph_pll>; reg = <0x90>; }; - per_nand_mmc_clk: per_nand_mmc_clk { + per_nand_mmc_clk: per_nand_mmc_clk@94 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&periph_pll>; reg = <0x94>; }; - per_base_clk: per_base_clk { + per_base_clk: per_base_clk@98 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&periph_pll>; reg = <0x98>; }; - h2f_usr1_clk: h2f_usr1_clk { + h2f_usr1_clk: h2f_usr1_clk@9c { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&periph_pll>; @@ -250,7 +258,7 @@ }; }; - sdram_pll: sdram_pll { + sdram_pll: sdram_pll@c0 { #address-cells = <1>; #size-cells = <0>; #clock-cells = <0>; @@ -258,28 +266,28 @@ clocks = <&osc1>, <&osc2>, <&f2s_sdram_ref_clk>; reg = <0xC0>; - ddr_dqs_clk: ddr_dqs_clk { + ddr_dqs_clk: ddr_dqs_clk@c8 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&sdram_pll>; reg = <0xC8>; }; - ddr_2x_dqs_clk: ddr_2x_dqs_clk { + ddr_2x_dqs_clk: ddr_2x_dqs_clk@cc { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&sdram_pll>; reg = <0xCC>; }; - ddr_dq_clk: ddr_dq_clk { + ddr_dq_clk: ddr_dq_clk@d0 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&sdram_pll>; reg = <0xD0>; }; - h2f_usr2_clk: h2f_usr2_clk { + h2f_usr2_clk: h2f_usr2_clk@d4 { #clock-cells = <0>; compatible = "altr,socfpga-perip-clk"; clocks = <&sdram_pll>; @@ -678,7 +686,7 @@ status = "disabled"; }; - eccmgr: eccmgr@ffd08140 { + eccmgr: eccmgr { compatible = "altr,socfpga-ecc-manager"; #address-cells = <1>; #size-cells = <1>; @@ -879,7 +887,7 @@ dma-names = "tx", "rx"; }; - usbphy0: usbphy@0 { + usbphy0: usbphy { #phy-cells = <0>; compatible = "usb-nop-xceiv"; status = "okay"; diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi index 6b0b7463f36f..bead79e4b2aa 100644 --- a/arch/arm/boot/dts/socfpga_arria10.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10.dtsi @@ -14,7 +14,6 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "skeleton.dtsi" #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/reset/altr,rst-mgr-a10.h> @@ -119,7 +118,7 @@ compatible = "fixed-clock"; }; - main_pll: main_pll { + main_pll: main_pll@40 { #address-cells = <1>; #size-cells = <0>; #clock-cells = <0>; @@ -142,35 +141,35 @@ div-reg = <0x144 0 11>; }; - main_emaca_clk: main_emaca_clk { + main_emaca_clk: main_emaca_clk@68 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; reg = <0x68>; }; - main_emacb_clk: main_emacb_clk { + main_emacb_clk: main_emacb_clk@6c { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; reg = <0x6C>; }; - main_emac_ptp_clk: main_emac_ptp_clk { + main_emac_ptp_clk: main_emac_ptp_clk@70 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; reg = <0x70>; }; - main_gpio_db_clk: main_gpio_db_clk { + main_gpio_db_clk: main_gpio_db_clk@74 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; reg = <0x74>; }; - main_sdmmc_clk: main_sdmmc_clk { + main_sdmmc_clk: main_sdmmc_clk@78 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk" ; @@ -178,28 +177,28 @@ reg = <0x78>; }; - main_s2f_usr0_clk: main_s2f_usr0_clk { + main_s2f_usr0_clk: main_s2f_usr0_clk@7c { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; reg = <0x7C>; }; - main_s2f_usr1_clk: main_s2f_usr1_clk { + main_s2f_usr1_clk: main_s2f_usr1_clk@80 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; reg = <0x80>; }; - main_hmc_pll_ref_clk: main_hmc_pll_ref_clk { + main_hmc_pll_ref_clk: main_hmc_pll_ref_clk@84 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; reg = <0x84>; }; - main_periph_ref_clk: main_periph_ref_clk { + main_periph_ref_clk: main_periph_ref_clk@9c { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; @@ -207,7 +206,7 @@ }; }; - periph_pll: periph_pll { + periph_pll: periph_pll@c0 { #address-cells = <1>; #size-cells = <0>; #clock-cells = <0>; @@ -230,56 +229,56 @@ div-reg = <0x144 16 11>; }; - peri_emaca_clk: peri_emaca_clk { + peri_emaca_clk: peri_emaca_clk@e8 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; reg = <0xE8>; }; - peri_emacb_clk: peri_emacb_clk { + peri_emacb_clk: peri_emacb_clk@ec { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; reg = <0xEC>; }; - peri_emac_ptp_clk: peri_emac_ptp_clk { + peri_emac_ptp_clk: peri_emac_ptp_clk@f0 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; reg = <0xF0>; }; - peri_gpio_db_clk: peri_gpio_db_clk { + peri_gpio_db_clk: peri_gpio_db_clk@f4 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; reg = <0xF4>; }; - peri_sdmmc_clk: peri_sdmmc_clk { + peri_sdmmc_clk: peri_sdmmc_clk@f8 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; reg = <0xF8>; }; - peri_s2f_usr0_clk: peri_s2f_usr0_clk { + peri_s2f_usr0_clk: peri_s2f_usr0_clk@fc { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; reg = <0xFC>; }; - peri_s2f_usr1_clk: peri_s2f_usr1_clk { + peri_s2f_usr1_clk: peri_s2f_usr1_clk@100 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; reg = <0x100>; }; - peri_hmc_pll_ref_clk: peri_hmc_pll_ref_clk { + peri_hmc_pll_ref_clk: peri_hmc_pll_ref_clk@104 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; @@ -287,7 +286,7 @@ }; }; - mpu_free_clk: mpu_free_clk { + mpu_free_clk: mpu_free_clk@60 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_mpu_base_clk>, <&peri_mpu_base_clk>, @@ -296,7 +295,7 @@ reg = <0x60>; }; - noc_free_clk: noc_free_clk { + noc_free_clk: noc_free_clk@64 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_noc_base_clk>, <&peri_noc_base_clk>, @@ -305,7 +304,7 @@ reg = <0x64>; }; - s2f_user1_free_clk: s2f_user1_free_clk { + s2f_user1_free_clk: s2f_user1_free_clk@104 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_s2f_usr1_clk>, <&peri_s2f_usr1_clk>, @@ -314,7 +313,7 @@ reg = <0x104>; }; - sdmmc_free_clk: sdmmc_free_clk { + sdmmc_free_clk: sdmmc_free_clk@f8 { #clock-cells = <0>; compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_sdmmc_clk>, <&peri_sdmmc_clk>, @@ -649,7 +648,7 @@ reg = <0xffe00000 0x40000>; }; - eccmgr: eccmgr@ffd06000 { + eccmgr: eccmgr { compatible = "altr,socfpga-a10-ecc-manager"; altr,sysmgr-syscon = <&sysmgr>; #address-cells = <1>; @@ -806,7 +805,7 @@ status = "disabled"; }; - usbphy0: usbphy@0 { + usbphy0: usbphy { #phy-cells = <0>; compatible = "usb-nop-xceiv"; status = "okay"; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi index c57e6cea0d83..94e088473823 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi @@ -30,7 +30,7 @@ stdout-path = "serial0:115200n8"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ @@ -121,6 +121,11 @@ gpio-controller; #gpio-cells = <2>; }; + + a10sr_rst: reset-controller { + compatible = "altr,a10sr-reset"; + #reset-cells = <1>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/socfpga_arria5_socdk.dts index 8672edf9ba4e..aac4feea86f3 100644 --- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts @@ -26,7 +26,7 @@ stdout-path = "serial0:115200n8"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ diff --git a/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts index 5ecd2ef405e3..7b49395452b6 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts @@ -25,7 +25,7 @@ stdout-path = "serial0:115200n8"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ diff --git a/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi index 6ad3b1eb9b86..3c03da6b8b1d 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi @@ -21,7 +21,7 @@ model = "Aries/DENX MCV"; compatible = "altr,socfpga-cyclone5", "altr,socfpga"; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1 GiB */ diff --git a/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts b/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts index e5a98e5696ca..21e397287e29 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts @@ -71,7 +71,6 @@ stmpe_touchscreen { compatible = "st,stmpe-ts"; - reg = <0>; ts,sample-time = <4>; ts,mod-12b = <1>; ts,ref-sel = <0>; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts index 7ea32c81e720..155829f9eba1 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts @@ -26,7 +26,7 @@ stdout-path = "serial0:115200n8"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts index a0c90b3bdfd1..a4a555c19d94 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts @@ -26,7 +26,7 @@ stdout-path = "serial0:115200n8"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts b/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts index c3d52f27b21e..53bf99eef66d 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts @@ -25,7 +25,7 @@ bootargs = "console=ttyS0,115200"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ @@ -60,18 +60,18 @@ &leds { compatible = "gpio-leds"; - led@0 { + led0 { label = "led:green:heartbeat"; gpios = <&porta 28 1>; linux,default-trigger = "heartbeat"; }; - led@1 { + led1 { label = "led:green:D7"; gpios = <&portb 19 1>; }; - led@2 { + led2 { label = "led:green:D8"; gpios = <&portb 25 1>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts index 5b7e3c27e6e9..8860dd2e242c 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts @@ -28,7 +28,7 @@ stdout-path = "serial0:115200n8"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; @@ -121,3 +121,24 @@ &usb1 { status = "okay"; }; + +&qspi { + status = "okay"; + + flash0: n25q512a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q512a"; + reg = <0>; + spi-max-frequency = <100000000>; + + m25p,fast-read; + cdns,page-size = <256>; + cdns,block-size = <16>; + cdns,read-delay = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; + }; +}; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts index 363ee62457fe..893198049397 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts @@ -57,7 +57,7 @@ bootargs = "console=ttyS0,115200"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index f9345e02ca49..dfe2193cd4d5 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -26,7 +26,7 @@ bootargs = "console=ttyS0,57600"; }; - memory { + memory@0 { name = "memory"; device_type = "memory"; reg = <0x0 0x40000000>; /* 1 GB */ diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts index d865a891776d..c67e76c8ba5d 100644 --- a/arch/arm/boot/dts/spear600-evb.dts +++ b/arch/arm/boot/dts/spear600-evb.dts @@ -22,95 +22,91 @@ device_type = "memory"; reg = <0 0x10000000>; }; +}; - ahb { - clcd@fc200000 { - status = "okay"; - }; +&clcd { + status = "okay"; +}; - dma@fc400000 { - status = "okay"; - }; +&dmac { + status = "okay"; +}; - ehci@e1800000 { - status = "okay"; - }; +&ehci_usb0 { + status = "okay"; +}; - ehci@e2000000 { - status = "okay"; - }; +&ehci_usb1 { + status = "okay"; +}; - gmac: ethernet@e0800000 { - phy-mode = "gmii"; - status = "okay"; - }; +&gmac { + phy-mode = "gmii"; + status = "okay"; +}; - ohci@e1900000 { - status = "okay"; - }; +&ohci_usb0 { + status = "okay"; +}; - ohci@e2100000 { - status = "okay"; - }; +&ohci_usb1 { + status = "okay"; +}; - smi: flash@fc000000 { - status = "okay"; - clock-rate=<50000000>; - - flash@f8000000 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xf8000000 0x800000>; - st,smi-fast-mode; - - partition@0 { - label = "xloader"; - reg = <0x0 0x10000>; - }; - partition@10000 { - label = "u-boot"; - reg = <0x10000 0x50000>; - }; - partition@60000 { - label = "environment"; - reg = <0x60000 0x10000>; - }; - partition@70000 { - label = "dtb"; - reg = <0x70000 0x10000>; - }; - partition@80000 { - label = "linux"; - reg = <0x80000 0x310000>; - }; - partition@390000 { - label = "rootfs"; - reg = <0x390000 0x0>; - }; - }; - }; +&smi { + status = "okay"; + clock-rate = <50000000>; - apb { - serial@d0000000 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <>; - }; + flash@f8000000 { + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; - serial@d0080000 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <>; - }; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; - rtc@fc900000 { - status = "okay"; + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; }; - - i2c@d0200000 { - clock-frequency = <400000>; - status = "okay"; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x50000>; + }; + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; + }; + partition@80000 { + label = "linux"; + reg = <0x80000 0x310000>; + }; + partition@390000 { + label = "rootfs"; + reg = <0x390000 0x0>; }; }; }; }; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&i2c { + clock-frequency = <400000>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index 9f60a7b6a42b..6b32d20acc9f 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -49,7 +49,7 @@ #interrupt-cells = <1>; }; - clcd@fc200000 { + clcd: clcd@fc200000 { compatible = "arm,pl110", "arm,primecell"; reg = <0xfc200000 0x1000>; interrupt-parent = <&vic1>; @@ -57,7 +57,7 @@ status = "disabled"; }; - dma@fc400000 { + dmac: dma@fc400000 { compatible = "arm,pl080", "arm,primecell"; reg = <0xfc400000 0x1000>; interrupt-parent = <&vic1>; @@ -97,7 +97,7 @@ status = "disabled"; }; - ehci@e1800000 { + ehci_usb0: ehci@e1800000 { compatible = "st,spear600-ehci", "usb-ehci"; reg = <0xe1800000 0x1000>; interrupt-parent = <&vic1>; @@ -105,7 +105,7 @@ status = "disabled"; }; - ehci@e2000000 { + ehci_usb1: ehci@e2000000 { compatible = "st,spear600-ehci", "usb-ehci"; reg = <0xe2000000 0x1000>; interrupt-parent = <&vic1>; @@ -113,7 +113,7 @@ status = "disabled"; }; - ohci@e1900000 { + ohci_usb0: ohci@e1900000 { compatible = "st,spear600-ohci", "usb-ohci"; reg = <0xe1900000 0x1000>; interrupt-parent = <&vic1>; @@ -121,7 +121,7 @@ status = "disabled"; }; - ohci@e2100000 { + ohci_usb1: ohci@e2100000 { compatible = "st,spear600-ohci", "usb-ohci"; reg = <0xe2100000 0x1000>; interrupt-parent = <&vic1>; @@ -135,7 +135,7 @@ compatible = "simple-bus"; ranges = <0xd0000000 0xd0000000 0x30000000>; - serial@d0000000 { + uart0: serial@d0000000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xd0000000 0x1000>; interrupt-parent = <&vic0>; @@ -143,7 +143,7 @@ status = "disabled"; }; - serial@d0080000 { + uart1: serial@d0080000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xd0080000 0x1000>; interrupt-parent = <&vic0>; @@ -181,7 +181,7 @@ interrupts = <4>; }; - i2c@d0200000 { + i2c: i2c@d0200000 { #address-cells = <1>; #size-cells = <0>; compatible = "snps,designware-i2c"; @@ -191,7 +191,7 @@ status = "disabled"; }; - rtc@fc900000 { + rtc: rtc@fc900000 { compatible = "st,spear600-rtc"; reg = <0xfc900000 0x1000>; interrupts = <10>; @@ -204,6 +204,14 @@ interrupt-parent = <&vic0>; interrupts = <16>; }; + + adc: adc@d820b000 { + compatible = "st,spear600-adc"; + reg = <0xd820b000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <6>; + status = "disabled"; + }; }; }; }; diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi index 044184580326..12c0757594d7 100644 --- a/arch/arm/boot/dts/stih407-family.dtsi +++ b/arch/arm/boot/dts/stih407-family.dtsi @@ -464,6 +464,8 @@ clock-names = "ssc"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi1_default>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -476,6 +478,8 @@ clock-names = "ssc"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi2_default>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -488,6 +492,8 @@ clock-names = "ssc"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi3_default>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -500,6 +506,8 @@ clock-names = "ssc"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi4_default>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -513,6 +521,8 @@ clock-names = "ssc"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi10_default>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -525,6 +535,8 @@ clock-names = "ssc"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi11_default>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -537,6 +549,8 @@ clock-names = "ssc"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi12_default>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -789,7 +803,7 @@ status = "okay"; }; - st231_gp0: remote-processor { + st231_gp0: st231-gp0@0 { compatible = "st,st231-rproc"; memory-region = <&gp0_reserved>; resets = <&softreset STIH407_ST231_GP0_SOFTRESET>; @@ -802,7 +816,7 @@ mboxes = <&mailbox0 0 2>, <&mailbox2 0 1>, <&mailbox0 0 3>, <&mailbox2 0 0>; }; - st231_delta: remote-processor { + st231_delta: st231-delta@0 { compatible = "st,st231-rproc"; memory-region = <&delta_reserved>; resets = <&softreset STIH407_ST231_DMU_SOFTRESET>; diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts index 3c99466989b1..b6331146aa02 100644 --- a/arch/arm/boot/dts/stm32429i-eval.dts +++ b/arch/arm/boot/dts/stm32429i-eval.dts @@ -167,6 +167,34 @@ status = "okay"; }; +&timers1 { + status = "okay"; + + pwm { + pinctrl-0 = <&pwm1_pins>; + pinctrl-names = "default"; + status = "okay"; + }; + + timer@0 { + status = "okay"; + }; +}; + +&timers3 { + status = "okay"; + + pwm { + pinctrl-0 = <&pwm3_pins>; + pinctrl-names = "default"; + status = "okay"; + }; + + timer@2 { + status = "okay"; + }; +}; + &usart1 { pinctrl-0 = <&usart1_pins_a>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/stm32746g-eval.dts b/arch/arm/boot/dts/stm32746g-eval.dts index 0dc18a0f0940..69a957963fa8 100644 --- a/arch/arm/boot/dts/stm32746g-eval.dts +++ b/arch/arm/boot/dts/stm32746g-eval.dts @@ -93,6 +93,10 @@ status = "okay"; }; +&rtc { + status = "okay"; +}; + &usart1 { pinctrl-0 = <&usart1_pins_a>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts index 9222b9f37bc0..191fa50e34eb 100644 --- a/arch/arm/boot/dts/stm32f429-disco.dts +++ b/arch/arm/boot/dts/stm32f429-disco.dts @@ -88,6 +88,14 @@ gpios = <&gpioa 0 0>; }; }; + + /* This turns on vbus for otg for host mode (dwc2) */ + vcc5v_otg: vcc5v-otg-regulator { + compatible = "regulator-fixed"; + gpio = <&gpioc 4 0>; + regulator-name = "vcc5_host1"; + regulator-always-on; + }; }; &clk_hse { @@ -105,3 +113,11 @@ pinctrl-names = "default"; status = "okay"; }; + +&usbotg_hs { + compatible = "st,stm32f4x9-fsotg"; + dr_mode = "host"; + pinctrl-0 = <&usbotg_fs_pins_b>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi index ee0da970e8ad..b2a2b5c38caa 100644 --- a/arch/arm/boot/dts/stm32f429.dtsi +++ b/arch/arm/boot/dts/stm32f429.dtsi @@ -450,6 +450,8 @@ clocks = <&rcc 0 STM32F4_APB2_CLOCK(ADC1)>; interrupt-parent = <&adc>; interrupts = <0>; + dmas = <&dma2 0 0 0x400 0x0>; + dma-names = "rx"; status = "disabled"; }; @@ -460,6 +462,8 @@ clocks = <&rcc 0 STM32F4_APB2_CLOCK(ADC2)>; interrupt-parent = <&adc>; interrupts = <1>; + dmas = <&dma2 3 1 0x400 0x0>; + dma-names = "rx"; status = "disabled"; }; @@ -470,6 +474,8 @@ clocks = <&rcc 0 STM32F4_APB2_CLOCK(ADC3)>; interrupt-parent = <&adc>; interrupts = <2>; + dmas = <&dma2 1 2 0x400 0x0>; + dma-names = "rx"; status = "disabled"; }; }; @@ -666,6 +672,28 @@ }; }; + usbotg_fs_pins_a: usbotg_fs@0 { + pins { + pinmux = <STM32F429_PA10_FUNC_OTG_FS_ID>, + <STM32F429_PA11_FUNC_OTG_FS_DM>, + <STM32F429_PA12_FUNC_OTG_FS_DP>; + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + usbotg_fs_pins_b: usbotg_fs@1 { + pins { + pinmux = <STM32F429_PB12_FUNC_OTG_HS_ID>, + <STM32F429_PB14_FUNC_OTG_HS_DM>, + <STM32F429_PB15_FUNC_OTG_HS_DP>; + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + usbotg_hs_pins_a: usbotg_hs@0 { pins { pinmux = <STM32F429_PH4_FUNC_OTG_HS_ULPI_NXT>, @@ -805,6 +833,15 @@ status = "disabled"; }; + usbotg_fs: usb@50000000 { + compatible = "st,stm32f4x9-fsotg"; + reg = <0x50000000 0x40000>; + interrupts = <67>; + clocks = <&rcc 0 39>; + clock-names = "otg"; + status = "disabled"; + }; + rng: rng@50060800 { compatible = "st,stm32-rng"; reg = <0x50060800 0x400>; diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts index 0dd56ef574fa..75470c34b92c 100644 --- a/arch/arm/boot/dts/stm32f469-disco.dts +++ b/arch/arm/boot/dts/stm32f469-disco.dts @@ -68,6 +68,15 @@ soc { dma-ranges = <0xc0000000 0x0 0x10000000>; }; + + /* This turns on vbus for otg for host mode (dwc2) */ + vcc5v_otg: vcc5v-otg-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpiob 2 0>; + regulator-name = "vcc5_host1"; + regulator-always-on; + }; }; &rcc { @@ -115,3 +124,10 @@ pinctrl-names = "default"; status = "okay"; }; + +&usbotg_fs { + dr_mode = "host"; + pinctrl-0 = <&usbotg_fs_pins_a>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32f746.dtsi b/arch/arm/boot/dts/stm32f746.dtsi index 755fb923c07b..c2765ce12e2e 100644 --- a/arch/arm/boot/dts/stm32f746.dtsi +++ b/arch/arm/boot/dts/stm32f746.dtsi @@ -43,6 +43,8 @@ #include "skeleton.dtsi" #include "armv7-m.dtsi" #include <dt-bindings/pinctrl/stm32f746-pinfunc.h> +#include <dt-bindings/clock/stm32fx-clock.h> +#include <dt-bindings/mfd/stm32f7-rcc.h> / { clocks { @@ -51,6 +53,24 @@ compatible = "fixed-clock"; clock-frequency = <0>; }; + + clk-lse { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + clk-lsi { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32000>; + }; + + clk_i2s_ckin: clk-i2s-ckin { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <48000000>; + }; }; soc { @@ -58,7 +78,7 @@ compatible = "st,stm32-timer"; reg = <0x40000000 0x400>; interrupts = <28>; - clocks = <&rcc 0 128>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM2)>; status = "disabled"; }; @@ -66,7 +86,7 @@ compatible = "st,stm32-timer"; reg = <0x40000400 0x400>; interrupts = <29>; - clocks = <&rcc 0 129>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM3)>; status = "disabled"; }; @@ -74,7 +94,7 @@ compatible = "st,stm32-timer"; reg = <0x40000800 0x400>; interrupts = <30>; - clocks = <&rcc 0 130>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM4)>; status = "disabled"; }; @@ -82,14 +102,14 @@ compatible = "st,stm32-timer"; reg = <0x40000c00 0x400>; interrupts = <50>; - clocks = <&rcc 0 131>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM5)>; }; timer6: timer@40001000 { compatible = "st,stm32-timer"; reg = <0x40001000 0x400>; interrupts = <54>; - clocks = <&rcc 0 132>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM6)>; status = "disabled"; }; @@ -97,7 +117,21 @@ compatible = "st,stm32-timer"; reg = <0x40001400 0x400>; interrupts = <55>; - clocks = <&rcc 0 133>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM7)>; + status = "disabled"; + }; + + rtc: rtc@40002800 { + compatible = "st,stm32-rtc"; + reg = <0x40002800 0x400>; + clocks = <&rcc 1 CLK_RTC>; + clock-names = "ck_rtc"; + assigned-clocks = <&rcc 1 CLK_RTC>; + assigned-clock-parents = <&rcc 1 CLK_LSE>; + interrupt-parent = <&exti>; + interrupts = <17 1>; + interrupt-names = "alarm"; + st,syscfg = <&pwrcfg>; status = "disabled"; }; @@ -105,7 +139,7 @@ compatible = "st,stm32f7-usart", "st,stm32f7-uart"; reg = <0x40004400 0x400>; interrupts = <38>; - clocks = <&rcc 0 145>; + clocks = <&rcc 1 CLK_USART2>; status = "disabled"; }; @@ -113,7 +147,7 @@ compatible = "st,stm32f7-usart", "st,stm32f7-uart"; reg = <0x40004800 0x400>; interrupts = <39>; - clocks = <&rcc 0 146>; + clocks = <&rcc 1 CLK_USART3>; status = "disabled"; }; @@ -121,7 +155,7 @@ compatible = "st,stm32f7-uart"; reg = <0x40004c00 0x400>; interrupts = <52>; - clocks = <&rcc 0 147>; + clocks = <&rcc 1 CLK_UART4>; status = "disabled"; }; @@ -129,7 +163,7 @@ compatible = "st,stm32f7-uart"; reg = <0x40005000 0x400>; interrupts = <53>; - clocks = <&rcc 0 148>; + clocks = <&rcc 1 CLK_UART5>; status = "disabled"; }; @@ -137,7 +171,7 @@ compatible = "st,stm32f7-usart", "st,stm32f7-uart"; reg = <0x40007800 0x400>; interrupts = <82>; - clocks = <&rcc 0 158>; + clocks = <&rcc 1 CLK_UART7>; status = "disabled"; }; @@ -145,7 +179,7 @@ compatible = "st,stm32f7-usart", "st,stm32f7-uart"; reg = <0x40007c00 0x400>; interrupts = <83>; - clocks = <&rcc 0 159>; + clocks = <&rcc 1 CLK_UART8>; status = "disabled"; }; @@ -153,7 +187,7 @@ compatible = "st,stm32f7-usart", "st,stm32f7-uart"; reg = <0x40011000 0x400>; interrupts = <37>; - clocks = <&rcc 0 164>; + clocks = <&rcc 1 CLK_USART1>; status = "disabled"; }; @@ -161,7 +195,7 @@ compatible = "st,stm32f7-usart", "st,stm32f7-uart"; reg = <0x40011400 0x400>; interrupts = <71>; - clocks = <&rcc 0 165>; + clocks = <&rcc 1 CLK_USART6>; status = "disabled"; }; @@ -178,6 +212,11 @@ interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>; }; + pwrcfg: power-config@40007000 { + compatible = "syscon"; + reg = <0x40007000 0x400>; + }; + pin-controller { #address-cells = <1>; #size-cells = <1>; @@ -191,7 +230,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x0 0x400>; - clocks = <&rcc 0 256>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOA)>; st,bank-name = "GPIOA"; }; @@ -199,7 +238,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x400 0x400>; - clocks = <&rcc 0 257>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOB)>; st,bank-name = "GPIOB"; }; @@ -207,7 +246,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x800 0x400>; - clocks = <&rcc 0 258>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOC)>; st,bank-name = "GPIOC"; }; @@ -215,7 +254,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0xc00 0x400>; - clocks = <&rcc 0 259>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOD)>; st,bank-name = "GPIOD"; }; @@ -223,7 +262,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x1000 0x400>; - clocks = <&rcc 0 260>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOE)>; st,bank-name = "GPIOE"; }; @@ -231,7 +270,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x1400 0x400>; - clocks = <&rcc 0 261>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOF)>; st,bank-name = "GPIOF"; }; @@ -239,7 +278,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x1800 0x400>; - clocks = <&rcc 0 262>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOG)>; st,bank-name = "GPIOG"; }; @@ -247,7 +286,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x1c00 0x400>; - clocks = <&rcc 0 263>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOH)>; st,bank-name = "GPIOH"; }; @@ -255,7 +294,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x2000 0x400>; - clocks = <&rcc 0 264>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOI)>; st,bank-name = "GPIOI"; }; @@ -263,7 +302,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x2400 0x400>; - clocks = <&rcc 0 265>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOJ)>; st,bank-name = "GPIOJ"; }; @@ -271,7 +310,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x2800 0x400>; - clocks = <&rcc 0 266>; + clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOK)>; st,bank-name = "GPIOK"; }; @@ -298,9 +337,12 @@ rcc: rcc@40023800 { #clock-cells = <2>; - compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; + compatible = "st,stm32f746-rcc", "st,stm32-rcc"; reg = <0x40023800 0x400>; - clocks = <&clk_hse>; + clocks = <&clk_hse>, <&clk_i2s_ckin>; + st,syscfg = <&pwrcfg>; + assigned-clocks = <&rcc 1 CLK_HSE_RTC>; + assigned-clock-rates = <1000000>; }; }; }; diff --git a/arch/arm/boot/dts/stm32h743-pinctrl.dtsi b/arch/arm/boot/dts/stm32h743-pinctrl.dtsi new file mode 100644 index 000000000000..fcc1e0640233 --- /dev/null +++ b/arch/arm/boot/dts/stm32h743-pinctrl.dtsi @@ -0,0 +1,156 @@ +/* + * Copyright 2017 - Alexandre Torgue <alexandre.torgue@st.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/pinctrl/stm32h7-pinfunc.h> + +/ { + soc { + pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32h743-pinctrl"; + ranges = <0 0x58020000 0x3000>; + pins-are-numbered; + + gpioa: gpio@58020000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOA"; + }; + + gpiob: gpio@58020400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x400 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOB"; + }; + + gpioc: gpio@58020800 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x800 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOC"; + }; + + gpiod: gpio@58020c00 { + gpio-controller; + #gpio-cells = <2>; + reg = <0xc00 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOD"; + }; + + gpioe: gpio@58021000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1000 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOE"; + }; + + gpiof: gpio@58021400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1400 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOF"; + }; + + gpiog: gpio@58021800 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1800 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOG"; + }; + + gpioh: gpio@58021c00 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x1c00 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOH"; + }; + + gpioi: gpio@58022000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x2000 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOI"; + }; + + gpioj: gpio@58022400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x2400 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOJ"; + }; + + gpiok: gpio@58022800 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x2800 0x400>; + clocks = <&timer_clk>; + st,bank-name = "GPIOK"; + }; + + usart1_pins: usart1@0 { + pins1 { + pinmux = <STM32H7_PB14_FUNC_USART1_TX>; + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = <STM32H7_PB15_FUNC_USART1_RX>; + bias-disable; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi new file mode 100644 index 000000000000..46856298ee16 --- /dev/null +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -0,0 +1,83 @@ +/* + * Copyright 2017 - Alexandre Torgue <alexandre.torgue@st.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "skeleton.dtsi" +#include "armv7-m.dtsi" + +/ { + clocks { + clk_hse: clk-hse { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + timer_clk: timer-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <125000000>; + }; + }; + + soc { + usart1: serial@40011000 { + compatible = "st,stm32f7-usart", "st,stm32f7-uart"; + reg = <0x40011000 0x400>; + interrupts = <37>; + status = "disabled"; + clocks = <&timer_clk>; + + }; + + timer5: timer@40000c00 { + compatible = "st,stm32-timer"; + reg = <0x40000c00 0x400>; + interrupts = <50>; + clocks = <&timer_clk>; + }; + }; +}; + +&systick { + clock-frequency = <250000000>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32h743i-eval.dts b/arch/arm/boot/dts/stm32h743i-eval.dts new file mode 100644 index 000000000000..c6effbb36e4a --- /dev/null +++ b/arch/arm/boot/dts/stm32h743i-eval.dts @@ -0,0 +1,74 @@ +/* + * Copyright 2017 - Alexandre Torgue <alexandre.torgue@st.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "stm32h743.dtsi" +#include "stm32h743-pinctrl.dtsi" + +/ { + model = "STMicroelectronics STM32H743i-EVAL board"; + compatible = "st,stm32h743i-eval", "st,stm32h743"; + + chosen { + bootargs = "root=/dev/ram"; + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0xd0000000 0x2000000>; + }; + + aliases { + serial0 = &usart1; + }; +}; + +&clk_hse { + clock-frequency = <125000000>; +}; + +&usart1 { + pinctrl-0 = <&usart1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts index f3fc27412a67..f2a01fe2bebc 100644 --- a/arch/arm/boot/dts/sun4i-a10-a1000.dts +++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts @@ -47,7 +47,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Mele A1000"; diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts index 04e040e6233d..d844938e2aa7 100644 --- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts @@ -46,7 +46,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Cubietech Cubieboard"; diff --git a/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts b/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts index 8317fbfeec4a..aad3bec1cb39 100644 --- a/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts +++ b/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/pwm/pwm.h> / { diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts index a48b46474417..a1a7282199d5 100644 --- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts +++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts @@ -47,7 +47,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Miniand Hackberry"; diff --git a/arch/arm/boot/dts/sun4i-a10-inet1.dts b/arch/arm/boot/dts/sun4i-a10-inet1.dts index f3092703a1a6..b8923b92cb36 100644 --- a/arch/arm/boot/dts/sun4i-a10-inet1.dts +++ b/arch/arm/boot/dts/sun4i-a10-inet1.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/pwm/pwm.h> / { diff --git a/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts index 4ef2a60a8cd4..4a27eb9102cd 100644 --- a/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts +++ b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "iNet-9F Rev 03"; diff --git a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts index fc4d4d49e2e2..308dc1513041 100644 --- a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts +++ b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts @@ -47,7 +47,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Jesurun Q5"; diff --git a/arch/arm/boot/dts/sun4i-a10-marsboard.dts b/arch/arm/boot/dts/sun4i-a10-marsboard.dts index a2885039d5f1..98a5f7258dca 100644 --- a/arch/arm/boot/dts/sun4i-a10-marsboard.dts +++ b/arch/arm/boot/dts/sun4i-a10-marsboard.dts @@ -46,7 +46,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "HAOYU Electronics Marsboard A10"; diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts index af42ebb3a97b..484c57493bd2 100644 --- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts +++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts @@ -47,7 +47,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "PineRiver Mini X-Plus"; diff --git a/arch/arm/boot/dts/sun4i-a10-mk802.dts b/arch/arm/boot/dts/sun4i-a10-mk802.dts index 9c1afd4277d7..2b75745cd246 100644 --- a/arch/arm/boot/dts/sun4i-a10-mk802.dts +++ b/arch/arm/boot/dts/sun4i-a10-mk802.dts @@ -44,7 +44,6 @@ #include "sun4i-a10.dtsi" #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "MK802"; diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts index 214a5accfe93..3a2522a9419d 100644 --- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts +++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts @@ -45,7 +45,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A10-OLinuXino-LIME"; diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts index b0365d63ba70..83596fd2ccfc 100644 --- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts +++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts @@ -47,7 +47,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "LinkSprite pcDuino"; diff --git a/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts index bfa6bbdaab27..a68c7cc53b94 100644 --- a/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts +++ b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/pwm/pwm.h> / { diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index ba20b48c0702..b63668ece151 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -47,7 +47,6 @@ #include <dt-bindings/clock/sun4i-a10-pll2.h> #include <dt-bindings/dma/sun4i-a10.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { interrupt-parent = <&intc>; @@ -974,6 +973,11 @@ #interrupt-cells = <3>; #gpio-cells = <3>; + can0_pins_a: can0@0 { + pins = "PH20", "PH21"; + function = "can"; + }; + emac_pins_a: emac0@0 { pins = "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", @@ -1283,6 +1287,22 @@ status = "disabled"; }; + ps20: ps2@01c2a000 { + compatible = "allwinner,sun4i-a10-ps2"; + reg = <0x01c2a000 0x400>; + interrupts = <62>; + clocks = <&apb1_gates 6>; + status = "disabled"; + }; + + ps21: ps2@01c2a400 { + compatible = "allwinner,sun4i-a10-ps2"; + reg = <0x01c2a400 0x400>; + interrupts = <63>; + clocks = <&apb1_gates 7>; + status = "disabled"; + }; + i2c0: i2c@01c2ac00 { compatible = "allwinner,sun4i-a10-i2c"; reg = <0x01c2ac00 0x400>; @@ -1313,19 +1333,11 @@ #size-cells = <0>; }; - ps20: ps2@01c2a000 { - compatible = "allwinner,sun4i-a10-ps2"; - reg = <0x01c2a000 0x400>; - interrupts = <62>; - clocks = <&apb1_gates 6>; - status = "disabled"; - }; - - ps21: ps2@01c2a400 { - compatible = "allwinner,sun4i-a10-ps2"; - reg = <0x01c2a400 0x400>; - interrupts = <63>; - clocks = <&apb1_gates 7>; + can0: can@01c2bc00 { + compatible = "allwinner,sun4i-a10-can"; + reg = <0x01c2bc00 0x400>; + interrupts = <26>; + clocks = <&apb1_gates 4>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts b/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts index a539b72ce093..c6f742a7e69f 100644 --- a/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts +++ b/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts @@ -44,7 +44,6 @@ #include "sun5i-a10s.dtsi" #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Auxtek t003 A10s hdmi tv-stick"; diff --git a/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts index e1b5e8a446fe..a27c3fa58736 100644 --- a/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts +++ b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts @@ -44,7 +44,6 @@ #include "sun5i-a10s.dtsi" #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Auxtek t004 A10s hdmi tv-stick"; diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts index d8245c6314a7..894f874a5beb 100644 --- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A10s-Olinuxino Micro"; @@ -83,7 +82,7 @@ &emac { pinctrl-names = "default"; - pinctrl-0 = <&emac_pins_a>; + pinctrl-0 = <&emac_pins_b>; phy = <&phy1>; status = "okay"; }; @@ -257,7 +256,7 @@ &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&uart2_pins_a>; + pinctrl-0 = <&uart2_pins_b>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts index 51371f9b1cf0..262b3669f04d 100644 --- a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts +++ b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts @@ -45,7 +45,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "R7 A10s hdmi tv-stick"; diff --git a/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts index 2b8adda0deda..ea3e5655a61b 100644 --- a/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts +++ b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "A10s-Wobo i5"; @@ -95,7 +94,7 @@ &emac { pinctrl-names = "default"; - pinctrl-0 = <&emac_pins_b>; + pinctrl-0 = <&emac_pins_a>; phy = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index 24b0f5f556f8..1e38ff80366c 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -47,7 +47,6 @@ #include "sun5i.dtsi" #include <dt-bindings/dma/sun4i-a10.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { interrupt-parent = <&intc>; @@ -61,7 +60,7 @@ #size-cells = <1>; ranges; - framebuffer@0 { + framebuffer@2 { compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0-hdmi"; @@ -70,45 +69,9 @@ <&ccu CLK_DE_BE>, <&ccu CLK_HDMI>; status = "disabled"; }; - - framebuffer@1 { - compatible = "allwinner,simple-framebuffer", - "simple-framebuffer"; - allwinner,pipeline = "de_be0-lcd0"; - clocks = <&ccu CLK_AHB_LCD>, <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, - <&ccu CLK_TCON_CH0>, <&ccu CLK_DRAM_DE_BE>; - status = "disabled"; - }; - - framebuffer@2 { - compatible = "allwinner,simple-framebuffer", - "simple-framebuffer"; - allwinner,pipeline = "de_be0-lcd0-tve0"; - clocks = <&ccu CLK_AHB_TVE>, <&ccu CLK_AHB_LCD>, - <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, - <&ccu CLK_TCON_CH1>, <&ccu CLK_DRAM_DE_BE>; - status = "disabled"; - }; }; soc@01c00000 { - emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-a10-emac"; - reg = <0x01c0b000 0x1000>; - interrupts = <55>; - clocks = <&ccu CLK_AHB_EMAC>; - allwinner,sram = <&emac_sram 1>; - status = "disabled"; - }; - - mdio: mdio@01c0b080 { - compatible = "allwinner,sun4i-a10-mdio"; - reg = <0x01c0b080 0x14>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - pwm: pwm@01c20e00 { compatible = "allwinner,sun5i-a10s-pwm"; reg = <0x01c20e00 0xc>; @@ -116,26 +79,6 @@ #pwm-cells = <3>; status = "disabled"; }; - - uart0: serial@01c28000 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28000 0x400>; - interrupts = <1>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_APB1_UART0>; - status = "disabled"; - }; - - uart2: serial@01c28800 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28800 0x400>; - interrupts = <3>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_APB1_UART2>; - status = "disabled"; - }; }; }; @@ -151,12 +94,12 @@ function = "uart0"; }; - uart2_pins_a: uart2@0 { + uart2_pins_b: uart2@1 { pins = "PC18", "PC19"; function = "uart2"; }; - emac_pins_a: emac0@0 { + emac_pins_b: emac0@1 { pins = "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7", "PA8", "PA9", "PA10", @@ -165,15 +108,6 @@ function = "emac"; }; - emac_pins_b: emac0@1 { - pins = "PD6", "PD7", "PD10", - "PD11", "PD12", "PD13", "PD14", - "PD15", "PD18", "PD19", "PD20", - "PD21", "PD22", "PD23", "PD24", - "PD25", "PD26", "PD27"; - function = "emac"; - }; - mmc1_pins_a: mmc1@0 { pins = "PG3", "PG4", "PG5", "PG6", "PG7", "PG8"; @@ -193,9 +127,4 @@ }; &sram_a { - emac_sram: sram-section@8000 { - compatible = "allwinner,sun4i-a10-sram-a3-a4"; - reg = <0x8000 0x4000>; - status = "disabled"; - }; }; diff --git a/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts b/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts index 42435454acef..34411d27aadf 100644 --- a/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts +++ b/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/pwm/pwm.h> / { diff --git a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts index 5879a75cf97a..2489c16f7efa 100644 --- a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts +++ b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "HSG H702"; diff --git a/arch/arm/boot/dts/sun5i-a13-licheepi-one.dts b/arch/arm/boot/dts/sun5i-a13-licheepi-one.dts index 566cda91a66b..bc883893f4a4 100644 --- a/arch/arm/boot/dts/sun5i-a13-licheepi-one.dts +++ b/arch/arm/boot/dts/sun5i-a13-licheepi-one.dts @@ -50,7 +50,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Lichee Pi One"; diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts index 60e393e28783..3a831eaf1dfc 100644 --- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts @@ -46,7 +46,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A13-Olinuxino Micro"; diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts index 940d47e88056..95f591bb8ced 100644 --- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A13-Olinuxino"; diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index fb2ddb9a04c9..6436bad94404 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi @@ -46,27 +46,11 @@ #include "sun5i.dtsi" -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/thermal/thermal.h> / { interrupt-parent = <&intc>; - chosen { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - framebuffer@0 { - compatible = "allwinner,simple-framebuffer", - "simple-framebuffer"; - allwinner,pipeline = "de_be0-lcd0"; - clocks = <&ccu CLK_AHB_LCD>, <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, - <&ccu CLK_TCON_CH0>, <&ccu CLK_DRAM_DE_BE>; - status = "disabled"; - }; - }; - thermal-zones { cpu_thermal { /* milliseconds */ @@ -105,44 +89,6 @@ }; soc@01c00000 { - tcon0: lcd-controller@01c0c000 { - compatible = "allwinner,sun5i-a13-tcon"; - reg = <0x01c0c000 0x1000>; - interrupts = <44>; - resets = <&ccu RST_LCD>; - reset-names = "lcd"; - clocks = <&ccu CLK_AHB_LCD>, - <&ccu CLK_TCON_CH0>, - <&ccu CLK_TCON_CH1>; - clock-names = "ahb", - "tcon-ch0", - "tcon-ch1"; - clock-output-names = "tcon-pixel-clock"; - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - tcon0_in: port@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - tcon0_in_be0: endpoint@0 { - reg = <0>; - remote-endpoint = <&be0_out_tcon0>; - }; - }; - - tcon0_out: port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - }; - }; - pwm: pwm@01c20e00 { compatible = "allwinner,sun5i-a13-pwm"; reg = <0x01c20e00 0xc>; @@ -151,74 +97,6 @@ status = "disabled"; }; - fe0: display-frontend@01e00000 { - compatible = "allwinner,sun5i-a13-display-frontend"; - reg = <0x01e00000 0x20000>; - interrupts = <47>; - clocks = <&ccu CLK_DE_FE>, <&ccu CLK_DE_FE>, - <&ccu CLK_DRAM_DE_FE>; - clock-names = "ahb", "mod", - "ram"; - resets = <&ccu RST_DE_FE>; - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - fe0_out: port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - - fe0_out_be0: endpoint@0 { - reg = <0>; - remote-endpoint = <&be0_in_fe0>; - }; - }; - }; - }; - - be0: display-backend@01e60000 { - compatible = "allwinner,sun5i-a13-display-backend"; - reg = <0x01e60000 0x10000>; - clocks = <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, - <&ccu CLK_DRAM_DE_BE>; - clock-names = "ahb", "mod", - "ram"; - resets = <&ccu RST_DE_BE>; - status = "disabled"; - - assigned-clocks = <&ccu CLK_DE_BE>; - assigned-clock-rates = <300000000>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - be0_in: port@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - be0_in_fe0: endpoint@0 { - reg = <0>; - remote-endpoint = <&fe0_out_be0>; - }; - }; - - be0_out: port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - - be0_out_tcon0: endpoint@0 { - reg = <0>; - remote-endpoint = <&tcon0_in_be0>; - }; - }; - }; - }; }; }; @@ -244,22 +122,4 @@ &pio { compatible = "allwinner,sun5i-a13-pinctrl"; - - lcd_rgb666_pins: lcd_rgb666@0 { - pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", - "PD10", "PD11", "PD12", "PD13", "PD14", "PD15", - "PD18", "PD19", "PD20", "PD21", "PD22", "PD23", - "PD24", "PD25", "PD26", "PD27"; - function = "lcd0"; - }; - - uart1_pins_a: uart1@0 { - pins = "PE10", "PE11"; - function = "uart1"; - }; - - uart1_pins_b: uart1@1 { - pins = "PG3", "PG4"; - function = "uart1"; - }; }; diff --git a/arch/arm/boot/dts/sun5i-gr8-chip-pro.dts b/arch/arm/boot/dts/sun5i-gr8-chip-pro.dts index 0cf0813d363a..c55b11a4d3c7 100644 --- a/arch/arm/boot/dts/sun5i-gr8-chip-pro.dts +++ b/arch/arm/boot/dts/sun5i-gr8-chip-pro.dts @@ -171,7 +171,7 @@ &pwm { pinctrl-names = "default"; - pinctrl-0 = <&pwm0_pins_a>, <&pwm1_pins>; + pinctrl-0 = <&pwm0_pins>, <&pwm1_pins>; status = "disabled"; }; @@ -220,7 +220,7 @@ &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&uart1_pins_a>, <&uart1_cts_rts_pins_a>; + pinctrl-0 = <&uart1_pins_b>, <&uart1_cts_rts_pins_a>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun5i-gr8-evb.dts b/arch/arm/boot/dts/sun5i-gr8-evb.dts index 1a845af4d4db..558c16a30543 100644 --- a/arch/arm/boot/dts/sun5i-gr8-evb.dts +++ b/arch/arm/boot/dts/sun5i-gr8-evb.dts @@ -281,7 +281,7 @@ &pwm { pinctrl-names = "default"; - pinctrl-0 = <&pwm0_pins_a>; + pinctrl-0 = <&pwm0_pins>; status = "okay"; }; @@ -332,7 +332,7 @@ &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&uart1_pins_a>, <&uart1_cts_rts_pins_a>; + pinctrl-0 = <&uart1_pins_b>, <&uart1_cts_rts_pins_a>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun5i-gr8.dtsi b/arch/arm/boot/dts/sun5i-gr8.dtsi index cb9b2aaf7297..3eb56cad0cea 100644 --- a/arch/arm/boot/dts/sun5i-gr8.dtsi +++ b/arch/arm/boot/dts/sun5i-gr8.dtsi @@ -42,429 +42,19 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "sun5i.dtsi" + #include <dt-bindings/clock/sun5i-ccu.h> #include <dt-bindings/dma/sun4i-a10.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/reset/sun5i-ccu.h> / { - interrupt-parent = <&intc>; - #address-cells = <1>; - #size-cells = <1>; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu0: cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a8"; - reg = <0x0>; - clocks = <&ccu CLK_CPU>; - }; - }; - - clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - osc24M: clk@01c20050 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - clock-output-names = "osc24M"; - }; - - osc32k: clk@0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <32768>; - clock-output-names = "osc32k"; - }; - }; - display-engine { compatible = "allwinner,sun5i-a13-display-engine"; allwinner,pipelines = <&fe0>; }; soc@01c00000 { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - sram-controller@01c00000 { - compatible = "allwinner,sun4i-a10-sram-controller"; - reg = <0x01c00000 0x30>; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - sram_a: sram@00000000 { - compatible = "mmio-sram"; - reg = <0x00000000 0xc000>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x00000000 0xc000>; - }; - - sram_d: sram@00010000 { - compatible = "mmio-sram"; - reg = <0x00010000 0x1000>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x00010000 0x1000>; - - otg_sram: sram-section@0000 { - compatible = "allwinner,sun4i-a10-sram-d"; - reg = <0x0000 0x1000>; - status = "disabled"; - }; - }; - }; - - dma: dma-controller@01c02000 { - compatible = "allwinner,sun4i-a10-dma"; - reg = <0x01c02000 0x1000>; - interrupts = <27>; - clocks = <&ccu CLK_AHB_DMA>; - #dma-cells = <2>; - }; - - nfc: nand@01c03000 { - compatible = "allwinner,sun4i-a10-nand"; - reg = <0x01c03000 0x1000>; - interrupts = <37>; - clocks = <&ccu CLK_AHB_NAND>, <&ccu CLK_NAND>; - clock-names = "ahb", "mod"; - dmas = <&dma SUN4I_DMA_DEDICATED 3>; - dma-names = "rxtx"; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - spi0: spi@01c05000 { - compatible = "allwinner,sun4i-a10-spi"; - reg = <0x01c05000 0x1000>; - interrupts = <10>; - clocks = <&ccu CLK_AHB_SPI0>, <&ccu CLK_SPI0>; - clock-names = "ahb", "mod"; - dmas = <&dma SUN4I_DMA_DEDICATED 27>, - <&dma SUN4I_DMA_DEDICATED 26>; - dma-names = "rx", "tx"; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - spi1: spi@01c06000 { - compatible = "allwinner,sun4i-a10-spi"; - reg = <0x01c06000 0x1000>; - interrupts = <11>; - clocks = <&ccu CLK_AHB_SPI1>, <&ccu CLK_SPI1>; - clock-names = "ahb", "mod"; - dmas = <&dma SUN4I_DMA_DEDICATED 9>, - <&dma SUN4I_DMA_DEDICATED 8>; - dma-names = "rx", "tx"; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - tve0: tv-encoder@01c0a000 { - compatible = "allwinner,sun4i-a10-tv-encoder"; - reg = <0x01c0a000 0x1000>; - clocks = <&ccu CLK_AHB_TVE>; - resets = <&ccu RST_TVE>; - status = "disabled"; - - port { - #address-cells = <1>; - #size-cells = <0>; - - tve0_in_tcon0: endpoint@0 { - reg = <0>; - remote-endpoint = <&tcon0_out_tve0>; - }; - }; - }; - - tcon0: lcd-controller@01c0c000 { - compatible = "allwinner,sun5i-a13-tcon"; - reg = <0x01c0c000 0x1000>; - interrupts = <44>; - resets = <&ccu RST_LCD>; - reset-names = "lcd"; - clocks = <&ccu CLK_AHB_LCD>, - <&ccu CLK_TCON_CH0>, - <&ccu CLK_TCON_CH1>; - clock-names = "ahb", - "tcon-ch0", - "tcon-ch1"; - clock-output-names = "tcon-pixel-clock"; - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - tcon0_in: port@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - tcon0_in_be0: endpoint@0 { - reg = <0>; - remote-endpoint = <&be0_out_tcon0>; - }; - }; - - tcon0_out: port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - - tcon0_out_tve0: endpoint@1 { - reg = <1>; - remote-endpoint = <&tve0_in_tcon0>; - }; - }; - }; - }; - - mmc0: mmc@01c0f000 { - compatible = "allwinner,sun5i-a13-mmc"; - reg = <0x01c0f000 0x1000>; - clocks = <&ccu CLK_AHB_MMC0>, <&ccu CLK_MMC0>; - clock-names = "ahb", "mmc"; - interrupts = <32>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - mmc1: mmc@01c10000 { - compatible = "allwinner,sun5i-a13-mmc"; - reg = <0x01c10000 0x1000>; - clocks = <&ccu CLK_AHB_MMC1>, <&ccu CLK_MMC1>; - clock-names = "ahb", "mmc"; - interrupts = <33>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - mmc2: mmc@01c11000 { - compatible = "allwinner,sun5i-a13-mmc"; - reg = <0x01c11000 0x1000>; - clocks = <&ccu CLK_AHB_MMC2>, <&ccu CLK_MMC2>; - clock-names = "ahb", "mmc"; - interrupts = <34>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - usb_otg: usb@01c13000 { - compatible = "allwinner,sun4i-a10-musb"; - reg = <0x01c13000 0x0400>; - clocks = <&ccu CLK_AHB_OTG>; - interrupts = <38>; - interrupt-names = "mc"; - phys = <&usbphy 0>; - phy-names = "usb"; - extcon = <&usbphy 0>; - allwinner,sram = <&otg_sram 1>; - status = "disabled"; - - dr_mode = "otg"; - }; - - usbphy: phy@01c13400 { - #phy-cells = <1>; - compatible = "allwinner,sun5i-a13-usb-phy"; - reg = <0x01c13400 0x10 0x01c14800 0x4>; - reg-names = "phy_ctrl", "pmu1"; - clocks = <&ccu CLK_USB_PHY0>; - clock-names = "usb_phy"; - resets = <&ccu RST_USB_PHY0>, <&ccu RST_USB_PHY1>; - reset-names = "usb0_reset", "usb1_reset"; - status = "disabled"; - }; - - ehci0: usb@01c14000 { - compatible = "allwinner,sun5i-a13-ehci", "generic-ehci"; - reg = <0x01c14000 0x100>; - interrupts = <39>; - clocks = <&ccu CLK_AHB_EHCI>; - phys = <&usbphy 1>; - phy-names = "usb"; - status = "disabled"; - }; - - ohci0: usb@01c14400 { - compatible = "allwinner,sun5i-a13-ohci", "generic-ohci"; - reg = <0x01c14400 0x100>; - interrupts = <40>; - clocks = <&ccu CLK_USB_OHCI>, <&ccu CLK_AHB_OHCI>; - phys = <&usbphy 1>; - phy-names = "usb"; - status = "disabled"; - }; - - spi2: spi@01c17000 { - compatible = "allwinner,sun4i-a10-spi"; - reg = <0x01c17000 0x1000>; - interrupts = <12>; - clocks = <&ccu CLK_AHB_SPI2>, <&ccu CLK_SPI2>; - clock-names = "ahb", "mod"; - dmas = <&dma SUN4I_DMA_DEDICATED 29>, - <&dma SUN4I_DMA_DEDICATED 28>; - dma-names = "rx", "tx"; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - ccu: clock@01c20000 { - compatible = "nextthing,gr8-ccu"; - reg = <0x01c20000 0x400>; - clocks = <&osc24M>, <&osc32k>; - clock-names = "hosc", "losc"; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - intc: interrupt-controller@01c20400 { - compatible = "allwinner,sun4i-a10-ic"; - reg = <0x01c20400 0x400>; - interrupt-controller; - #interrupt-cells = <1>; - }; - - pio: pinctrl@01c20800 { - compatible = "nextthing,gr8-pinctrl"; - reg = <0x01c20800 0x400>; - interrupts = <28>; - clocks = <&ccu CLK_APB0_PIO>; - gpio-controller; - interrupt-controller; - #interrupt-cells = <3>; - #gpio-cells = <3>; - - i2c0_pins_a: i2c0@0 { - pins = "PB0", "PB1"; - function = "i2c0"; - }; - - i2c1_pins_a: i2c1@0 { - pins = "PB15", "PB16"; - function = "i2c1"; - }; - - i2c2_pins_a: i2c2@0 { - pins = "PB17", "PB18"; - function = "i2c2"; - }; - - i2s0_data_pins_a: i2s0-data@0 { - pins = "PB6", "PB7", "PB8", "PB9"; - function = "i2s0"; - }; - - i2s0_mclk_pins_a: i2s0-mclk@0 { - pins = "PB5"; - function = "i2s0"; - }; - - ir0_rx_pins_a: ir0@0 { - pins = "PB4"; - function = "ir0"; - }; - - lcd_rgb666_pins: lcd-rgb666@0 { - pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", - "PD10", "PD11", "PD12", "PD13", "PD14", "PD15", - "PD18", "PD19", "PD20", "PD21", "PD22", "PD23", - "PD24", "PD25", "PD26", "PD27"; - function = "lcd0"; - }; - - mmc0_pins_a: mmc0@0 { - pins = "PF0", "PF1", "PF2", "PF3", - "PF4", "PF5"; - function = "mmc0"; - drive-strength = <30>; - }; - - nand_pins_a: nand-base0@0 { - pins = "PC0", "PC1", "PC2", - "PC5", "PC8", "PC9", "PC10", - "PC11", "PC12", "PC13", "PC14", - "PC15"; - function = "nand0"; - }; - - nand_cs0_pins_a: nand-cs@0 { - pins = "PC4"; - function = "nand0"; - }; - - nand_rb0_pins_a: nand-rb@0 { - pins = "PC6"; - function = "nand0"; - }; - - pwm0_pins_a: pwm0@0 { - pins = "PB2"; - function = "pwm0"; - }; - - pwm1_pins: pwm1 { - pins = "PG13"; - function = "pwm1"; - }; - - spdif_tx_pins_a: spdif@0 { - pins = "PB10"; - function = "spdif"; - bias-pull-up; - }; - - uart1_pins_a: uart1@1 { - pins = "PG3", "PG4"; - function = "uart1"; - }; - - uart1_cts_rts_pins_a: uart1-cts-rts@0 { - pins = "PG5", "PG6"; - function = "uart1"; - }; - - uart2_pins_a: uart2@1 { - pins = "PD2", "PD3"; - function = "uart2"; - }; - - uart2_cts_rts_pins_a: uart2-cts-rts@0 { - pins = "PD4", "PD5"; - function = "uart2"; - }; - - uart3_pins_a: uart3@1 { - pins = "PG9", "PG10"; - function = "uart3"; - }; - - uart3_cts_rts_pins_a: uart3-cts-rts@0 { - pins = "PG11", "PG12"; - function = "uart3"; - }; - }; - pwm: pwm@01c20e00 { compatible = "allwinner,sun5i-a10s-pwm"; reg = <0x01c20e00 0xc>; @@ -473,18 +63,6 @@ status = "disabled"; }; - timer@01c20c00 { - compatible = "allwinner,sun4i-a10-timer"; - reg = <0x01c20c00 0x90>; - interrupts = <22>; - clocks = <&ccu CLK_HOSC>; - }; - - wdt: watchdog@01c20c90 { - compatible = "allwinner,sun4i-a10-wdt"; - reg = <0x01c20c90 0x10>; - }; - spdif: spdif@01c21000 { #sound-dai-cells = <0>; compatible = "allwinner,sun4i-a10-spdif"; @@ -498,15 +76,6 @@ status = "disabled"; }; - ir0: ir@01c21800 { - compatible = "allwinner,sun4i-a10-ir"; - clocks = <&ccu CLK_APB0_IR>, <&ccu CLK_IR>; - clock-names = "apb", "ir"; - interrupts = <5>; - reg = <0x01c21800 0x40>; - status = "disabled"; - }; - i2s0: i2s@01c22400 { #sound-dai-cells = <0>; compatible = "allwinner,sun4i-a10-i2s"; @@ -519,168 +88,39 @@ dma-names = "rx", "tx"; status = "disabled"; }; + }; +}; - lradc: lradc@01c22800 { - compatible = "allwinner,sun4i-a10-lradc-keys"; - reg = <0x01c22800 0x100>; - interrupts = <31>; - status = "disabled"; - }; - - codec: codec@01c22c00 { - #sound-dai-cells = <0>; - compatible = "allwinner,sun4i-a10-codec"; - reg = <0x01c22c00 0x40>; - interrupts = <30>; - clocks = <&ccu CLK_APB0_CODEC>, <&ccu CLK_CODEC>; - clock-names = "apb", "codec"; - dmas = <&dma SUN4I_DMA_NORMAL 19>, - <&dma SUN4I_DMA_NORMAL 19>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - rtp: rtp@01c25000 { - compatible = "allwinner,sun5i-a13-ts"; - reg = <0x01c25000 0x100>; - interrupts = <29>; - #thermal-sensor-cells = <0>; - }; - - uart1: serial@01c28400 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28400 0x400>; - interrupts = <2>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_APB1_UART1>; - status = "disabled"; - }; - - uart2: serial@01c28800 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28800 0x400>; - interrupts = <3>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_APB1_UART2>; - status = "disabled"; - }; - - uart3: serial@01c28c00 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28c00 0x400>; - interrupts = <4>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_APB1_UART3>; - status = "disabled"; - }; - - i2c0: i2c@01c2ac00 { - compatible = "allwinner,sun4i-a10-i2c"; - reg = <0x01c2ac00 0x400>; - interrupts = <7>; - clocks = <&ccu CLK_APB1_I2C0>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - i2c1: i2c@01c2b000 { - compatible = "allwinner,sun4i-a10-i2c"; - reg = <0x01c2b000 0x400>; - interrupts = <8>; - clocks = <&ccu CLK_APB1_I2C1>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - i2c2: i2c@01c2b400 { - compatible = "allwinner,sun4i-a10-i2c"; - reg = <0x01c2b400 0x400>; - interrupts = <9>; - clocks = <&ccu CLK_APB1_I2C2>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - timer@01c60000 { - compatible = "allwinner,sun5i-a13-hstimer"; - reg = <0x01c60000 0x1000>; - interrupts = <82>, <83>; - clocks = <&ccu CLK_AHB_HSTIMER>; - }; - - fe0: display-frontend@01e00000 { - compatible = "allwinner,sun5i-a13-display-frontend"; - reg = <0x01e00000 0x20000>; - interrupts = <47>; - clocks = <&ccu CLK_AHB_DE_FE>, <&ccu CLK_DE_FE>, - <&ccu CLK_DRAM_DE_FE>; - clock-names = "ahb", "mod", - "ram"; - resets = <&ccu RST_DE_FE>; - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - fe0_out: port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - - fe0_out_be0: endpoint@0 { - reg = <0>; - remote-endpoint = <&be0_in_fe0>; - }; - }; - }; - }; - - be0: display-backend@01e60000 { - compatible = "allwinner,sun5i-a13-display-backend"; - reg = <0x01e60000 0x10000>; - clocks = <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, - <&ccu CLK_DRAM_DE_BE>; - clock-names = "ahb", "mod", - "ram"; - resets = <&ccu RST_DE_BE>; - status = "disabled"; +&ccu { + compatible = "nextthing,gr8-ccu"; +}; - assigned-clocks = <&ccu CLK_DE_BE>; - assigned-clock-rates = <300000000>; +&pio { + compatible = "nextthing,gr8-pinctrl"; - ports { - #address-cells = <1>; - #size-cells = <0>; + i2s0_data_pins_a: i2s0-data@0 { + pins = "PB6", "PB7", "PB8", "PB9"; + function = "i2s0"; + }; - be0_in: port@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; + i2s0_mclk_pins_a: i2s0-mclk@0 { + pins = "PB5"; + function = "i2s0"; + }; - be0_in_fe0: endpoint@0 { - reg = <0>; - remote-endpoint = <&fe0_out_be0>; - }; - }; + pwm1_pins: pwm1 { + pins = "PG13"; + function = "pwm1"; + }; - be0_out: port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; + spdif_tx_pins_a: spdif@0 { + pins = "PB10"; + function = "spdif"; + bias-pull-up; + }; - be0_out_tcon0: endpoint@0 { - reg = <0>; - remote-endpoint = <&tcon0_in_be0>; - }; - }; - }; - }; + uart1_cts_rts_pins_a: uart1-cts-rts@0 { + pins = "PG5", "PG6"; + function = "uart1"; }; }; diff --git a/arch/arm/boot/dts/sun5i-r8-chip.dts b/arch/arm/boot/dts/sun5i-r8-chip.dts index e86fa46fdd45..d0785602663b 100644 --- a/arch/arm/boot/dts/sun5i-r8-chip.dts +++ b/arch/arm/boot/dts/sun5i-r8-chip.dts @@ -128,6 +128,10 @@ #include "axp209.dtsi" +&ac_power_supply { + status = "okay"; +}; + &i2c1 { pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins_a>; @@ -281,7 +285,7 @@ &uart3 { pinctrl-names = "default"; pinctrl-0 = <&uart3_pins_a>, - <&uart3_pins_cts_rts_a>; + <&uart3_cts_rts_pins_a>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi index 4c1141396c99..de35dbcd1191 100644 --- a/arch/arm/boot/dts/sun5i-r8.dtsi +++ b/arch/arm/boot/dts/sun5i-r8.dtsi @@ -45,43 +45,3 @@ #include "sun5i-a13.dtsi" -/ { - chosen { - framebuffer@1 { - compatible = "allwinner,simple-framebuffer", - "simple-framebuffer"; - allwinner,pipeline = "de_be0-lcd0-tve0"; - clocks = <&ccu CLK_AHB_TVE>, <&ccu CLK_AHB_LCD>, - <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, - <&ccu CLK_TCON_CH1>, <&ccu CLK_DRAM_DE_BE>; - status = "disabled"; - }; - }; - - soc@01c00000 { - tve0: tv-encoder@01c0a000 { - compatible = "allwinner,sun4i-a10-tv-encoder"; - reg = <0x01c0a000 0x1000>; - clocks = <&ccu CLK_AHB_TVE>; - resets = <&ccu RST_TVE>; - status = "disabled"; - - port { - #address-cells = <1>; - #size-cells = <0>; - - tve0_in_tcon0: endpoint@0 { - reg = <0>; - remote-endpoint = <&tcon0_out_tve0>; - }; - }; - }; - }; -}; - -&tcon0_out { - tcon0_out_tve0: endpoint@1 { - reg = <1>; - remote-endpoint = <&tve0_in_tcon0>; - }; -}; diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi index a9574a6cd95c..5175f9cc9bed 100644 --- a/arch/arm/boot/dts/sun5i.dtsi +++ b/arch/arm/boot/dts/sun5i.dtsi @@ -46,7 +46,6 @@ #include <dt-bindings/clock/sun5i-ccu.h> #include <dt-bindings/dma/sun4i-a10.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/reset/sun5i-ccu.h> / { @@ -64,6 +63,31 @@ }; }; + chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + framebuffer@0 { + compatible = "allwinner,simple-framebuffer", + "simple-framebuffer"; + allwinner,pipeline = "de_be0-lcd0"; + clocks = <&ccu CLK_AHB_LCD>, <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, + <&ccu CLK_TCON_CH0>, <&ccu CLK_DRAM_DE_BE>; + status = "disabled"; + }; + + framebuffer@1 { + compatible = "allwinner,simple-framebuffer", + "simple-framebuffer"; + allwinner,pipeline = "de_be0-lcd0-tve0"; + clocks = <&ccu CLK_AHB_TVE>, <&ccu CLK_AHB_LCD>, + <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, + <&ccu CLK_TCON_CH1>, <&ccu CLK_DRAM_DE_BE>; + status = "disabled"; + }; + }; + clocks { #address-cells = <1>; #size-cells = <1>; @@ -105,6 +129,12 @@ ranges = <0 0x00000000 0xc000>; }; + emac_sram: sram-section@8000 { + compatible = "allwinner,sun4i-a10-sram-a3-a4"; + reg = <0x8000 0x4000>; + status = "disabled"; + }; + sram_d: sram@00010000 { compatible = "mmio-sram"; reg = <0x00010000 0x1000>; @@ -128,6 +158,19 @@ #dma-cells = <2>; }; + nfc: nand@01c03000 { + compatible = "allwinner,sun4i-a10-nand"; + reg = <0x01c03000 0x1000>; + interrupts = <37>; + clocks = <&ccu CLK_AHB_NAND>, <&ccu CLK_NAND>; + clock-names = "ahb", "mod"; + dmas = <&dma SUN4I_DMA_DEDICATED 3>; + dma-names = "rxtx"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + spi0: spi@01c05000 { compatible = "allwinner,sun4i-a10-spi"; reg = <0x01c05000 0x1000>; @@ -156,6 +199,84 @@ #size-cells = <0>; }; + tve0: tv-encoder@01c0a000 { + compatible = "allwinner,sun4i-a10-tv-encoder"; + reg = <0x01c0a000 0x1000>; + clocks = <&ccu CLK_AHB_TVE>; + resets = <&ccu RST_TVE>; + status = "disabled"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + tve0_in_tcon0: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon0_out_tve0>; + }; + }; + }; + + emac: ethernet@01c0b000 { + compatible = "allwinner,sun4i-a10-emac"; + reg = <0x01c0b000 0x1000>; + interrupts = <55>; + clocks = <&ccu CLK_AHB_EMAC>; + allwinner,sram = <&emac_sram 1>; + status = "disabled"; + }; + + mdio: mdio@01c0b080 { + compatible = "allwinner,sun4i-a10-mdio"; + reg = <0x01c0b080 0x14>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + tcon0: lcd-controller@01c0c000 { + compatible = "allwinner,sun5i-a13-tcon"; + reg = <0x01c0c000 0x1000>; + interrupts = <44>; + resets = <&ccu RST_LCD>; + reset-names = "lcd"; + clocks = <&ccu CLK_AHB_LCD>, + <&ccu CLK_TCON_CH0>, + <&ccu CLK_TCON_CH1>; + clock-names = "ahb", + "tcon-ch0", + "tcon-ch1"; + clock-output-names = "tcon-pixel-clock"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + tcon0_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + tcon0_in_be0: endpoint@0 { + reg = <0>; + remote-endpoint = <&be0_out_tcon0>; + }; + }; + + tcon0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + tcon0_out_tve0: endpoint@1 { + reg = <1>; + remote-endpoint = <&tve0_in_tcon0>; + }; + }; + }; + }; + mmc0: mmc@01c0f000 { compatible = "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; @@ -273,6 +394,15 @@ #interrupt-cells = <3>; #gpio-cells = <3>; + emac_pins_a: emac0@0 { + pins = "PD6", "PD7", "PD10", + "PD11", "PD12", "PD13", "PD14", + "PD15", "PD18", "PD19", "PD20", + "PD21", "PD22", "PD23", "PD24", + "PD25", "PD26", "PD27"; + function = "emac"; + }; + i2c0_pins_a: i2c0@0 { pins = "PB0", "PB1"; function = "i2c0"; @@ -288,6 +418,11 @@ function = "i2c2"; }; + ir0_rx_pins_a: ir0@0 { + pins = "PB4"; + function = "ir0"; + }; + lcd_rgb565_pins: lcd_rgb565@0 { pins = "PD3", "PD4", "PD5", "PD6", "PD7", "PD10", "PD11", "PD12", "PD13", "PD14", "PD15", @@ -296,6 +431,14 @@ function = "lcd0"; }; + lcd_rgb666_pins: lcd_rgb666@0 { + pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", + "PD10", "PD11", "PD12", "PD13", "PD14", "PD15", + "PD18", "PD19", "PD20", "PD21", "PD22", "PD23", + "PD24", "PD25", "PD26", "PD27"; + function = "lcd0"; + }; + mmc0_pins_a: mmc0@0 { pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; @@ -321,6 +464,24 @@ bias-pull-up; }; + nand_pins_a: nand-base0@0 { + pins = "PC0", "PC1", "PC2", + "PC5", "PC8", "PC9", "PC10", + "PC11", "PC12", "PC13", "PC14", + "PC15"; + function = "nand0"; + }; + + nand_cs0_pins_a: nand-cs@0 { + pins = "PC4"; + function = "nand0"; + }; + + nand_rb0_pins_a: nand-rb@0 { + pins = "PC6"; + function = "nand0"; + }; + spi2_pins_a: spi2@0 { pins = "PE1", "PE2", "PE3"; function = "spi2"; @@ -331,12 +492,32 @@ function = "spi2"; }; + uart1_pins_a: uart1@0 { + pins = "PE10", "PE11"; + function = "uart1"; + }; + + uart1_pins_b: uart1@1 { + pins = "PG3", "PG4"; + function = "uart1"; + }; + + uart2_pins_a: uart2@0 { + pins = "PD2", "PD3"; + function = "uart2"; + }; + + uart2_cts_rts_pins_a: uart2-cts-rts@0 { + pins = "PD4", "PD5"; + function = "uart2"; + }; + uart3_pins_a: uart3@0 { pins = "PG9", "PG10"; function = "uart3"; }; - uart3_pins_cts_rts_a: uart3-cts-rts@0 { + uart3_cts_rts_pins_a: uart3-cts-rts@0 { pins = "PG11", "PG12"; function = "uart3"; }; @@ -359,6 +540,15 @@ reg = <0x01c20c90 0x10>; }; + ir0: ir@01c21800 { + compatible = "allwinner,sun4i-a10-ir"; + clocks = <&ccu CLK_APB0_IR>, <&ccu CLK_IR>; + clock-names = "apb", "ir"; + interrupts = <5>; + reg = <0x01c21800 0x40>; + status = "disabled"; + }; + lradc: lradc@01c22800 { compatible = "allwinner,sun4i-a10-lradc-keys"; reg = <0x01c22800 0x100>; @@ -391,6 +581,16 @@ #thermal-sensor-cells = <0>; }; + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; + interrupts = <1>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_APB1_UART0>; + status = "disabled"; + }; + uart1: serial@01c28400 { compatible = "snps,dw-apb-uart"; reg = <0x01c28400 0x400>; @@ -401,6 +601,16 @@ status = "disabled"; }; + uart2: serial@01c28800 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28800 0x400>; + interrupts = <3>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_APB1_UART2>; + status = "disabled"; + }; + uart3: serial@01c28c00 { compatible = "snps,dw-apb-uart"; reg = <0x01c28c00 0x400>; @@ -447,5 +657,75 @@ interrupts = <82>, <83>; clocks = <&ccu CLK_AHB_HSTIMER>; }; + + fe0: display-frontend@01e00000 { + compatible = "allwinner,sun5i-a13-display-frontend"; + reg = <0x01e00000 0x20000>; + interrupts = <47>; + clocks = <&ccu CLK_DE_FE>, <&ccu CLK_DE_FE>, + <&ccu CLK_DRAM_DE_FE>; + clock-names = "ahb", "mod", + "ram"; + resets = <&ccu RST_DE_FE>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + fe0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + fe0_out_be0: endpoint@0 { + reg = <0>; + remote-endpoint = <&be0_in_fe0>; + }; + }; + }; + }; + + be0: display-backend@01e60000 { + compatible = "allwinner,sun5i-a13-display-backend"; + reg = <0x01e60000 0x10000>; + interrupts = <47>; + clocks = <&ccu CLK_AHB_DE_BE>, <&ccu CLK_DE_BE>, + <&ccu CLK_DRAM_DE_BE>; + clock-names = "ahb", "mod", + "ram"; + resets = <&ccu RST_DE_BE>; + status = "disabled"; + + assigned-clocks = <&ccu CLK_DE_BE>; + assigned-clock-rates = <300000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + be0_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + be0_in_fe0: endpoint@0 { + reg = <0>; + remote-endpoint = <&fe0_out_be0>; + }; + }; + + be0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + be0_out_tcon0: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon0_in_be0>; + }; + }; + }; + }; }; }; diff --git a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts index effbdc766938..7f34323a668c 100644 --- a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts +++ b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts @@ -47,7 +47,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Allwinner A31 APP4 EVB1 Evaluation Board"; diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts index f5ececd45bc0..85eff0307ca4 100644 --- a/arch/arm/boot/dts/sun6i-a31-colombus.dts +++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts @@ -47,7 +47,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "WITS A31 Colombus Evaluation Board"; diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts index f094eeb6c499..d4f74f476f25 100644 --- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts +++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts @@ -47,7 +47,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Merrii A31 Hummingbird"; diff --git a/arch/arm/boot/dts/sun6i-a31-i7.dts b/arch/arm/boot/dts/sun6i-a31-i7.dts index 2bc57d2dcd80..010a84c7c012 100644 --- a/arch/arm/boot/dts/sun6i-a31-i7.dts +++ b/arch/arm/boot/dts/sun6i-a31-i7.dts @@ -45,7 +45,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Mele I7 Quad top set box"; diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts index 8af5b667a46d..50605fd4449e 100644 --- a/arch/arm/boot/dts/sun6i-a31-m9.dts +++ b/arch/arm/boot/dts/sun6i-a31-m9.dts @@ -45,7 +45,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Mele M9 top set box"; diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts index bf0f5831126f..5219556e9f73 100644 --- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts +++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts @@ -45,7 +45,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Mele A1000G Quad top set box"; diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index a4b96184cac1..9c999d3788f6 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -48,7 +48,6 @@ #include <dt-bindings/thermal/thermal.h> #include <dt-bindings/clock/sun6i-a31-ccu.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/reset/sun6i-a31-ccu.h> / { diff --git a/arch/arm/boot/dts/sun6i-a31s-cs908.dts b/arch/arm/boot/dts/sun6i-a31s-cs908.dts index 5e8f8c4f2b30..75e578159c3a 100644 --- a/arch/arm/boot/dts/sun6i-a31s-cs908.dts +++ b/arch/arm/boot/dts/sun6i-a31s-cs908.dts @@ -43,8 +43,6 @@ /dts-v1/; #include "sun6i-a31s.dtsi" -#include <dt-bindings/pinctrl/sun4i-a10.h> - / { model = "CSQ CS908 top set box"; compatible = "csq,cs908", "allwinner,sun6i-a31s"; diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts index 2238eda318f6..f3712753fa42 100644 --- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts +++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "MSI Primo81 tablet"; diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi index 4ec0c8679b2e..d7325bc4eeb4 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi +++ b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi @@ -45,7 +45,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Sinlinx SinA31s Core Board"; diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts index 7ff68bdd7109..b3d98222bd81 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts +++ b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts @@ -63,6 +63,23 @@ gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; /* PH13 */ }; }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "On-board SPDIF"; + simple-audio-card,cpu { + sound-dai = <&spdif>; + }; + + simple-audio-card,codec { + sound-dai = <&spdif_out>; + }; + }; + + spdif_out: spdif-out { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dit"; + }; }; &codec { @@ -153,6 +170,12 @@ regulator-name = "vcc-gmac-phy"; }; +&spdif { + pinctrl-names = "default"; + pinctrl-0 = <&spdif_pins_a>; + status = "okay"; +}; + &usb_otg { dr_mode = "peripheral"; status = "okay"; diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts index 3bd862bf82a9..bdfdce8ca6ba 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts +++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts @@ -86,6 +86,10 @@ }; }; +&cpu0 { + cpu-supply = <®_dcdc3>; +}; + &ehci0 { status = "okay"; }; @@ -151,6 +155,17 @@ status = "okay"; }; +&p2wi { + status = "okay"; + + axp22x: pmic@68 { + compatible = "x-powers,axp221"; + reg = <0x68>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + }; +}; + &pio { gmac_phy_reset_pin_bpi_m2: gmac_phy_reset_pin@0 { pins = "PA21"; @@ -176,6 +191,48 @@ }; }; +#include "axp22x.dtsi" + +®_dc5ldo { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1320000>; + regulator-name = "vdd-cpus"; +}; + +®_dcdc1 { + regulator-always-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "vdd-3v0"; +}; + +®_dcdc2 { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1320000>; + regulator-name = "vdd-gpu"; +}; + +®_dcdc3 { + regulator-always-on; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1320000>; + regulator-name = "vdd-cpu"; +}; + +®_dcdc4 { + regulator-always-on; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1320000>; + regulator-name = "vdd-sys-dll"; +}; + +®_dcdc5 { + regulator-always-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-name = "vcc-dram"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts index 154ebf5082ed..f3edf9ca435c 100644 --- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts +++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts @@ -45,7 +45,6 @@ #include "sunxi-common-regulators.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Yones TopTech BS1078 v2 Tablet"; diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi index edaba5f904fd..3cc4046b904a 100644 --- a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi +++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi @@ -44,7 +44,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { aliases { diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts index 91f2e5f9efcb..ed2f35adf542 100644 --- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts +++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "LeMaker Banana Pi"; diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts index 4dc1e10f88c4..a2eab7aa80e0 100644 --- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Cubietech Cubieboard2"; diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts index f019aa3fe96d..102903e83bd2 100644 --- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Cubietech Cubietruck"; @@ -268,6 +267,10 @@ #include "axp209.dtsi" +&ac_power_supply { + status = "okay"; +}; + ®_dcdc2 { regulator-always-on; regulator-min-microvolt = <1000000>; @@ -324,6 +327,10 @@ status = "okay"; }; +&usb_power_supply { + status = "okay"; +}; + &usbphy { pinctrl-names = "default"; pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>; diff --git a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts index e921ba42f170..99c00b9a1546 100644 --- a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts +++ b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Merrii A20 Hummingbird"; diff --git a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts index 385fd8232ae0..4da49717da21 100644 --- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts +++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "I12 / Q5 / QT840A A20 tvbox"; diff --git a/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts index f5b5325a70e2..28d3abbdc2d4 100644 --- a/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts +++ b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "ICnova-A20 SWAC"; diff --git a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts index bbf1c8cbaac6..96bb0bc198ba 100644 --- a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts +++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Lamobo R1"; diff --git a/arch/arm/boot/dts/sun7i-a20-m3.dts b/arch/arm/boot/dts/sun7i-a20-m3.dts index 0e074bd0e8c9..86f69813683e 100644 --- a/arch/arm/boot/dts/sun7i-a20-m3.dts +++ b/arch/arm/boot/dts/sun7i-a20-m3.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Mele M3"; diff --git a/arch/arm/boot/dts/sun7i-a20-mk808c.dts b/arch/arm/boot/dts/sun7i-a20-mk808c.dts index 97d7a8b65a03..c4ee30709f3a 100644 --- a/arch/arm/boot/dts/sun7i-a20-mk808c.dts +++ b/arch/arm/boot/dts/sun7i-a20-mk808c.dts @@ -53,7 +53,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "mk808c"; diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts index a1450c10b08e..1af5b46862cb 100644 --- a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts +++ b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A20-Olimex-SOM-EVB"; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts index 1297432c2802..dcd0f7a0dffa 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts @@ -49,7 +49,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A20-OLinuXino-LIME"; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts index 71cca5360728..e7d45425758c 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A20-OLinuXino-LIME2"; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts index 223fbd9f7c62..def0ad8395bb 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts @@ -49,7 +49,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Olimex A20-Olinuxino Micro"; @@ -85,6 +84,14 @@ status = "okay"; }; +&codec { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <®_dcdc2>; +}; + &ehci0 { status = "okay"; }; @@ -111,13 +118,9 @@ status = "okay"; axp209: pmic@34 { - compatible = "x-powers,axp209"; reg = <0x34>; interrupt-parent = <&nmi_intc>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; - - interrupt-controller; - #interrupt-cells = <1>; }; }; @@ -251,6 +254,29 @@ }; }; +#include "axp209.dtsi" + +®_dcdc2 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-cpu"; +}; + +®_dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-int-dll"; +}; + +®_ldo2 { + regulator-always-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "avcc"; +}; + ®_ahci_5v { status = "okay"; }; diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts index a74265749227..7af4c8fc1865 100644 --- a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts +++ b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Orange Pi Mini"; diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi.dts b/arch/arm/boot/dts/sun7i-a20-orangepi.dts index 3de980c8f8ff..0a8d4a05e8a0 100644 --- a/arch/arm/boot/dts/sun7i-a20-orangepi.dts +++ b/arch/arm/boot/dts/sun7i-a20-orangepi.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Orange Pi"; diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts index 4599f98a3aee..7c96b53b76bf 100644 --- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts +++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "LinkSprite pcDuino3"; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 2db97fc820dd..93aa55970bd7 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -49,7 +49,6 @@ #include <dt-bindings/clock/sun4i-a10-pll2.h> #include <dt-bindings/dma/sun4i-a10.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { interrupt-parent = <&gic>; @@ -1096,6 +1095,11 @@ #interrupt-cells = <3>; #gpio-cells = <3>; + can0_pins_a: can0@0 { + pins = "PH20", "PH21"; + function = "can"; + }; + clk_out_a_pins_a: clk_out_a@0 { pins = "PI12"; function = "clk_out_a"; @@ -1538,6 +1542,22 @@ status = "disabled"; }; + ps20: ps2@01c2a000 { + compatible = "allwinner,sun4i-a10-ps2"; + reg = <0x01c2a000 0x400>; + interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&apb1_gates 6>; + status = "disabled"; + }; + + ps21: ps2@01c2a400 { + compatible = "allwinner,sun4i-a10-ps2"; + reg = <0x01c2a400 0x400>; + interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&apb1_gates 7>; + status = "disabled"; + }; + i2c0: i2c@01c2ac00 { compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c"; @@ -1582,6 +1602,15 @@ #size-cells = <0>; }; + can0: can@01c2bc00 { + compatible = "allwinner,sun7i-a20-can", + "allwinner,sun4i-a10-can"; + reg = <0x01c2bc00 0x400>; + interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&apb1_gates 4>; + status = "disabled"; + }; + i2c4: i2c@01c2c000 { compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c"; @@ -1629,20 +1658,5 @@ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; }; - ps20: ps2@01c2a000 { - compatible = "allwinner,sun4i-a10-ps2"; - reg = <0x01c2a000 0x400>; - interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&apb1_gates 6>; - status = "disabled"; - }; - - ps21: ps2@01c2a400 { - compatible = "allwinner,sun4i-a10-ps2"; - reg = <0x01c2a400 0x400>; - interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&apb1_gates 7>; - status = "disabled"; - }; }; }; diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi index 8a3ed21cb7bc..a8b978d0f35b 100644 --- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi +++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi @@ -47,7 +47,6 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/clock/sun8i-a23-a33-ccu.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include <dt-bindings/reset/sun8i-a23-a33-ccu.h> / { @@ -493,6 +492,7 @@ clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>; clock-names = "bus", "core"; resets = <&ccu RST_BUS_GPU>; + #cooling-cells = <2>; assigned-clocks = <&ccu CLK_GPU>; assigned-clock-rates = <384000000>; diff --git a/arch/arm/boot/dts/sun8i-a23-evb.dts b/arch/arm/boot/dts/sun8i-a23-evb.dts index c21f5b1b255e..87289a60c520 100644 --- a/arch/arm/boot/dts/sun8i-a23-evb.dts +++ b/arch/arm/boot/dts/sun8i-a23-evb.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Allwinner A23 Evaluation Board"; diff --git a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts index 3ab5c0c09d93..b6958e8f2f01 100644 --- a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts +++ b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts @@ -50,7 +50,6 @@ }; &codec { - pinctrl-0 = <&codec_pa_pin>; allwinner,pa-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */ allwinner,audio-routing = "Headphone", "HP", @@ -62,12 +61,3 @@ "Headset Mic", "HBIAS"; status = "okay"; }; - -&pio { - codec_pa_pin: codec_pa_pin@0 { - allwinner,pins = "PH9"; - allwinner,function = "gpio_out"; - allwinner,drive = <SUN4I_PINCTRL_10_MA>; - allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; - }; -}; diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts index 03b89bdd55ba..9b620cc1d5f1 100644 --- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts +++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts @@ -48,7 +48,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Sinlinx SinA33"; @@ -84,6 +83,24 @@ status = "okay"; }; +&cpu0 { + cpu-supply = <®_dcdc3>; +}; + +&cpu0_opp_table { + opp@1104000000 { + opp-hz = /bits/ 64 <1104000000>; + opp-microvolt = <1320000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1320000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; +}; + &de { status = "okay"; }; @@ -175,6 +192,10 @@ #include "axp223.dtsi" +&ac_power_supply { + status = "okay"; +}; + ®_aldo1 { regulator-always-on; regulator-min-microvolt = <3000000>; diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi index 306af6cadf26..013978259372 100644 --- a/arch/arm/boot/dts/sun8i-a33.dtsi +++ b/arch/arm/boot/dts/sun8i-a33.dtsi @@ -43,24 +43,79 @@ */ #include "sun8i-a23-a33.dtsi" +#include <dt-bindings/thermal/thermal.h> / { cpu0_opp_table: opp_table0 { compatible = "operating-points-v2"; opp-shared; + opp@120000000 { + opp-hz = /bits/ 64 <120000000>; + opp-microvolt = <1040000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@240000000 { + opp-hz = /bits/ 64 <240000000>; + opp-microvolt = <1040000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@312000000 { + opp-hz = /bits/ 64 <312000000>; + opp-microvolt = <1040000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <1040000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <1040000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@504000000 { + opp-hz = /bits/ 64 <504000000>; + opp-microvolt = <1040000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <1040000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + opp@648000000 { opp-hz = /bits/ 64 <648000000>; opp-microvolt = <1040000>; clock-latency-ns = <244144>; /* 8 32k periods */ }; + opp@720000000 { + opp-hz = /bits/ 64 <720000000>; + opp-microvolt = <1100000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + opp@816000000 { opp-hz = /bits/ 64 <816000000>; opp-microvolt = <1100000>; clock-latency-ns = <244144>; /* 8 32k periods */ }; + opp@912000000 { + opp-hz = /bits/ 64 <912000000>; + opp-microvolt = <1200000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + opp@1008000000 { opp-hz = /bits/ 64 <1008000000>; opp-microvolt = <1200000>; @@ -73,6 +128,7 @@ clocks = <&ccu CLK_CPUX>; clock-names = "cpu"; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; cpu@1 { @@ -100,6 +156,27 @@ status = "disabled"; }; + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&ths>; + }; + + mali_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp@144000000 { + opp-hz = /bits/ 64 <144000000>; + }; + + opp@240000000 { + opp-hz = /bits/ 64 <240000000>; + }; + + opp@384000000 { + opp-hz = /bits/ 64 <384000000>; + }; + }; + memory { reg = <0x40000000 0x80000000>; }; @@ -196,6 +273,13 @@ status = "disabled"; }; + ths: ths@01c25000 { + compatible = "allwinner,sun8i-a33-ths"; + reg = <0x01c25000 0x100>; + #thermal-sensor-cells = <0>; + #io-channel-cells = <0>; + }; + fe0: display-frontend@01e00000 { compatible = "allwinner,sun8i-a33-display-frontend"; reg = <0x01e00000 0x20000>; @@ -306,12 +390,83 @@ }; }; }; + + thermal-zones { + cpu_thermal { + /* milliseconds */ + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&ths>; + + cooling-maps { + map0 { + trip = <&cpu_alert0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu_alert1>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + + map2 { + trip = <&gpu_alert0>; + cooling-device = <&mali 1 THERMAL_NO_LIMIT>; + }; + + map3 { + trip = <&gpu_alert1>; + cooling-device = <&mali 2 THERMAL_NO_LIMIT>; + }; + }; + + trips { + cpu_alert0: cpu_alert0 { + /* milliCelsius */ + temperature = <75000>; + hysteresis = <2000>; + type = "passive"; + }; + + gpu_alert0: gpu_alert0 { + /* milliCelsius */ + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_alert1: cpu_alert1 { + /* milliCelsius */ + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpu_alert1: gpu_alert1 { + /* milliCelsius */ + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpu_crit: cpu_crit { + /* milliCelsius */ + temperature = <110000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; }; &ccu { compatible = "allwinner,sun8i-a33-ccu"; }; +&mali { + operating-points-v2 = <&mali_opp_table>; +}; + &pio { compatible = "allwinner,sun8i-a33-pinctrl"; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>, diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi index a789a7caf217..0ec143773ee9 100644 --- a/arch/arm/boot/dts/sun8i-a83t.dtsi +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi @@ -47,8 +47,6 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> - / { interrupt-parent = <&gic>; diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts index b7ca916d871d..9e8b082c134f 100644 --- a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts +++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts @@ -49,7 +49,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Xunlong Orange Pi Zero"; @@ -96,6 +95,10 @@ }; }; +&ehci0 { + status = "okay"; +}; + &ehci1 { status = "okay"; }; @@ -132,6 +135,10 @@ bias-pull-up; }; +&ohci0 { + status = "okay"; +}; + &ohci1 { status = "okay"; }; @@ -154,7 +161,17 @@ status = "disabled"; }; +&usb_otg { + dr_mode = "peripheral"; + status = "okay"; +}; + &usbphy { - /* USB VBUS is always on */ + /* + * USB Type-A port VBUS is always on. However, MicroUSB VBUS can only + * power up the board; when it's used as OTG port, this VBUS is + * always off even if the board is powered via GPIO pins. + */ status = "okay"; + usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */ }; diff --git a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts index c0c49dd4d3b2..52acbe111cad 100644 --- a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts +++ b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Banana Pi BPI-M2-Plus"; diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts index 25b225b7dfd6..e7fae65eb5d3 100644 --- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts +++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Beelink X2"; @@ -138,6 +137,16 @@ }; }; +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_8bit_pins>; + vmmc-supply = <®_vcc3v3>; + bus-width = <8>; + non-removable; + cap-mmc-hw-reset; + status = "okay"; +}; + &ohci1 { status = "okay"; }; diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts new file mode 100644 index 000000000000..03ff6f8b93ff --- /dev/null +++ b/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 Jelle van der Waa <jelle@vdwaa.nl> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "sun8i-h3.dtsi" +#include "sunxi-common-regulators.dtsi" + +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "FriendlyARM NanoPi NEO Air"; + compatible = "friendlyarm,nanopi-neo-air", "allwinner,sun8i-h3"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + pwr { + label = "nanopi:green:pwr"; + gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ + default-state = "on"; + }; + + status { + label = "nanopi:blue:status"; + gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */ + }; + }; +}; + +&mmc0 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>; + vmmc-supply = <®_vcc3v3>; + bus-width = <4>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ + cd-inverted; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_a>; + status = "okay"; +}; + +&usbphy { + /* USB VBUS is always on */ + status = "okay"; +}; diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi b/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi index 2216e68d1838..c6decee41a27 100644 --- a/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi +++ b/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi @@ -47,7 +47,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { aliases { diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts index 047e9e1c6093..5b6d14555b7c 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Xunlong Orange Pi 2"; diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts index 22b99b407019..9b47a0def740 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Xunlong Orange Pi Lite"; diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts index 34da853ee037..5fea430e0eb1 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Xunlong Orange Pi One"; @@ -90,6 +89,10 @@ }; }; +&ehci0 { + status = "okay"; +}; + &ehci1 { status = "okay"; }; @@ -104,6 +107,10 @@ status = "okay"; }; +&ohci0 { + status = "okay"; +}; + &ohci1 { status = "okay"; }; @@ -127,6 +134,11 @@ }; }; +®_usb0_vbus { + gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */ + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; @@ -151,7 +163,14 @@ status = "disabled"; }; +&usb_otg { + dr_mode = "otg"; + status = "okay"; +}; + &usbphy { - /* USB VBUS is always on */ + /* USB Type-A port's VBUS is always on */ + usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */ + usb0_vbus-supply = <®_usb0_vbus>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts index d43978d3294e..f148111c326d 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts @@ -46,7 +46,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Xunlong Orange Pi PC"; diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi index 27780b97c863..b36f9f423c39 100644 --- a/arch/arm/boot/dts/sun8i-h3.dtsi +++ b/arch/arm/boot/dts/sun8i-h3.dtsi @@ -40,16 +40,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include "skeleton.dtsi" - -#include <dt-bindings/clock/sun8i-h3-ccu.h> -#include <dt-bindings/interrupt-controller/arm-gic.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> -#include <dt-bindings/reset/sun8i-h3-ccu.h> +#include "sunxi-h3-h5.dtsi" / { - interrupt-parent = <&gic>; - cpus { #address-cells = <1>; #size-cells = <0>; @@ -86,563 +79,48 @@ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; }; +}; - clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - osc24M: osc24M_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - clock-output-names = "osc24M"; - }; - - osc32k: osc32k_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <32768>; - clock-output-names = "osc32k"; - }; - - apb0: apb0_clk { - compatible = "fixed-factor-clock"; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - clocks = <&osc24M>; - clock-output-names = "apb0"; - }; - - apb0_gates: clk@01f01428 { - compatible = "allwinner,sun8i-h3-apb0-gates-clk", - "allwinner,sun4i-a10-gates-clk"; - reg = <0x01f01428 0x4>; - #clock-cells = <1>; - clocks = <&apb0>; - clock-indices = <0>, <1>; - clock-output-names = "apb0_pio", "apb0_ir"; - }; - - ir_clk: ir_clk@01f01454 { - compatible = "allwinner,sun4i-a10-mod0-clk"; - reg = <0x01f01454 0x4>; - #clock-cells = <0>; - clocks = <&osc32k>, <&osc24M>; - clock-output-names = "ir"; - }; - }; - - soc { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - dma: dma-controller@01c02000 { - compatible = "allwinner,sun8i-h3-dma"; - reg = <0x01c02000 0x1000>; - interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_DMA>; - resets = <&ccu RST_BUS_DMA>; - #dma-cells = <1>; - }; - - mmc0: mmc@01c0f000 { - compatible = "allwinner,sun7i-a20-mmc"; - reg = <0x01c0f000 0x1000>; - clocks = <&ccu CLK_BUS_MMC0>, - <&ccu CLK_MMC0>, - <&ccu CLK_MMC0_OUTPUT>, - <&ccu CLK_MMC0_SAMPLE>; - clock-names = "ahb", - "mmc", - "output", - "sample"; - resets = <&ccu RST_BUS_MMC0>; - reset-names = "ahb"; - interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - mmc1: mmc@01c10000 { - compatible = "allwinner,sun7i-a20-mmc"; - reg = <0x01c10000 0x1000>; - clocks = <&ccu CLK_BUS_MMC1>, - <&ccu CLK_MMC1>, - <&ccu CLK_MMC1_OUTPUT>, - <&ccu CLK_MMC1_SAMPLE>; - clock-names = "ahb", - "mmc", - "output", - "sample"; - resets = <&ccu RST_BUS_MMC1>; - reset-names = "ahb"; - interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - mmc2: mmc@01c11000 { - compatible = "allwinner,sun7i-a20-mmc"; - reg = <0x01c11000 0x1000>; - clocks = <&ccu CLK_BUS_MMC2>, - <&ccu CLK_MMC2>, - <&ccu CLK_MMC2_OUTPUT>, - <&ccu CLK_MMC2_SAMPLE>; - clock-names = "ahb", - "mmc", - "output", - "sample"; - resets = <&ccu RST_BUS_MMC2>; - reset-names = "ahb"; - interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - usbphy: phy@01c19400 { - compatible = "allwinner,sun8i-h3-usb-phy"; - reg = <0x01c19400 0x2c>, - <0x01c1a800 0x4>, - <0x01c1b800 0x4>, - <0x01c1c800 0x4>, - <0x01c1d800 0x4>; - reg-names = "phy_ctrl", - "pmu0", - "pmu1", - "pmu2", - "pmu3"; - clocks = <&ccu CLK_USB_PHY0>, - <&ccu CLK_USB_PHY1>, - <&ccu CLK_USB_PHY2>, - <&ccu CLK_USB_PHY3>; - clock-names = "usb0_phy", - "usb1_phy", - "usb2_phy", - "usb3_phy"; - resets = <&ccu RST_USB_PHY0>, - <&ccu RST_USB_PHY1>, - <&ccu RST_USB_PHY2>, - <&ccu RST_USB_PHY3>; - reset-names = "usb0_reset", - "usb1_reset", - "usb2_reset", - "usb3_reset"; - status = "disabled"; - #phy-cells = <1>; - }; - - ehci1: usb@01c1b000 { - compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; - reg = <0x01c1b000 0x100>; - interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>; - resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; - phys = <&usbphy 1>; - phy-names = "usb"; - status = "disabled"; - }; - - ohci1: usb@01c1b400 { - compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; - reg = <0x01c1b400 0x100>; - interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>, - <&ccu CLK_USB_OHCI1>; - resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; - phys = <&usbphy 1>; - phy-names = "usb"; - status = "disabled"; - }; - - ehci2: usb@01c1c000 { - compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; - reg = <0x01c1c000 0x100>; - interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>; - resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; - phys = <&usbphy 2>; - phy-names = "usb"; - status = "disabled"; - }; - - ohci2: usb@01c1c400 { - compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; - reg = <0x01c1c400 0x100>; - interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>, - <&ccu CLK_USB_OHCI2>; - resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; - phys = <&usbphy 2>; - phy-names = "usb"; - status = "disabled"; - }; - - ehci3: usb@01c1d000 { - compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; - reg = <0x01c1d000 0x100>; - interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>; - resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; - phys = <&usbphy 3>; - phy-names = "usb"; - status = "disabled"; - }; - - ohci3: usb@01c1d400 { - compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; - reg = <0x01c1d400 0x100>; - interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>, - <&ccu CLK_USB_OHCI3>; - resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; - phys = <&usbphy 3>; - phy-names = "usb"; - status = "disabled"; - }; - - ccu: clock@01c20000 { - compatible = "allwinner,sun8i-h3-ccu"; - reg = <0x01c20000 0x400>; - clocks = <&osc24M>, <&osc32k>; - clock-names = "hosc", "losc"; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - pio: pinctrl@01c20800 { - compatible = "allwinner,sun8i-h3-pinctrl"; - reg = <0x01c20800 0x400>; - interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>; - clock-names = "apb", "hosc", "losc"; - gpio-controller; - #gpio-cells = <3>; - interrupt-controller; - #interrupt-cells = <3>; - - i2c0_pins: i2c0 { - pins = "PA11", "PA12"; - function = "i2c0"; - }; - - i2c1_pins: i2c1 { - pins = "PA18", "PA19"; - function = "i2c1"; - }; - - i2c2_pins: i2c2 { - pins = "PE12", "PE13"; - function = "i2c2"; - }; - - mmc0_pins_a: mmc0@0 { - pins = "PF0", "PF1", "PF2", "PF3", - "PF4", "PF5"; - function = "mmc0"; - drive-strength = <30>; - bias-pull-up; - }; - - mmc0_cd_pin: mmc0_cd_pin@0 { - pins = "PF6"; - function = "gpio_in"; - bias-pull-up; - }; - - mmc1_pins_a: mmc1@0 { - pins = "PG0", "PG1", "PG2", "PG3", - "PG4", "PG5"; - function = "mmc1"; - drive-strength = <30>; - bias-pull-up; - }; - - mmc2_8bit_pins: mmc2_8bit { - pins = "PC5", "PC6", "PC8", - "PC9", "PC10", "PC11", - "PC12", "PC13", "PC14", - "PC15", "PC16"; - function = "mmc2"; - drive-strength = <30>; - bias-pull-up; - }; - - spdif_tx_pins_a: spdif@0 { - pins = "PA17"; - function = "spdif"; - }; - - spi0_pins: spi0 { - pins = "PC0", "PC1", "PC2", "PC3"; - function = "spi0"; - }; - - spi1_pins: spi1 { - pins = "PA15", "PA16", "PA14", "PA13"; - function = "spi1"; - }; - - uart0_pins_a: uart0@0 { - pins = "PA4", "PA5"; - function = "uart0"; - }; - - uart1_pins: uart1 { - pins = "PG6", "PG7"; - function = "uart1"; - }; - - uart1_rts_cts_pins: uart1_rts_cts { - pins = "PG8", "PG9"; - function = "uart1"; - }; - - uart2_pins: uart2 { - pins = "PA0", "PA1"; - function = "uart2"; - }; - - uart3_pins: uart3 { - pins = "PA13", "PA14"; - function = "uart3"; - }; - }; - - timer@01c20c00 { - compatible = "allwinner,sun4i-a10-timer"; - reg = <0x01c20c00 0xa0>; - interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc24M>; - }; - - spi0: spi@01c68000 { - compatible = "allwinner,sun8i-h3-spi"; - reg = <0x01c68000 0x1000>; - interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>; - clock-names = "ahb", "mod"; - dmas = <&dma 23>, <&dma 23>; - dma-names = "rx", "tx"; - pinctrl-names = "default"; - pinctrl-0 = <&spi0_pins>; - resets = <&ccu RST_BUS_SPI0>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - spi1: spi@01c69000 { - compatible = "allwinner,sun8i-h3-spi"; - reg = <0x01c69000 0x1000>; - interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>; - clock-names = "ahb", "mod"; - dmas = <&dma 24>, <&dma 24>; - dma-names = "rx", "tx"; - pinctrl-names = "default"; - pinctrl-0 = <&spi1_pins>; - resets = <&ccu RST_BUS_SPI1>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - wdt0: watchdog@01c20ca0 { - compatible = "allwinner,sun6i-a31-wdt"; - reg = <0x01c20ca0 0x20>; - interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; - }; - - spdif: spdif@01c21000 { - #sound-dai-cells = <0>; - compatible = "allwinner,sun8i-h3-spdif"; - reg = <0x01c21000 0x400>; - interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>; - resets = <&ccu RST_BUS_SPDIF>; - clock-names = "apb", "spdif"; - dmas = <&dma 2>; - dma-names = "tx"; - status = "disabled"; - }; - - pwm: pwm@01c21400 { - compatible = "allwinner,sun8i-h3-pwm"; - reg = <0x01c21400 0x8>; - clocks = <&osc24M>; - #pwm-cells = <3>; - status = "disabled"; - }; - - codec: codec@01c22c00 { - #sound-dai-cells = <0>; - compatible = "allwinner,sun8i-h3-codec"; - reg = <0x01c22c00 0x400>; - interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; - clock-names = "apb", "codec"; - resets = <&ccu RST_BUS_CODEC>; - dmas = <&dma 15>, <&dma 15>; - dma-names = "rx", "tx"; - allwinner,codec-analog-controls = <&codec_analog>; - status = "disabled"; - }; - - uart0: serial@01c28000 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28000 0x400>; - interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_BUS_UART0>; - resets = <&ccu RST_BUS_UART0>; - dmas = <&dma 6>, <&dma 6>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - uart1: serial@01c28400 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28400 0x400>; - interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_BUS_UART1>; - resets = <&ccu RST_BUS_UART1>; - dmas = <&dma 7>, <&dma 7>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - uart2: serial@01c28800 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28800 0x400>; - interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_BUS_UART2>; - resets = <&ccu RST_BUS_UART2>; - dmas = <&dma 8>, <&dma 8>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - uart3: serial@01c28c00 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28c00 0x400>; - interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&ccu CLK_BUS_UART3>; - resets = <&ccu RST_BUS_UART3>; - dmas = <&dma 9>, <&dma 9>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2c0: i2c@01c2ac00 { - compatible = "allwinner,sun6i-a31-i2c"; - reg = <0x01c2ac00 0x400>; - interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_I2C0>; - resets = <&ccu RST_BUS_I2C0>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pins>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - i2c1: i2c@01c2b000 { - compatible = "allwinner,sun6i-a31-i2c"; - reg = <0x01c2b000 0x400>; - interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_I2C1>; - resets = <&ccu RST_BUS_I2C1>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c1_pins>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - i2c2: i2c@01c2b400 { - compatible = "allwinner,sun6i-a31-i2c"; - reg = <0x01c2b000 0x400>; - interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_I2C2>; - resets = <&ccu RST_BUS_I2C2>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c2_pins>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - gic: interrupt-controller@01c81000 { - compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; - reg = <0x01c81000 0x1000>, - <0x01c82000 0x2000>, - <0x01c84000 0x2000>, - <0x01c86000 0x2000>; - interrupt-controller; - #interrupt-cells = <3>; - interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; - }; - - rtc: rtc@01f00000 { - compatible = "allwinner,sun6i-a31-rtc"; - reg = <0x01f00000 0x54>; - interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; - }; - - apb0_reset: reset@01f014b0 { - reg = <0x01f014b0 0x4>; - compatible = "allwinner,sun6i-a31-clock-reset"; - #reset-cells = <1>; - }; +&ccu { + compatible = "allwinner,sun8i-h3-ccu"; +}; - codec_analog: codec-analog@01f015c0 { - compatible = "allwinner,sun8i-h3-codec-analog"; - reg = <0x01f015c0 0x4>; - }; +&mmc0 { + compatible = "allwinner,sun7i-a20-mmc"; + clocks = <&ccu CLK_BUS_MMC0>, + <&ccu CLK_MMC0>, + <&ccu CLK_MMC0_OUTPUT>, + <&ccu CLK_MMC0_SAMPLE>; + clock-names = "ahb", + "mmc", + "output", + "sample"; +}; - ir: ir@01f02000 { - compatible = "allwinner,sun5i-a13-ir"; - clocks = <&apb0_gates 1>, <&ir_clk>; - clock-names = "apb", "ir"; - resets = <&apb0_reset 1>; - interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x01f02000 0x40>; - status = "disabled"; - }; +&mmc1 { + compatible = "allwinner,sun7i-a20-mmc"; + clocks = <&ccu CLK_BUS_MMC1>, + <&ccu CLK_MMC1>, + <&ccu CLK_MMC1_OUTPUT>, + <&ccu CLK_MMC1_SAMPLE>; + clock-names = "ahb", + "mmc", + "output", + "sample"; +}; - r_pio: pinctrl@01f02c00 { - compatible = "allwinner,sun8i-h3-r-pinctrl"; - reg = <0x01f02c00 0x400>; - interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&apb0_gates 0>, <&osc24M>, <&osc32k>; - clock-names = "apb", "hosc", "losc"; - resets = <&apb0_reset 0>; - gpio-controller; - #gpio-cells = <3>; - interrupt-controller; - #interrupt-cells = <3>; +&mmc2 { + compatible = "allwinner,sun7i-a20-mmc"; + clocks = <&ccu CLK_BUS_MMC2>, + <&ccu CLK_MMC2>, + <&ccu CLK_MMC2_OUTPUT>, + <&ccu CLK_MMC2_SAMPLE>; + clock-names = "ahb", + "mmc", + "output", + "sample"; +}; - ir_pins_a: ir@0 { - pins = "PL11"; - function = "s_cir_rx"; - }; - }; - }; +&pio { + compatible = "allwinner,sun8i-h3-pinctrl"; }; diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts index 9112a200fd5e..3741ac71c3d6 100644 --- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts +++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts @@ -47,7 +47,6 @@ #include "sun9i-a80.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Cubietech Cubieboard4"; diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts index 0fc3a87f5576..85f1ad670310 100644 --- a/arch/arm/boot/dts/sun9i-a80-optimus.dts +++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts @@ -46,7 +46,6 @@ #include "sun9i-a80.dtsi" #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> / { model = "Merrii A80 Optimus Board"; diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi index 15b6d122f878..759a72317eb8 100644 --- a/arch/arm/boot/dts/sun9i-a80.dtsi +++ b/arch/arm/boot/dts/sun9i-a80.dtsi @@ -46,8 +46,6 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> - #include <dt-bindings/clock/sun9i-a80-ccu.h> #include <dt-bindings/clock/sun9i-a80-de.h> #include <dt-bindings/clock/sun9i-a80-usb.h> diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi index 17c09fed9e84..ce5c53e4452f 100644 --- a/arch/arm/boot/dts/sunxi-common-regulators.dtsi +++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi @@ -43,7 +43,6 @@ */ #include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> &pio { ahci_pwr_pin_a: ahci_pwr_pin@0 { diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi new file mode 100644 index 000000000000..1aeeacb3a884 --- /dev/null +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/clock/sun8i-h3-ccu.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/reset/sun8i-h3-ccu.h> + +/ { + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + + osc32k: osc32k_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "osc32k"; + }; + + iosc: internal-osc-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16000000>; + clock-accuracy = <300000000>; + clock-output-names = "iosc"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dma: dma-controller@01c02000 { + compatible = "allwinner,sun8i-h3-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_DMA>; + resets = <&ccu RST_BUS_DMA>; + #dma-cells = <1>; + }; + + mmc0: mmc@01c0f000 { + /* compatible and clocks are in per SoC .dtsi file */ + reg = <0x01c0f000 0x1000>; + resets = <&ccu RST_BUS_MMC0>; + reset-names = "ahb"; + interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc1: mmc@01c10000 { + /* compatible and clocks are in per SoC .dtsi file */ + reg = <0x01c10000 0x1000>; + resets = <&ccu RST_BUS_MMC1>; + reset-names = "ahb"; + interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc2: mmc@01c11000 { + /* compatible and clocks are in per SoC .dtsi file */ + reg = <0x01c11000 0x1000>; + resets = <&ccu RST_BUS_MMC2>; + reset-names = "ahb"; + interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + usb_otg: usb@01c19000 { + compatible = "allwinner,sun8i-h3-musb"; + reg = <0x01c19000 0x400>; + clocks = <&ccu CLK_BUS_OTG>; + resets = <&ccu RST_BUS_OTG>; + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "mc"; + phys = <&usbphy 0>; + phy-names = "usb"; + extcon = <&usbphy 0>; + status = "disabled"; + }; + + usbphy: phy@01c19400 { + compatible = "allwinner,sun8i-h3-usb-phy"; + reg = <0x01c19400 0x2c>, + <0x01c1a800 0x4>, + <0x01c1b800 0x4>, + <0x01c1c800 0x4>, + <0x01c1d800 0x4>; + reg-names = "phy_ctrl", + "pmu0", + "pmu1", + "pmu2", + "pmu3"; + clocks = <&ccu CLK_USB_PHY0>, + <&ccu CLK_USB_PHY1>, + <&ccu CLK_USB_PHY2>, + <&ccu CLK_USB_PHY3>; + clock-names = "usb0_phy", + "usb1_phy", + "usb2_phy", + "usb3_phy"; + resets = <&ccu RST_USB_PHY0>, + <&ccu RST_USB_PHY1>, + <&ccu RST_USB_PHY2>, + <&ccu RST_USB_PHY3>; + reset-names = "usb0_reset", + "usb1_reset", + "usb2_reset", + "usb3_reset"; + status = "disabled"; + #phy-cells = <1>; + }; + + ehci0: usb@01c1a000 { + compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; + reg = <0x01c1a000 0x100>; + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>; + resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>; + status = "disabled"; + }; + + ohci0: usb@01c1a400 { + compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; + reg = <0x01c1a400 0x100>; + interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>, + <&ccu CLK_USB_OHCI0>; + resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>; + status = "disabled"; + }; + + ehci1: usb@01c1b000 { + compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; + reg = <0x01c1b000 0x100>; + interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>; + resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; + phys = <&usbphy 1>; + phy-names = "usb"; + status = "disabled"; + }; + + ohci1: usb@01c1b400 { + compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; + reg = <0x01c1b400 0x100>; + interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>, + <&ccu CLK_USB_OHCI1>; + resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; + phys = <&usbphy 1>; + phy-names = "usb"; + status = "disabled"; + }; + + ehci2: usb@01c1c000 { + compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; + reg = <0x01c1c000 0x100>; + interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>; + resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; + phys = <&usbphy 2>; + phy-names = "usb"; + status = "disabled"; + }; + + ohci2: usb@01c1c400 { + compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; + reg = <0x01c1c400 0x100>; + interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>, + <&ccu CLK_USB_OHCI2>; + resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; + phys = <&usbphy 2>; + phy-names = "usb"; + status = "disabled"; + }; + + ehci3: usb@01c1d000 { + compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; + reg = <0x01c1d000 0x100>; + interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>; + resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; + phys = <&usbphy 3>; + phy-names = "usb"; + status = "disabled"; + }; + + ohci3: usb@01c1d400 { + compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; + reg = <0x01c1d400 0x100>; + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>, + <&ccu CLK_USB_OHCI3>; + resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; + phys = <&usbphy 3>; + phy-names = "usb"; + status = "disabled"; + }; + + ccu: clock@01c20000 { + /* compatible is in per SoC .dtsi file */ + reg = <0x01c20000 0x400>; + clocks = <&osc24M>, <&osc32k>; + clock-names = "hosc", "losc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + pio: pinctrl@01c20800 { + /* compatible is in per SoC .dtsi file */ + reg = <0x01c20800 0x400>; + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + + i2c0_pins: i2c0 { + pins = "PA11", "PA12"; + function = "i2c0"; + }; + + i2c1_pins: i2c1 { + pins = "PA18", "PA19"; + function = "i2c1"; + }; + + i2c2_pins: i2c2 { + pins = "PE12", "PE13"; + function = "i2c2"; + }; + + mmc0_pins_a: mmc0@0 { + pins = "PF0", "PF1", "PF2", "PF3", + "PF4", "PF5"; + function = "mmc0"; + drive-strength = <30>; + bias-pull-up; + }; + + mmc0_cd_pin: mmc0_cd_pin@0 { + pins = "PF6"; + function = "gpio_in"; + bias-pull-up; + }; + + mmc1_pins_a: mmc1@0 { + pins = "PG0", "PG1", "PG2", "PG3", + "PG4", "PG5"; + function = "mmc1"; + drive-strength = <30>; + bias-pull-up; + }; + + mmc2_8bit_pins: mmc2_8bit { + pins = "PC5", "PC6", "PC8", + "PC9", "PC10", "PC11", + "PC12", "PC13", "PC14", + "PC15", "PC16"; + function = "mmc2"; + drive-strength = <30>; + bias-pull-up; + }; + + spdif_tx_pins_a: spdif@0 { + pins = "PA17"; + function = "spdif"; + }; + + spi0_pins: spi0 { + pins = "PC0", "PC1", "PC2", "PC3"; + function = "spi0"; + }; + + spi1_pins: spi1 { + pins = "PA15", "PA16", "PA14", "PA13"; + function = "spi1"; + }; + + uart0_pins_a: uart0@0 { + pins = "PA4", "PA5"; + function = "uart0"; + }; + + uart1_pins: uart1 { + pins = "PG6", "PG7"; + function = "uart1"; + }; + + uart1_rts_cts_pins: uart1_rts_cts { + pins = "PG8", "PG9"; + function = "uart1"; + }; + + uart2_pins: uart2 { + pins = "PA0", "PA1"; + function = "uart2"; + }; + + uart3_pins: uart3 { + pins = "PA13", "PA14"; + function = "uart3"; + }; + }; + + timer@01c20c00 { + compatible = "allwinner,sun4i-a10-timer"; + reg = <0x01c20c00 0xa0>; + interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc24M>; + }; + + spi0: spi@01c68000 { + compatible = "allwinner,sun8i-h3-spi"; + reg = <0x01c68000 0x1000>; + interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>; + clock-names = "ahb", "mod"; + dmas = <&dma 23>, <&dma 23>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; + resets = <&ccu RST_BUS_SPI0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi1: spi@01c69000 { + compatible = "allwinner,sun8i-h3-spi"; + reg = <0x01c69000 0x1000>; + interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>; + clock-names = "ahb", "mod"; + dmas = <&dma 24>, <&dma 24>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; + resets = <&ccu RST_BUS_SPI1>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + wdt0: watchdog@01c20ca0 { + compatible = "allwinner,sun6i-a31-wdt"; + reg = <0x01c20ca0 0x20>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + }; + + spdif: spdif@01c21000 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-h3-spdif"; + reg = <0x01c21000 0x400>; + interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>; + resets = <&ccu RST_BUS_SPDIF>; + clock-names = "apb", "spdif"; + dmas = <&dma 2>; + dma-names = "tx"; + status = "disabled"; + }; + + pwm: pwm@01c21400 { + compatible = "allwinner,sun8i-h3-pwm"; + reg = <0x01c21400 0x8>; + clocks = <&osc24M>; + #pwm-cells = <3>; + status = "disabled"; + }; + + codec: codec@01c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-h3-codec"; + reg = <0x01c22c00 0x400>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "apb", "codec"; + resets = <&ccu RST_BUS_CODEC>; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; + allwinner,codec-analog-controls = <&codec_analog>; + status = "disabled"; + }; + + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART0>; + resets = <&ccu RST_BUS_UART0>; + dmas = <&dma 6>, <&dma 6>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart1: serial@01c28400 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28400 0x400>; + interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART1>; + resets = <&ccu RST_BUS_UART1>; + dmas = <&dma 7>, <&dma 7>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart2: serial@01c28800 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28800 0x400>; + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART2>; + resets = <&ccu RST_BUS_UART2>; + dmas = <&dma 8>, <&dma 8>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart3: serial@01c28c00 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28c00 0x400>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART3>; + resets = <&ccu RST_BUS_UART3>; + dmas = <&dma 9>, <&dma 9>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + i2c0: i2c@01c2ac00 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2ac00 0x400>; + interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C0>; + resets = <&ccu RST_BUS_I2C0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c1: i2c@01c2b000 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2b000 0x400>; + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C1>; + resets = <&ccu RST_BUS_I2C1>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@01c2b400 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2b000 0x400>; + interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C2>; + resets = <&ccu RST_BUS_I2C2>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + gic: interrupt-controller@01c81000 { + compatible = "arm,gic-400"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x2000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + + rtc: rtc@01f00000 { + compatible = "allwinner,sun6i-a31-rtc"; + reg = <0x01f00000 0x54>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; + }; + + r_ccu: clock@1f01400 { + compatible = "allwinner,sun50i-a64-r-ccu"; + reg = <0x01f01400 0x100>; + clocks = <&osc24M>, <&osc32k>, <&iosc>; + clock-names = "hosc", "losc", "iosc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + codec_analog: codec-analog@01f015c0 { + compatible = "allwinner,sun8i-h3-codec-analog"; + reg = <0x01f015c0 0x4>; + }; + + ir: ir@01f02000 { + compatible = "allwinner,sun5i-a13-ir"; + clocks = <&r_ccu 4>, <&r_ccu 11>; + clock-names = "apb", "ir"; + resets = <&r_ccu 0>; + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x01f02000 0x40>; + status = "disabled"; + }; + + r_pio: pinctrl@01f02c00 { + compatible = "allwinner,sun8i-h3-r-pinctrl"; + reg = <0x01f02c00 0x400>; + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu 3>, <&osc24M>, <&osc32k>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + + ir_pins_a: ir@0 { + pins = "PL11"; + function = "s_cir_rx"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/sunxi-reference-design-tablet.dtsi b/arch/arm/boot/dts/sunxi-reference-design-tablet.dtsi index b8241462fcea..245d0bcde441 100644 --- a/arch/arm/boot/dts/sunxi-reference-design-tablet.dtsi +++ b/arch/arm/boot/dts/sunxi-reference-design-tablet.dtsi @@ -42,7 +42,6 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> -#include <dt-bindings/pinctrl/sun4i-a10.h> #include "sunxi-common-regulators.dtsi" &i2c0 { diff --git a/arch/arm/boot/dts/uniphier-ld4-ref.dts b/arch/arm/boot/dts/uniphier-ld4-ref.dts index 110031bc0e7e..e0da4ee21c21 100644 --- a/arch/arm/boot/dts/uniphier-ld4-ref.dts +++ b/arch/arm/boot/dts/uniphier-ld4-ref.dts @@ -52,11 +52,6 @@ model = "UniPhier LD4 Reference Board"; compatible = "socionext,uniphier-ld4-ref", "socionext,uniphier-ld4"; - memory { - device_type = "memory"; - reg = <0x80000000 0x20000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -71,6 +66,11 @@ i2c2 = &i2c2; i2c3 = &i2c3; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; + }; }; ðsc { diff --git a/arch/arm/boot/dts/uniphier-ld4.dtsi b/arch/arm/boot/dts/uniphier-ld4.dtsi index a7c494d7c43a..4f5fe15eaee2 100644 --- a/arch/arm/boot/dts/uniphier-ld4.dtsi +++ b/arch/arm/boot/dts/uniphier-ld4.dtsi @@ -43,10 +43,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -/include/ "skeleton.dtsi" - / { compatible = "socionext,uniphier-ld4"; + #address-cells = <1>; + #size-cells = <1>; cpus { #address-cells = <1>; diff --git a/arch/arm/boot/dts/uniphier-ld6b-ref.dts b/arch/arm/boot/dts/uniphier-ld6b-ref.dts index c05d631dcf02..a397a8811c78 100644 --- a/arch/arm/boot/dts/uniphier-ld6b-ref.dts +++ b/arch/arm/boot/dts/uniphier-ld6b-ref.dts @@ -52,11 +52,6 @@ model = "UniPhier LD6b Reference Board"; compatible = "socionext,uniphier-ld6b-ref", "socionext,uniphier-ld6b"; - memory { - device_type = "memory"; - reg = <0x80000000 0x80000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -73,6 +68,11 @@ i2c5 = &i2c5; i2c6 = &i2c6; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; }; ðsc { diff --git a/arch/arm/boot/dts/uniphier-pinctrl.dtsi b/arch/arm/boot/dts/uniphier-pinctrl.dtsi index 8ee79da9af7c..246f35ffb638 100644 --- a/arch/arm/boot/dts/uniphier-pinctrl.dtsi +++ b/arch/arm/boot/dts/uniphier-pinctrl.dtsi @@ -45,7 +45,7 @@ &pinctrl { pinctrl_emmc: emmc_grp { - groups = "emmc"; + groups = "emmc", "emmc_dat8"; function = "emmc"; }; diff --git a/arch/arm/boot/dts/uniphier-pro4-ace.dts b/arch/arm/boot/dts/uniphier-pro4-ace.dts index 0ab0a40c041e..fefc89149234 100644 --- a/arch/arm/boot/dts/uniphier-pro4-ace.dts +++ b/arch/arm/boot/dts/uniphier-pro4-ace.dts @@ -50,11 +50,6 @@ model = "UniPhier Pro4 Ace Board"; compatible = "socionext,uniphier-pro4-ace", "socionext,uniphier-pro4"; - memory { - device_type = "memory"; - reg = <0x80000000 0x40000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -70,6 +65,11 @@ i2c5 = &i2c5; i2c6 = &i2c6; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x40000000>; + }; }; &serial0 { @@ -90,6 +90,7 @@ eeprom@54 { compatible = "st,24c64"; reg = <0x54>; + pagesize = <32>; }; }; diff --git a/arch/arm/boot/dts/uniphier-pro4-ref.dts b/arch/arm/boot/dts/uniphier-pro4-ref.dts index 9e92e60d25ce..6077e634d14a 100644 --- a/arch/arm/boot/dts/uniphier-pro4-ref.dts +++ b/arch/arm/boot/dts/uniphier-pro4-ref.dts @@ -52,11 +52,6 @@ model = "UniPhier Pro4 Reference Board"; compatible = "socionext,uniphier-pro4-ref", "socionext,uniphier-pro4"; - memory { - device_type = "memory"; - reg = <0x80000000 0x40000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -73,6 +68,11 @@ i2c5 = &i2c5; i2c6 = &i2c6; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x40000000>; + }; }; ðsc { diff --git a/arch/arm/boot/dts/uniphier-pro4-sanji.dts b/arch/arm/boot/dts/uniphier-pro4-sanji.dts index dc4ea8832ce2..6c63c8bad825 100644 --- a/arch/arm/boot/dts/uniphier-pro4-sanji.dts +++ b/arch/arm/boot/dts/uniphier-pro4-sanji.dts @@ -50,11 +50,6 @@ model = "UniPhier Pro4 Sanji Board"; compatible = "socionext,uniphier-pro4-sanji", "socionext,uniphier-pro4"; - memory { - device_type = "memory"; - reg = <0x80000000 0x80000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -69,6 +64,11 @@ i2c5 = &i2c5; i2c6 = &i2c6; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; }; &serial0 { @@ -85,6 +85,7 @@ eeprom@54 { compatible = "st,24c64"; reg = <0x54>; + pagesize = <32>; }; }; diff --git a/arch/arm/boot/dts/uniphier-pro4.dtsi b/arch/arm/boot/dts/uniphier-pro4.dtsi index e960b09ff01c..794a85a7068b 100644 --- a/arch/arm/boot/dts/uniphier-pro4.dtsi +++ b/arch/arm/boot/dts/uniphier-pro4.dtsi @@ -43,10 +43,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -/include/ "skeleton.dtsi" - / { compatible = "socionext,uniphier-pro4"; + #address-cells = <1>; + #size-cells = <1>; cpus { #address-cells = <1>; diff --git a/arch/arm/boot/dts/uniphier-pro5.dtsi b/arch/arm/boot/dts/uniphier-pro5.dtsi index dbc5e5333163..df07b555cbed 100644 --- a/arch/arm/boot/dts/uniphier-pro5.dtsi +++ b/arch/arm/boot/dts/uniphier-pro5.dtsi @@ -43,10 +43,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -/include/ "skeleton.dtsi" - / { compatible = "socionext,uniphier-pro5"; + #address-cells = <1>; + #size-cells = <1>; cpus { #address-cells = <1>; diff --git a/arch/arm/boot/dts/uniphier-pxs2-gentil.dts b/arch/arm/boot/dts/uniphier-pxs2-gentil.dts index 373818ace086..cccc86658d20 100644 --- a/arch/arm/boot/dts/uniphier-pxs2-gentil.dts +++ b/arch/arm/boot/dts/uniphier-pxs2-gentil.dts @@ -51,11 +51,6 @@ compatible = "socionext,uniphier-pxs2-gentil", "socionext,uniphier-pxs2"; - memory { - device_type = "memory"; - reg = <0x80000000 0x80000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -70,6 +65,11 @@ i2c5 = &i2c5; i2c6 = &i2c6; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; }; &serial2 { @@ -82,6 +82,7 @@ eeprom@54 { compatible = "st,24c64"; reg = <0x54>; + pagesize = <32>; }; }; diff --git a/arch/arm/boot/dts/uniphier-pxs2-vodka.dts b/arch/arm/boot/dts/uniphier-pxs2-vodka.dts index 51a3eacddfc6..803a39aa39d0 100644 --- a/arch/arm/boot/dts/uniphier-pxs2-vodka.dts +++ b/arch/arm/boot/dts/uniphier-pxs2-vodka.dts @@ -50,11 +50,6 @@ model = "UniPhier PXs2 Vodka Board"; compatible = "socionext,uniphier-pxs2-vodka", "socionext,uniphier-pxs2"; - memory { - device_type = "memory"; - reg = <0x80000000 0x80000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -68,6 +63,11 @@ i2c5 = &i2c5; i2c6 = &i2c6; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; }; &serial2 { diff --git a/arch/arm/boot/dts/uniphier-pxs2.dtsi b/arch/arm/boot/dts/uniphier-pxs2.dtsi index e9e031d63c1a..58c3e2f35706 100644 --- a/arch/arm/boot/dts/uniphier-pxs2.dtsi +++ b/arch/arm/boot/dts/uniphier-pxs2.dtsi @@ -43,10 +43,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -/include/ "skeleton.dtsi" - / { compatible = "socionext,uniphier-pxs2"; + #address-cells = <1>; + #size-cells = <1>; cpus { #address-cells = <1>; diff --git a/arch/arm/boot/dts/uniphier-ref-daughter.dtsi b/arch/arm/boot/dts/uniphier-ref-daughter.dtsi index f7df0881c5e0..c62ae1a81f47 100644 --- a/arch/arm/boot/dts/uniphier-ref-daughter.dtsi +++ b/arch/arm/boot/dts/uniphier-ref-daughter.dtsi @@ -1,7 +1,8 @@ /* * Device Tree Source for UniPhier Reference Daughter Board * - * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * Copyright (C) 2015-2017 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual @@ -46,5 +47,6 @@ eeprom@50 { compatible = "microchip,24lc128"; reg = <0x50>; + pagesize = <64>; }; }; diff --git a/arch/arm/boot/dts/uniphier-sld3-ref.dts b/arch/arm/boot/dts/uniphier-sld3-ref.dts index ac792ae07ae0..eb63dcca92b5 100644 --- a/arch/arm/boot/dts/uniphier-sld3-ref.dts +++ b/arch/arm/boot/dts/uniphier-sld3-ref.dts @@ -52,12 +52,6 @@ model = "UniPhier sLD3 Reference Board"; compatible = "socionext,uniphier-sld3-ref", "socionext,uniphier-sld3"; - memory { - device_type = "memory"; - reg = <0x80000000 0x20000000 - 0xc0000000 0x20000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -72,6 +66,12 @@ i2c3 = &i2c3; i2c4 = &i2c4; }; + + memory@8000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000 + 0xc0000000 0x20000000>; + }; }; ðsc { diff --git a/arch/arm/boot/dts/uniphier-sld3.dtsi b/arch/arm/boot/dts/uniphier-sld3.dtsi index 9fad6bd2db8a..01d77edac01f 100644 --- a/arch/arm/boot/dts/uniphier-sld3.dtsi +++ b/arch/arm/boot/dts/uniphier-sld3.dtsi @@ -43,10 +43,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -/include/ "skeleton.dtsi" - / { compatible = "socionext,uniphier-sld3"; + #address-cells = <1>; + #size-cells = <1>; cpus { #address-cells = <1>; diff --git a/arch/arm/boot/dts/uniphier-sld8-ref.dts b/arch/arm/boot/dts/uniphier-sld8-ref.dts index a8291f988066..737d276349fd 100644 --- a/arch/arm/boot/dts/uniphier-sld8-ref.dts +++ b/arch/arm/boot/dts/uniphier-sld8-ref.dts @@ -52,11 +52,6 @@ model = "UniPhier sLD8 Reference Board"; compatible = "socionext,uniphier-sld8-ref", "socionext,uniphier-sld8"; - memory { - device_type = "memory"; - reg = <0x80000000 0x20000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -71,6 +66,11 @@ i2c2 = &i2c2; i2c3 = &i2c3; }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; + }; }; ðsc { diff --git a/arch/arm/boot/dts/uniphier-sld8.dtsi b/arch/arm/boot/dts/uniphier-sld8.dtsi index b2c980ead7f0..eb06fdc04b02 100644 --- a/arch/arm/boot/dts/uniphier-sld8.dtsi +++ b/arch/arm/boot/dts/uniphier-sld8.dtsi @@ -43,10 +43,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -/include/ "skeleton.dtsi" - / { compatible = "socionext,uniphier-sld8"; + #address-cells = <1>; + #size-cells = <1>; cpus { #address-cells = <1>; diff --git a/arch/arm/boot/dts/uniphier-support-card.dtsi b/arch/arm/boot/dts/uniphier-support-card.dtsi index 51ecc9b9c0ce..f61dfec2807f 100644 --- a/arch/arm/boot/dts/uniphier-support-card.dtsi +++ b/arch/arm/boot/dts/uniphier-support-card.dtsi @@ -1,7 +1,8 @@ /* * Device Tree Source for UniPhier Support Card (Expansion Board) * - * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * Copyright (C) 2015-2017 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual @@ -46,7 +47,7 @@ status = "okay"; ranges = <1 0x00000000 0x42000000 0x02000000>; - support_card: support_card { + support_card: support_card@1,1f00000 { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi index 3086efacd00e..35714ff6f467 100644 --- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi @@ -71,7 +71,7 @@ #size-cells = <1>; ranges = <0 3 0 0x200000>; - v2m_sysreg: sysreg@010000 { + v2m_sysreg: sysreg@10000 { compatible = "arm,vexpress-sysreg"; reg = <0x010000 0x1000>; @@ -94,7 +94,7 @@ }; }; - v2m_sysctl: sysctl@020000 { + v2m_sysctl: sysctl@20000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x020000 0x1000>; clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; @@ -106,7 +106,7 @@ }; /* PCI-E I2C bus */ - v2m_i2c_pcie: i2c@030000 { + v2m_i2c_pcie: i2c@30000 { compatible = "arm,versatile-i2c"; reg = <0x030000 0x1000>; @@ -119,7 +119,7 @@ }; }; - aaci@040000 { + aaci@40000 { compatible = "arm,pl041", "arm,primecell"; reg = <0x040000 0x1000>; interrupts = <11>; @@ -127,7 +127,7 @@ clock-names = "apb_pclk"; }; - mmci@050000 { + mmci@50000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x050000 0x1000>; interrupts = <9 10>; @@ -139,7 +139,7 @@ clock-names = "mclk", "apb_pclk"; }; - kmi@060000 { + kmi@60000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x060000 0x1000>; interrupts = <12>; @@ -147,7 +147,7 @@ clock-names = "KMIREFCLK", "apb_pclk"; }; - kmi@070000 { + kmi@70000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x070000 0x1000>; interrupts = <13>; @@ -155,7 +155,7 @@ clock-names = "KMIREFCLK", "apb_pclk"; }; - v2m_serial0: uart@090000 { + v2m_serial0: uart@90000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x090000 0x1000>; interrupts = <5>; @@ -163,7 +163,7 @@ clock-names = "uartclk", "apb_pclk"; }; - v2m_serial1: uart@0a0000 { + v2m_serial1: uart@a0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0a0000 0x1000>; interrupts = <6>; @@ -171,7 +171,7 @@ clock-names = "uartclk", "apb_pclk"; }; - v2m_serial2: uart@0b0000 { + v2m_serial2: uart@b0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b0000 0x1000>; interrupts = <7>; @@ -179,7 +179,7 @@ clock-names = "uartclk", "apb_pclk"; }; - v2m_serial3: uart@0c0000 { + v2m_serial3: uart@c0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0c0000 0x1000>; interrupts = <8>; @@ -187,7 +187,7 @@ clock-names = "uartclk", "apb_pclk"; }; - wdt@0f0000 { + wdt@f0000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f0000 0x1000>; interrupts = <0>; diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi index c6393d3f1719..1b6f6393be93 100644 --- a/arch/arm/boot/dts/vexpress-v2m.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m.dtsi @@ -70,7 +70,7 @@ #size-cells = <1>; ranges = <0 7 0 0x20000>; - v2m_sysreg: sysreg@00000 { + v2m_sysreg: sysreg@0 { compatible = "arm,vexpress-sysreg"; reg = <0x00000 0x1000>; @@ -93,7 +93,7 @@ }; }; - v2m_sysctl: sysctl@01000 { + v2m_sysctl: sysctl@1000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x01000 0x1000>; clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; @@ -105,7 +105,7 @@ }; /* PCI-E I2C bus */ - v2m_i2c_pcie: i2c@02000 { + v2m_i2c_pcie: i2c@2000 { compatible = "arm,versatile-i2c"; reg = <0x02000 0x1000>; @@ -118,7 +118,7 @@ }; }; - aaci@04000 { + aaci@4000 { compatible = "arm,pl041", "arm,primecell"; reg = <0x04000 0x1000>; interrupts = <11>; @@ -126,7 +126,7 @@ clock-names = "apb_pclk"; }; - mmci@05000 { + mmci@5000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x05000 0x1000>; interrupts = <9 10>; @@ -138,7 +138,7 @@ clock-names = "mclk", "apb_pclk"; }; - kmi@06000 { + kmi@6000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x06000 0x1000>; interrupts = <12>; @@ -146,7 +146,7 @@ clock-names = "KMIREFCLK", "apb_pclk"; }; - kmi@07000 { + kmi@7000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x07000 0x1000>; interrupts = <13>; @@ -154,7 +154,7 @@ clock-names = "KMIREFCLK", "apb_pclk"; }; - v2m_serial0: uart@09000 { + v2m_serial0: uart@9000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x09000 0x1000>; interrupts = <5>; @@ -162,7 +162,7 @@ clock-names = "uartclk", "apb_pclk"; }; - v2m_serial1: uart@0a000 { + v2m_serial1: uart@a000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0a000 0x1000>; interrupts = <6>; @@ -170,7 +170,7 @@ clock-names = "uartclk", "apb_pclk"; }; - v2m_serial2: uart@0b000 { + v2m_serial2: uart@b000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b000 0x1000>; interrupts = <7>; @@ -178,7 +178,7 @@ clock-names = "uartclk", "apb_pclk"; }; - v2m_serial3: uart@0c000 { + v2m_serial3: uart@c000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0c000 0x1000>; interrupts = <8>; @@ -186,7 +186,7 @@ clock-names = "uartclk", "apb_pclk"; }; - wdt@0f000 { + wdt@f000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f000 0x1000>; interrupts = <0>; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts index 15f4fd3f4695..0c8de0ca73ee 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts @@ -220,7 +220,7 @@ }; }; - smb@08000000 { + smb@8000000 { compatible = "simple-bus"; #address-cells = <2>; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index bd107c5a0226..65ecf206388c 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -385,7 +385,7 @@ }; }; - etb@0,20010000 { + etb@20010000 { compatible = "arm,coresight-etb10", "arm,primecell"; reg = <0 0x20010000 0 0x1000>; @@ -399,7 +399,7 @@ }; }; - tpiu@0,20030000 { + tpiu@20030000 { compatible = "arm,coresight-tpiu", "arm,primecell"; reg = <0 0x20030000 0 0x1000>; @@ -449,7 +449,7 @@ }; }; - funnel@0,20040000 { + funnel@20040000 { compatible = "arm,coresight-funnel", "arm,primecell"; reg = <0 0x20040000 0 0x1000>; @@ -513,7 +513,7 @@ }; }; - ptm@0,2201c000 { + ptm@2201c000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0 0x2201c000 0 0x1000>; @@ -527,7 +527,7 @@ }; }; - ptm@0,2201d000 { + ptm@2201d000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0 0x2201d000 0 0x1000>; @@ -541,7 +541,7 @@ }; }; - etm@0,2203c000 { + etm@2203c000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0 0x2203c000 0 0x1000>; @@ -555,7 +555,7 @@ }; }; - etm@0,2203d000 { + etm@2203d000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0 0x2203d000 0 0x1000>; @@ -569,7 +569,7 @@ }; }; - etm@0,2203e000 { + etm@2203e000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0 0x2203e000 0 0x1000>; @@ -583,7 +583,7 @@ }; }; - smb@08000000 { + smb@8000000 { compatible = "simple-bus"; #address-cells = <2>; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts index 1acecaf4b13d..6e69b8e6c1a7 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts @@ -190,7 +190,7 @@ }; }; - smb@08000000 { + smb@8000000 { compatible = "simple-bus"; #address-cells = <2>; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts index b608a03ee02f..c9305b58afc2 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts @@ -300,7 +300,7 @@ }; }; - smb@04000000 { + smb@4000000 { compatible = "simple-bus"; #address-cells = <2>; diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts index 7940408838df..37f95427616f 100644 --- a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts +++ b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts @@ -239,7 +239,7 @@ #size-cells = <0>; reg = <4>; - switch2: switch2@0 { + switch2: switch@0 { compatible = "marvell,mv88e6085"; #address-cells = <1>; #size-cells = <0>; @@ -459,18 +459,6 @@ >; }; - pinctrl_gpio_switch0: pinctrl-gpio-switch0 { - fsl,pins = < - VF610_PAD_PTB5__GPIO_27 0x219d - >; - }; - - pinctrl_gpio_switch1: pinctrl-gpio-switch1 { - fsl,pins = < - VF610_PAD_PTB4__GPIO_26 0x219d - >; - }; - pinctrl_mdio_mux: pinctrl-mdio-mux { fsl,pins = < VF610_PAD_PTA18__GPIO_8 0x31c2 diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts index 6a45bd24ffe6..db3b408ea55a 100644 --- a/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts +++ b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts @@ -67,11 +67,17 @@ switch0: switch@0 { compatible = "marvell,mv88e6190"; + pinctrl-0 = <&pinctrl_gpio_switch0>; + pinctrl-names = "default"; #address-cells = <1>; #size-cells = <0>; reg = <0>; dsa,member = <0 0>; eeprom-length = <512>; + interrupt-parent = <&gpio0>; + interrupts = <27 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; ports { #address-cells = <1>; @@ -91,21 +97,25 @@ port@1 { reg = <1>; label = "lan1"; + phy-handle = <&switch0phy1>; }; port@2 { reg = <2>; label = "lan2"; + phy-handle = <&switch0phy2>; }; port@3 { reg = <3>; label = "lan3"; + phy-handle = <&switch0phy3>; }; port@4 { reg = <4>; label = "lan4"; + phy-handle = <&switch0phy4>; }; switch0port10: port@10 { @@ -115,6 +125,35 @@ link = <&switch1port10>; }; }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch0phy1: switch0phy@1 { + reg = <1>; + interrupt-parent = <&switch0>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + }; + + switch0phy2: switch0phy@2 { + reg = <2>; + interrupt-parent = <&switch0>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + }; + + switch0phy3: switch0phy@3 { + reg = <3>; + interrupt-parent = <&switch0>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + }; + + switch0phy4: switch0phy@4 { + reg = <4>; + interrupt-parent = <&switch0>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + }; + }; }; }; @@ -125,11 +164,17 @@ switch1: switch@0 { compatible = "marvell,mv88e6190"; + pinctrl-0 = <&pinctrl_gpio_switch1>; + pinctrl-names = "default"; #address-cells = <1>; #size-cells = <0>; reg = <0>; dsa,member = <0 1>; eeprom-length = <512>; + interrupt-parent = <&gpio0>; + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; ports { #address-cells = <1>; @@ -138,21 +183,25 @@ port@1 { reg = <1>; label = "lan5"; + phy-handle = <&switch1phy1>; }; port@2 { reg = <2>; label = "lan6"; + phy-handle = <&switch1phy2>; }; port@3 { reg = <3>; label = "lan7"; + phy-handle = <&switch1phy3>; }; port@4 { reg = <4>; label = "lan8"; + phy-handle = <&switch1phy4>; }; @@ -163,6 +212,34 @@ link = <&switch0port10>; }; }; + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch1phy1: switch1phy@1 { + reg = <1>; + interrupt-parent = <&switch1>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + }; + + switch1phy2: switch1phy@2 { + reg = <2>; + interrupt-parent = <&switch1>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + }; + + switch1phy3: switch1phy@3 { + reg = <3>; + interrupt-parent = <&switch1>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + }; + + switch1phy4: switch1phy@4 { + reg = <4>; + interrupt-parent = <&switch1>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/vf610-zii-dev.dtsi b/arch/arm/boot/dts/vf610-zii-dev.dtsi index ca9e1bc35e45..6b58d3a97992 100644 --- a/arch/arm/boot/dts/vf610-zii-dev.dtsi +++ b/arch/arm/boot/dts/vf610-zii-dev.dtsi @@ -296,6 +296,18 @@ >; }; + pinctrl_gpio_switch0: pinctrl-gpio-switch0 { + fsl,pins = < + VF610_PAD_PTB5__GPIO_27 0x219d + >; + }; + + pinctrl_gpio_switch1: pinctrl-gpio-switch1 { + fsl,pins = < + VF610_PAD_PTB4__GPIO_26 0x219d + >; + }; + pinctrl_i2c_mux_reset: pinctrl-i2c-mux-reset { fsl,pins = < VF610_PAD_PTE14__GPIO_119 0x31c2 diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 9353184d730d..1181053e3ade 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -1,6 +1,3 @@ -config ICST - bool - config SA1111 bool select DMABOUNCE if !ARCH_PXA diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 27f23b15b1ea..29fdf6a3601d 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -4,7 +4,6 @@ obj-y += firmware.o -obj-$(CONFIG_ICST) += icst.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o obj-$(CONFIG_SHARP_LOCOMO) += locomo.o diff --git a/arch/arm/configs/aspeed_g4_defconfig b/arch/arm/configs/aspeed_g4_defconfig index d25010e3a0bc..cfc2465e8b77 100644 --- a/arch/arm/configs/aspeed_g4_defconfig +++ b/arch/arm/configs/aspeed_g4_defconfig @@ -1,6 +1,6 @@ CONFIG_KERNEL_XZ=y +# CONFIG_SWAP is not set CONFIG_SYSVIPC=y -CONFIG_USELIB=y CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y @@ -8,39 +8,65 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_BZIP2 is not set -# CONFIG_RD_LZMA is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set -CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_SHMEM is not set # CONFIG_AIO is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_JUMP_LABEL=y +CONFIG_GCC_PLUGINS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -# CONFIG_BLOCK is not set +# CONFIG_LBDAF is not set # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_ASPEED=y CONFIG_MACH_ASPEED_G4=y CONFIG_AEABI=y -CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_CPU_SW_DOMAIN_PAN is not set +# CONFIG_COMPACTION is not set CONFIG_SECCOMP=y +# CONFIG_ATAGS is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_KEXEC=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_SYN_COOKIES=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_DIAG is not set +# CONFIG_IPV6 is not set CONFIG_NET_NCSI=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_PARTITIONED_MASTER=y +CONFIG_MTD_SPI_NOR=y +CONFIG_SPI_ASPEED_SMC=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_FASTMAP=y +CONFIG_MTD_UBI_BLOCK=y +CONFIG_BLK_DEV_RAM=y +CONFIG_ASPEED_LPC_CTRL=y +CONFIG_EEPROM_AT24=y CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y # CONFIG_NET_VENDOR_ALACRITECH is not set # CONFIG_NET_VENDOR_AMAZON is not set # CONFIG_NET_VENDOR_ARC is not set @@ -63,9 +89,10 @@ CONFIG_FTGMAC100=y # CONFIG_NET_VENDOR_SOLARFLARE is not set # CONFIG_NET_VENDOR_SMSC is not set # CONFIG_NET_VENDOR_STMICRO is not set -# CONFIG_NET_VENDOR_SYNOPSYS is not set # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_BROADCOM_PHY=y +CONFIG_REALTEK_PHY=y # CONFIG_WLAN is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -81,35 +108,74 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_ASPEED_BT_IPMI_BMC=y # CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA9541=y +CONFIG_I2C_MUX_PCA954x=y CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y CONFIG_GPIO_ASPEED=y -# CONFIG_USB_SUPPORT is not set +CONFIG_W1=y +CONFIG_W1_MASTER_GPIO=y +CONFIG_W1_SLAVE_THERM=y +CONFIG_SENSORS_ASPEED=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_SENSORS_LM75=y +CONFIG_SENSORS_NCT7904=y +CONFIG_PMBUS=y +CONFIG_SENSORS_ADM1275=y +CONFIG_SENSORS_LM25066=y +CONFIG_SENSORS_UCD9000=y +CONFIG_SENSORS_TMP421=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_FLASH=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_PCF8523=y +CONFIG_RTC_DRV_RV8803=y +CONFIG_MAILBOX=y # CONFIG_IOMMU_SUPPORT is not set +CONFIG_IIO=y +CONFIG_ASPEED_ADC=y +CONFIG_BMP280=y CONFIG_FIRMWARE_MEMMAP=y CONFIG_FANOTIFY=y +CONFIG_OVERLAY_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_UBIFS_FS=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XZ=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y CONFIG_STRIP_ASM_SYMS=y -CONFIG_PAGE_POISONING=y -CONFIG_DEBUG_KMEMLEAK=y -CONFIG_DEBUG_SHIRQ=y +CONFIG_DEBUG_FS=y CONFIG_LOCKUP_DETECTOR=y CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=-1 # CONFIG_SCHED_DEBUG is not set CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y +CONFIG_STACKTRACE=y # CONFIG_FTRACE is not set -CONFIG_MEMTEST=y -CONFIG_UBSAN=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y -CONFIG_DEBUG_LL_UART_8250=y -CONFIG_DEBUG_UART_PHYS=0x1e784000 -CONFIG_DEBUG_UART_VIRT=0xe8784000 -CONFIG_EARLY_PRINTK=y -CONFIG_STRICT_MODULE_RWX=y -CONFIG_STRICT_KERNEL_RWX=y +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_HW is not set # CONFIG_XZ_DEC_X86 is not set # CONFIG_XZ_DEC_POWERPC is not set # CONFIG_XZ_DEC_IA64 is not set diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig index 5f660b02abd9..3c20d93de389 100644 --- a/arch/arm/configs/aspeed_g5_defconfig +++ b/arch/arm/configs/aspeed_g5_defconfig @@ -1,6 +1,6 @@ CONFIG_KERNEL_XZ=y +# CONFIG_SWAP is not set CONFIG_SYSVIPC=y -CONFIG_USELIB=y CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y @@ -8,27 +8,28 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_BZIP2 is not set -# CONFIG_RD_LZMA is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set -CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y -# CONFIG_SHMEM is not set # CONFIG_AIO is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_JUMP_LABEL=y +CONFIG_GCC_PLUGINS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -# CONFIG_BLOCK is not set +# CONFIG_LBDAF is not set CONFIG_ARCH_MULTI_V6=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_ASPEED=y CONFIG_MACH_ASPEED_G5=y +# CONFIG_CACHE_L2X0 is not set CONFIG_VMSPLIT_2G=y CONFIG_AEABI=y -CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_CPU_SW_DOMAIN_PAN is not set +# CONFIG_COMPACTION is not set CONFIG_SECCOMP=y # CONFIG_ATAGS is not set CONFIG_ZBOOT_ROM_TEXT=0x0 @@ -38,15 +39,37 @@ CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_KEXEC=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_SYN_COOKIES=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_DIAG is not set +# CONFIG_IPV6 is not set CONFIG_NET_NCSI=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_PARTITIONED_MASTER=y +CONFIG_MTD_SPI_NOR=y +CONFIG_SPI_ASPEED_SMC=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_FASTMAP=y +CONFIG_MTD_UBI_BLOCK=y +CONFIG_BLK_DEV_RAM=y +CONFIG_ASPEED_LPC_CTRL=y +CONFIG_EEPROM_AT24=y CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y # CONFIG_NET_VENDOR_ALACRITECH is not set # CONFIG_NET_VENDOR_AMAZON is not set # CONFIG_NET_VENDOR_ARC is not set @@ -69,9 +92,10 @@ CONFIG_FTGMAC100=y # CONFIG_NET_VENDOR_SOLARFLARE is not set # CONFIG_NET_VENDOR_SMSC is not set # CONFIG_NET_VENDOR_STMICRO is not set -# CONFIG_NET_VENDOR_SYNOPSYS is not set # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_BROADCOM_PHY=y +CONFIG_REALTEK_PHY=y # CONFIG_WLAN is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -87,37 +111,74 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_ASPEED_BT_IPMI_BMC=y # CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA9541=y +CONFIG_I2C_MUX_PCA954x=y CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y CONFIG_GPIO_ASPEED=y -# CONFIG_USB_SUPPORT is not set +CONFIG_W1=y +CONFIG_W1_MASTER_GPIO=y +CONFIG_W1_SLAVE_THERM=y +CONFIG_SENSORS_ASPEED=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_SENSORS_LM75=y +CONFIG_SENSORS_NCT7904=y +CONFIG_PMBUS=y +CONFIG_SENSORS_ADM1275=y +CONFIG_SENSORS_LM25066=y +CONFIG_SENSORS_UCD9000=y +CONFIG_SENSORS_TMP421=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_FLASH=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_PCF8523=y +CONFIG_RTC_DRV_RV8803=y +CONFIG_MAILBOX=y # CONFIG_IOMMU_SUPPORT is not set +CONFIG_IIO=y +CONFIG_ASPEED_ADC=y +CONFIG_BMP280=y CONFIG_FIRMWARE_MEMMAP=y CONFIG_FANOTIFY=y +CONFIG_OVERLAY_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_UBIFS_FS=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XZ=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y CONFIG_STRIP_ASM_SYMS=y -CONFIG_PAGE_POISONING=y -CONFIG_DEBUG_KMEMLEAK=y -CONFIG_DEBUG_SHIRQ=y +CONFIG_DEBUG_FS=y CONFIG_LOCKUP_DETECTOR=y CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=-1 # CONFIG_SCHED_DEBUG is not set CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y +CONFIG_STACKTRACE=y # CONFIG_FTRACE is not set -CONFIG_MEMTEST=y -CONFIG_UBSAN=y -CONFIG_UBSAN_ALIGNMENT=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y -CONFIG_DEBUG_LL_UART_8250=y -CONFIG_DEBUG_UART_PHYS=0x1e784000 -CONFIG_DEBUG_UART_VIRT=0xe8784000 -CONFIG_EARLY_PRINTK=y -CONFIG_STRICT_MODULE_RWX=y -CONFIG_STRICT_KERNEL_RWX=y -CONFIG_CRYPTO_ECHAINIV=y +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_HW is not set # CONFIG_XZ_DEC_X86 is not set # CONFIG_XZ_DEC_POWERPC is not set # CONFIG_XZ_DEC_IA64 is not set diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig index 4b89f4e6e849..3ba8cd3211f8 100644 --- a/arch/arm/configs/bcm2835_defconfig +++ b/arch/arm/configs/bcm2835_defconfig @@ -1,6 +1,5 @@ # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y -CONFIG_FHANDLE=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y @@ -32,6 +31,7 @@ CONFIG_PREEMPT_VOLUNTARY=y CONFIG_AEABI=y CONFIG_KSM=y CONFIG_CLEANCACHE=y +CONFIG_CMA=y CONFIG_SECCOMP=y CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y @@ -52,6 +52,7 @@ CONFIG_MAC80211=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set +CONFIG_DMA_CMA=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SCSI_CONSTANTS=y @@ -62,7 +63,6 @@ CONFIG_USB_NET_SMSC95XX=y CONFIG_ZD1211RW=y CONFIG_INPUT_EVDEV=y # CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVKMEM is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_TTY_PRINTK=y @@ -92,6 +92,7 @@ CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_IPROC=y +CONFIG_MMC_BCM2835=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index c8663eac9b1b..67db82999c06 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -74,12 +74,10 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_EEPROM_AT24=y -CONFIG_IDE=m -CONFIG_BLK_DEV_PALMCHIP_BK3710=m -CONFIG_SCSI=m CONFIG_BLK_DEV_SD=m CONFIG_ATA=m CONFIG_AHCI_DA850=m +CONFIG_PATA_BK3710=m CONFIG_NETDEVICES=y CONFIG_NETCONSOLE=y CONFIG_TUN=m @@ -121,6 +119,7 @@ CONFIG_PINCTRL_DA850_PUPD=m CONFIG_PINCTRL_SINGLE=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_GPIO=y CONFIG_WATCHDOG=y @@ -133,9 +132,11 @@ CONFIG_REGULATOR_TPS6507X=y CONFIG_MEDIA_SUPPORT=m CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY=m CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE=m # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_TVP514X=m +CONFIG_VIDEO_ADV7343=m CONFIG_DRM=m CONFIG_DRM_TILCDC=m CONFIG_DRM_DUMB_VGA_DAC=m @@ -204,12 +205,10 @@ CONFIG_MEMORY=y CONFIG_TI_AEMIF=m CONFIG_DA8XX_DDRCTL=y CONFIG_IIO=m -CONFIG_IIO_BUFFER=y CONFIG_IIO_BUFFER_CB=m -CONFIG_IIO_KFIFO_BUF=m -CONFIG_IIO_TRIGGER=y CONFIG_IIO_SW_DEVICE=m CONFIG_IIO_SW_TRIGGER=m +CONFIG_TI_ADS7950=m CONFIG_IIO_HRTIMER_TRIGGER=m CONFIG_IIO_SYSFS_TRIGGER=m CONFIG_PWM=y diff --git a/arch/arm/configs/dram_0xd0000000.config b/arch/arm/configs/dram_0xd0000000.config new file mode 100644 index 000000000000..61ba7045f8a1 --- /dev/null +++ b/arch/arm/configs/dram_0xd0000000.config @@ -0,0 +1 @@ +CONFIG_DRAM_BASE=0xd0000000 diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 742baf067e1c..6dc661c4a2c1 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -53,7 +53,7 @@ CONFIG_RFKILL_REGULATOR=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_DMA_CMA=y -CONFIG_CMA_SIZE_MBYTES=64 +CONFIG_CMA_SIZE_MBYTES=96 CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=y CONFIG_BLK_DEV_RAM=y @@ -240,7 +240,7 @@ CONFIG_PWM=y CONFIG_PWM_SAMSUNG=y CONFIG_PHY_EXYNOS5250_SATA=y CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_AUTOFS4_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -255,6 +255,7 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y CONFIG_MAGIC_SYSRQ=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index eaba3b165d72..bb6fa568b620 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -143,6 +143,7 @@ CONFIG_SMSC911X=y # CONFIG_NET_VENDOR_STMICRO is not set CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y +CONFIG_SMSC_PHY=y CONFIG_USB_PEGASUS=m CONFIG_USB_RTL8150=m CONFIG_USB_RTL8152=m @@ -152,7 +153,6 @@ CONFIG_BRCMFMAC=m CONFIG_WL12XX=m CONFIG_WLCORE_SDIO=m # CONFIG_WILINK_PLATFORM_DATA is not set -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_KEYBOARD_GPIO=y @@ -165,6 +165,7 @@ CONFIG_TOUCHSCREEN_ADS7846=y CONFIG_TOUCHSCREEN_EGALAX=y CONFIG_TOUCHSCREEN_IMX6UL_TSC=y CONFIG_TOUCHSCREEN_EDT_FT5X06=y +CONFIG_TOUCHSCREEN_MAX11801=y CONFIG_TOUCHSCREEN_MC13783=y CONFIG_TOUCHSCREEN_TSC2004=y CONFIG_TOUCHSCREEN_TSC2007=y @@ -173,6 +174,7 @@ CONFIG_TOUCHSCREEN_SX8654=y CONFIG_TOUCHSCREEN_COLIBRI_VF50=y CONFIG_INPUT_MISC=y CONFIG_INPUT_MMA8450=y +CONFIG_HID_MULTITOUCH=y CONFIG_SERIO_SERPORT=m # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_IMX=y @@ -376,7 +378,6 @@ CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=m CONFIG_NLS_UTF8=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_FS=y CONFIG_MAGIC_SYSRQ=y # CONFIG_SCHED_DEBUG is not set CONFIG_PROVE_LOCKING=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 6aa7be191f1a..2685e03600b1 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -195,7 +195,7 @@ CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=64 CONFIG_OMAP_OCP2SCP=y CONFIG_SIMPLE_PM_BUS=y -CONFIG_SUNXI_RSB=m +CONFIG_SUNXI_RSB=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y @@ -482,9 +482,10 @@ CONFIG_MFD_AS3722=y CONFIG_MFD_ATMEL_FLEXCOM=y CONFIG_MFD_ATMEL_HLCDC=m CONFIG_MFD_BCM590XX=y +CONFIG_MFD_AC100=y CONFIG_MFD_AXP20X=y -CONFIG_MFD_AXP20X_I2C=m -CONFIG_MFD_AXP20X_RSB=m +CONFIG_MFD_AXP20X_I2C=y +CONFIG_MFD_AXP20X_RSB=y CONFIG_MFD_CROS_EC=m CONFIG_MFD_CROS_EC_I2C=m CONFIG_MFD_CROS_EC_SPI=m @@ -513,7 +514,7 @@ CONFIG_REGULATOR_ACT8865=y CONFIG_REGULATOR_ANATOP=y CONFIG_REGULATOR_AS3711=y CONFIG_REGULATOR_AS3722=y -CONFIG_REGULATOR_AXP20X=m +CONFIG_REGULATOR_AXP20X=y CONFIG_REGULATOR_BCM590XX=y CONFIG_REGULATOR_DA9210=y CONFIG_REGULATOR_FAN53555=y @@ -593,10 +594,10 @@ CONFIG_DRM_EXYNOS_DPI=y CONFIG_DRM_EXYNOS_DSI=y CONFIG_DRM_EXYNOS_HDMI=y CONFIG_DRM_ROCKCHIP=m -CONFIG_ROCKCHIP_ANALOGIX_DP=m -CONFIG_ROCKCHIP_DW_HDMI=m -CONFIG_ROCKCHIP_DW_MIPI_DSI=m -CONFIG_ROCKCHIP_INNO_HDMI=m +CONFIG_ROCKCHIP_ANALOGIX_DP=y +CONFIG_ROCKCHIP_DW_HDMI=y +CONFIG_ROCKCHIP_DW_MIPI_DSI=y +CONFIG_ROCKCHIP_INNO_HDMI=y CONFIG_DRM_ATMEL_HLCDC=m CONFIG_DRM_RCAR_DU=m CONFIG_DRM_RCAR_HDMI=y @@ -730,6 +731,7 @@ CONFIG_MMC_DW_EXYNOS=y CONFIG_MMC_DW_ROCKCHIP=y CONFIG_MMC_SH_MMCIF=y CONFIG_MMC_SUNXI=y +CONFIG_MMC_BCM2835=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_FLASH=m @@ -751,6 +753,7 @@ CONFIG_EDAC=y CONFIG_EDAC_HIGHBANK_MC=y CONFIG_EDAC_HIGHBANK_L2=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_AC100=y CONFIG_RTC_DRV_AS3722=y CONFIG_RTC_DRV_DS1307=y CONFIG_RTC_DRV_HYM8563=m @@ -883,7 +886,7 @@ CONFIG_TI_PIPE3=y CONFIG_PHY_BERLIN_USB=y CONFIG_PHY_BERLIN_SATA=y CONFIG_PHY_ROCKCHIP_DP=m -CONFIG_PHY_ROCKCHIP_USB=m +CONFIG_PHY_ROCKCHIP_USB=y CONFIG_PHY_QCOM_APQ8064_SATA=m CONFIG_PHY_MIPHY28LP=y CONFIG_PHY_RCAR_GEN2=m diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index decd388d613d..a120ae816260 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -64,6 +64,7 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPUFREQ_DT=m +CONFIG_ARM_TI_CPUFREQ=y # CONFIG_ARM_OMAP2PLUS_CPUFREQ is not set CONFIG_CPU_IDLE=y CONFIG_BINFMT_MISC=y @@ -141,6 +142,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SCSI_SCAN_ASYNC=y CONFIG_ATA=y CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_DM816=m CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_CADENCE is not set @@ -167,8 +169,18 @@ CONFIG_TI_CPTS=y # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set CONFIG_AT803X_PHY=y +CONFIG_DP83848_PHY=y CONFIG_MICREL_PHY=y CONFIG_SMSC_PHY=y +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m CONFIG_USB_USBNET=m CONFIG_USB_NET_SMSC75XX=m CONFIG_USB_NET_SMSC95XX=m @@ -176,6 +188,7 @@ CONFIG_USB_ALI_M5632=y CONFIG_USB_AN2720=y CONFIG_USB_EPSON2888=y CONFIG_USB_KC2190=y +CONFIG_USB_NET_QMI_WWAN=m CONFIG_USB_CDC_PHONET=m CONFIG_LIBERTAS=m CONFIG_LIBERTAS_USB=m @@ -199,6 +212,7 @@ CONFIG_KEYBOARD_TWL4030=m # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ATMEL_MXT=m CONFIG_TOUCHSCREEN_EDT_FT5X06=m CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m CONFIG_TOUCHSCREEN_PIXCIR=m @@ -206,6 +220,7 @@ CONFIG_TOUCHSCREEN_TSC2004=m CONFIG_TOUCHSCREEN_TSC2005=m CONFIG_TOUCHSCREEN_TSC2007=m CONFIG_INPUT_MISC=y +CONFIG_INPUT_CPCAP_PWRBUTTON=m CONFIG_INPUT_TPS65218_PWRBUTTON=m CONFIG_INPUT_TWL4030_PWRBUTTON=m CONFIG_INPUT_PALMAS_PWRBUTTON=m @@ -241,6 +256,7 @@ CONFIG_W1=m CONFIG_HDQ_MASTER_OMAP=m CONFIG_POWER_AVS=y CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y CONFIG_BATTERY_BQ27XXX=m CONFIG_CHARGER_ISP1704=m CONFIG_CHARGER_TWL4030=m @@ -263,6 +279,7 @@ CONFIG_DRA752_THERMAL=y CONFIG_WATCHDOG=y CONFIG_OMAP_WATCHDOG=m CONFIG_TWL4030_WATCHDOG=m +CONFIG_MFD_CPCAP=y CONFIG_MFD_TI_AM335X_TSCADC=m CONFIG_MFD_PALMAS=y CONFIG_MFD_TPS65217=y @@ -270,7 +287,9 @@ CONFIG_MFD_TI_LP873X=y CONFIG_MFD_TPS65218=y CONFIG_MFD_TPS65910=y CONFIG_TWL6040_CORE=y +CONFIG_REGULATOR_CPCAP=y CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_LM363X=m CONFIG_REGULATOR_LP872X=y CONFIG_REGULATOR_LP873X=y CONFIG_REGULATOR_PALMAS=y @@ -339,6 +358,7 @@ CONFIG_SND_SOC=m CONFIG_SND_EDMA_SOC=m CONFIG_SND_AM33XX_SOC_EVM=m CONFIG_SND_OMAP_SOC=m +CONFIG_SND_OMAP_SOC_HDMI_AUDIO=m CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m @@ -354,6 +374,7 @@ CONFIG_USB_XHCI_HCD=m CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=m CONFIG_USB_WDM=m +CONFIG_USB_ACM=m CONFIG_USB_STORAGE=m CONFIG_USB_MUSB_HDRC=m CONFIG_USB_MUSB_TUSB6010=m @@ -402,6 +423,7 @@ CONFIG_MMC_OMAP=y CONFIG_MMC_OMAP_HS=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=m +CONFIG_LEDS_CPCAP=m CONFIG_LEDS_GPIO=m CONFIG_LEDS_PCA963X=m CONFIG_LEDS_PWM=m @@ -420,6 +442,7 @@ CONFIG_RTC_DRV_TWL92330=y CONFIG_RTC_DRV_TWL4030=m CONFIG_RTC_DRV_PALMAS=m CONFIG_RTC_DRV_OMAP=m +CONFIG_RTC_DRV_CPCAP=m CONFIG_DMADEVICES=y CONFIG_DMA_OMAP=y CONFIG_TI_EDMA=y @@ -432,6 +455,7 @@ CONFIG_IIO=m CONFIG_IIO_SW_DEVICE=m CONFIG_IIO_SW_TRIGGER=m CONFIG_IIO_ST_ACCEL_3AXIS=m +CONFIG_CPCAP_ADC=m CONFIG_TI_AM335X_ADC=m CONFIG_BMP280=m CONFIG_PWM=y diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig index 4ffdd607205d..07666a7a9de5 100644 --- a/arch/arm/configs/qcom_defconfig +++ b/arch/arm/configs/qcom_defconfig @@ -190,11 +190,18 @@ CONFIG_MDM_LCC_9615=y CONFIG_MSM_MMCC_8960=y CONFIG_MSM_MMCC_8974=y CONFIG_HWSPINLOCK_QCOM=y +CONFIG_REMOTEPROC=y +CONFIG_QCOM_ADSP_PIL=y +CONFIG_QCOM_Q6V5_PIL=y +CONFIG_QCOM_WCNSS_PIL=y CONFIG_QCOM_GSBI=y CONFIG_QCOM_PM=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD=y CONFIG_QCOM_SMD_RPM=y +CONFIG_QCOM_SMP2P=y +CONFIG_QCOM_SMSM=y +CONFIG_QCOM_WCNSS_CTRL=y CONFIG_IIO=y CONFIG_IIO_BUFFER_CB=y CONFIG_IIO_SW_TRIGGER=y diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 030264c98eec..2620ce790db0 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -71,6 +71,7 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y +CONFIG_ALTERA_TSE=m CONFIG_E1000E=m CONFIG_IGB=m CONFIG_IXGBE=m diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig index 03437f8f9ad1..a0975386a96c 100644 --- a/arch/arm/configs/stm32_defconfig +++ b/arch/arm/configs/stm32_defconfig @@ -20,6 +20,7 @@ CONFIG_EMBEDDED=y # CONFIG_MMU is not set CONFIG_ARM_SINGLE_ARMV7M=y CONFIG_ARCH_STM32=y +CONFIG_CPU_V7M_NUM_IRQ=240 CONFIG_SET_MEM_PARAM=y CONFIG_DRAM_BASE=0x90000000 CONFIG_FLASH_MEM_BASE=0x08000000 @@ -47,6 +48,9 @@ CONFIG_SERIAL_NONSTANDARD=y CONFIG_SERIAL_STM32=y CONFIG_SERIAL_STM32_CONSOLE=y # CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_STM32F4=y # CONFIG_HWMON is not set CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig index da92c25eb7cc..5cd5dd70bc83 100644 --- a/arch/arm/configs/sunxi_defconfig +++ b/arch/arm/configs/sunxi_defconfig @@ -87,6 +87,7 @@ CONFIG_THERMAL_OF=y CONFIG_CPU_THERMAL=y CONFIG_WATCHDOG=y CONFIG_SUNXI_WATCHDOG=y +CONFIG_MFD_AC100=y CONFIG_MFD_AXP20X=y CONFIG_MFD_AXP20X_I2C=y CONFIG_MFD_AXP20X_RSB=y @@ -129,6 +130,7 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_RTC_CLASS=y # CONFIG_RTC_INTF_SYSFS is not set # CONFIG_RTC_INTF_PROC is not set +CONFIG_RTC_DRV_AC100=y CONFIG_RTC_DRV_SUN6I=y CONFIG_RTC_DRV_SUNXI=y CONFIG_DMADEVICES=y diff --git a/arch/arm/include/debug/brcmstb.S b/arch/arm/include/debug/brcmstb.S index 9113d7b33ae0..52aaed2b936f 100644 --- a/arch/arm/include/debug/brcmstb.S +++ b/arch/arm/include/debug/brcmstb.S @@ -22,7 +22,8 @@ #define UARTA_3390 REG_PHYS_ADDR(0x40a900) #define UARTA_7250 REG_PHYS_ADDR(0x40b400) -#define UARTA_7268 REG_PHYS_ADDR(0x40c000) +#define UARTA_7260 REG_PHYS_ADDR(0x40c000) +#define UARTA_7268 UARTA_7260 #define UARTA_7271 UARTA_7268 #define UARTA_7364 REG_PHYS_ADDR(0x40b000) #define UARTA_7366 UARTA_7364 @@ -62,13 +63,14 @@ /* Chip specific detection starts here */ 20: checkuart(\rp, \rv, 0x33900000, 3390) 21: checkuart(\rp, \rv, 0x72500000, 7250) -22: checkuart(\rp, \rv, 0x72680000, 7268) -23: checkuart(\rp, \rv, 0x72710000, 7271) -24: checkuart(\rp, \rv, 0x73640000, 7364) -25: checkuart(\rp, \rv, 0x73660000, 7366) -26: checkuart(\rp, \rv, 0x07437100, 74371) -27: checkuart(\rp, \rv, 0x74390000, 7439) -28: checkuart(\rp, \rv, 0x74450000, 7445) +22: checkuart(\rp, \rv, 0x72600000, 7260) +23: checkuart(\rp, \rv, 0x72680000, 7268) +24: checkuart(\rp, \rv, 0x72710000, 7271) +25: checkuart(\rp, \rv, 0x73640000, 7364) +26: checkuart(\rp, \rv, 0x73660000, 7366) +27: checkuart(\rp, \rv, 0x07437100, 74371) +28: checkuart(\rp, \rv, 0x74390000, 7439) +29: checkuart(\rp, \rv, 0x74450000, 7445) /* No valid UART found */ 90: mov \rp, #0 diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index c5bbf8bb8c0f..cfd8f60a9268 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -1,7 +1,6 @@ # # Makefile for the linux kernel. # -obj-y := soc.o # CPU-specific support obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o @@ -18,3 +17,36 @@ endif ifeq ($(CONFIG_PM_DEBUG),y) CFLAGS_pm.o += -DDEBUG endif + +# Default sed regexp - multiline due to syntax constraints +define sed-y + "/^->/{s:->#\(.*\):/* \1 */:; \ + s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:->::; p;}" +endef + +# Use filechk to avoid rebuilds when a header changes, but the resulting file +# does not +define filechk_offsets + (set -e; \ + echo "#ifndef $2"; \ + echo "#define $2"; \ + echo "/*"; \ + echo " * DO NOT MODIFY."; \ + echo " *"; \ + echo " * This file was generated by Kbuild"; \ + echo " */"; \ + echo ""; \ + sed -ne $(sed-y); \ + echo ""; \ + echo "#endif" ) +endef + +arch/arm/mach-at91/pm_data-offsets.s: arch/arm/mach-at91/pm_data-offsets.c + $(call if_changed_dep,cc_s_c) + +include/generated/at91_pm_data-offsets.h: arch/arm/mach-at91/pm_data-offsets.s FORCE + $(call filechk,offsets,__PM_DATA_OFFSETS_H__) + +arch/arm/mach-at91/pm_suspend.o: include/generated/at91_pm_data-offsets.h diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index d068ec3cd1f6..656ad409a253 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -14,23 +14,10 @@ #include <asm/mach/arch.h> #include "generic.h" -#include "soc.h" - -static const struct at91_soc rm9200_socs[] = { - AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"), - { /* sentinel */ }, -}; static void __init at91rm9200_dt_device_init(void) { - struct soc_device *soc; - struct device *soc_dev = NULL; - - soc = at91_soc_init(rm9200_socs); - if (soc != NULL) - soc_dev = soc_device_to_device(soc); - - of_platform_default_populate(NULL, NULL, soc_dev); + of_platform_default_populate(NULL, NULL, NULL); at91rm9200_pm_init(); } diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c index ba28e9cc584d..3dbdef4d3cbf 100644 --- a/arch/arm/mach-at91/at91sam9.c +++ b/arch/arm/mach-at91/at91sam9.c @@ -14,60 +14,12 @@ #include <asm/system_misc.h> #include "generic.h" -#include "soc.h" -static const struct at91_soc at91sam9_socs[] = { - AT91_SOC(AT91SAM9260_CIDR_MATCH, 0, "at91sam9260", NULL), - AT91_SOC(AT91SAM9261_CIDR_MATCH, 0, "at91sam9261", NULL), - AT91_SOC(AT91SAM9263_CIDR_MATCH, 0, "at91sam9263", NULL), - AT91_SOC(AT91SAM9G20_CIDR_MATCH, 0, "at91sam9g20", NULL), - AT91_SOC(AT91SAM9RL64_CIDR_MATCH, 0, "at91sam9rl64", NULL), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M11_EXID_MATCH, - "at91sam9m11", "at91sam9g45"), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M10_EXID_MATCH, - "at91sam9m10", "at91sam9g45"), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G46_EXID_MATCH, - "at91sam9g46", "at91sam9g45"), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G45_EXID_MATCH, - "at91sam9g45", "at91sam9g45"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G15_EXID_MATCH, - "at91sam9g15", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G35_EXID_MATCH, - "at91sam9g35", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X35_EXID_MATCH, - "at91sam9x35", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G25_EXID_MATCH, - "at91sam9g25", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X25_EXID_MATCH, - "at91sam9x25", "at91sam9x5"), - AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN12_EXID_MATCH, - "at91sam9cn12", "at91sam9n12"), - AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9N12_EXID_MATCH, - "at91sam9n12", "at91sam9n12"), - AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN11_EXID_MATCH, - "at91sam9cn11", "at91sam9n12"), - AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), - AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), - AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), - { /* sentinel */ }, -}; - -static void __init at91sam9_common_init(void) +static void __init at91sam9_init(void) { - struct soc_device *soc; - struct device *soc_dev = NULL; - - soc = at91_soc_init(at91sam9_socs); - if (soc != NULL) - soc_dev = soc_device_to_device(soc); + of_platform_default_populate(NULL, NULL, NULL); - of_platform_default_populate(NULL, NULL, soc_dev); -} - -static void __init at91sam9_dt_device_init(void) -{ - at91sam9_common_init(); - at91sam9260_pm_init(); + at91sam9_pm_init(); } static const char *const at91_dt_board_compat[] __initconst = { @@ -77,41 +29,6 @@ static const char *const at91_dt_board_compat[] __initconst = { DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9") /* Maintainer: Atmel */ - .init_machine = at91sam9_dt_device_init, + .init_machine = at91sam9_init, .dt_compat = at91_dt_board_compat, MACHINE_END - -static void __init at91sam9g45_dt_device_init(void) -{ - at91sam9_common_init(); - at91sam9g45_pm_init(); -} - -static const char *const at91sam9g45_board_compat[] __initconst = { - "atmel,at91sam9g45", - NULL -}; - -DT_MACHINE_START(at91sam9g45_dt, "Atmel AT91SAM9G45") - /* Maintainer: Atmel */ - .init_machine = at91sam9g45_dt_device_init, - .dt_compat = at91sam9g45_board_compat, -MACHINE_END - -static void __init at91sam9x5_dt_device_init(void) -{ - at91sam9_common_init(); - at91sam9x5_pm_init(); -} - -static const char *const at91sam9x5_board_compat[] __initconst = { - "atmel,at91sam9x5", - "atmel,at91sam9n12", - NULL -}; - -DT_MACHINE_START(at91sam9x5_dt, "Atmel AT91SAM9") - /* Maintainer: Atmel */ - .init_machine = at91sam9x5_dt_device_init, - .dt_compat = at91sam9x5_board_compat, -MACHINE_END diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 28ca57a2060f..f1ead0f13c19 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -13,15 +13,11 @@ #ifdef CONFIG_PM extern void __init at91rm9200_pm_init(void); -extern void __init at91sam9260_pm_init(void); -extern void __init at91sam9g45_pm_init(void); -extern void __init at91sam9x5_pm_init(void); +extern void __init at91sam9_pm_init(void); extern void __init sama5_pm_init(void); #else static inline void __init at91rm9200_pm_init(void) { } -static inline void __init at91sam9260_pm_init(void) { } -static inline void __init at91sam9g45_pm_init(void) { } -static inline void __init at91sam9x5_pm_init(void) { } +static inline void __init at91sam9_pm_init(void) { } static inline void __init sama5_pm_init(void) { } #endif diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index a277981f414d..2cd27c830ab6 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -10,35 +10,22 @@ * (at your option) any later version. */ -#include <linux/gpio.h> -#include <linux/suspend.h> -#include <linux/sched.h> -#include <linux/proc_fs.h> #include <linux/genalloc.h> -#include <linux/interrupt.h> -#include <linux/sysfs.h> -#include <linux/module.h> +#include <linux/io.h> +#include <linux/of_address.h> #include <linux/of.h> #include <linux/of_platform.h> -#include <linux/of_address.h> -#include <linux/platform_device.h> -#include <linux/platform_data/atmel.h> -#include <linux/io.h> +#include <linux/suspend.h> + #include <linux/clk/at91_pmc.h> -#include <asm/irq.h> -#include <linux/atomic.h> -#include <asm/mach/time.h> -#include <asm/mach/irq.h> -#include <asm/fncpy.h> #include <asm/cacheflush.h> +#include <asm/fncpy.h> #include <asm/system_misc.h> #include "generic.h" #include "pm.h" -static void __iomem *pmc; - /* * FIXME: this is needed to communicate between the pinctrl driver and * the PM implementation in the machine. Possibly part of the PM @@ -50,12 +37,13 @@ extern void at91_pinctrl_gpio_suspend(void); extern void at91_pinctrl_gpio_resume(void); #endif -static struct { - unsigned long uhp_udp_mask; - int memctrl; -} at91_pm_data; +static struct at91_pm_data pm_data; -static void __iomem *at91_ramc_base[2]; +#define at91_ramc_read(id, field) \ + __raw_readl(pm_data.ramc[id] + field) + +#define at91_ramc_write(id, field, value) \ + __raw_writel(value, pm_data.ramc[id] + field) static int at91_pm_valid_state(suspend_state_t state) { @@ -91,10 +79,10 @@ static int at91_pm_verify_clocks(void) unsigned long scsr; int i; - scsr = readl(pmc + AT91_PMC_SCSR); + scsr = readl(pm_data.pmc + AT91_PMC_SCSR); /* USB must not be using PLLB */ - if ((scsr & at91_pm_data.uhp_udp_mask) != 0) { + if ((scsr & pm_data.uhp_udp_mask) != 0) { pr_err("AT91: PM - Suspend-to-RAM with USB still active\n"); return 0; } @@ -105,7 +93,7 @@ static int at91_pm_verify_clocks(void) if ((scsr & (AT91_PMC_PCK0 << i)) == 0) continue; - css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; + css = readl(pm_data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; if (css != AT91_PMC_CSS_SLOW) { pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css); return 0; @@ -131,25 +119,18 @@ int at91_suspend_entering_slow_clock(void) } EXPORT_SYMBOL(at91_suspend_entering_slow_clock); -static void (*at91_suspend_sram_fn)(void __iomem *pmc, void __iomem *ramc0, - void __iomem *ramc1, int memctrl); - -extern void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *ramc0, - void __iomem *ramc1, int memctrl); +static void (*at91_suspend_sram_fn)(struct at91_pm_data *); +extern void at91_pm_suspend_in_sram(struct at91_pm_data *pm_data); extern u32 at91_pm_suspend_in_sram_sz; static void at91_pm_suspend(suspend_state_t state) { - unsigned int pm_data = at91_pm_data.memctrl; - - pm_data |= (state == PM_SUSPEND_MEM) ? - AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0; + pm_data.mode = (state == PM_SUSPEND_MEM) ? AT91_PM_SLOW_CLOCK : 0; flush_cache_all(); outer_disable(); - at91_suspend_sram_fn(pmc, at91_ramc_base[0], - at91_ramc_base[1], pm_data); + at91_suspend_sram_fn(&pm_data); outer_resume(); } @@ -224,12 +205,6 @@ static struct platform_device at91_cpuidle_device = { .name = "cpuidle-at91", }; -static void at91_pm_set_standby(void (*at91_standby)(void)) -{ - if (at91_standby) - at91_cpuidle_device.dev.platform_data = at91_standby; -} - /* * The AT91RM9200 goes into self-refresh mode with this command, and will * terminate self-refresh automatically on the next SDRAM access. @@ -241,20 +216,15 @@ static void at91_pm_set_standby(void (*at91_standby)(void)) */ static void at91rm9200_standby(void) { - u32 lpr = at91_ramc_read(0, AT91_MC_SDRAMC_LPR); - asm volatile( "b 1f\n\t" ".align 5\n\t" "1: mcr p15, 0, %0, c7, c10, 4\n\t" - " str %0, [%1, %2]\n\t" - " str %3, [%1, %4]\n\t" + " str %2, [%1, %3]\n\t" " mcr p15, 0, %0, c7, c0, 4\n\t" - " str %5, [%1, %2]" : - : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91_MC_SDRAMC_LPR), - "r" (1), "r" (AT91_MC_SDRAMC_SRR), - "r" (lpr)); + : "r" (0), "r" (pm_data.ramc[0]), + "r" (1), "r" (AT91_MC_SDRAMC_SRR)); } /* We manage both DDRAM/SDRAM controllers, we need more than one value to @@ -265,12 +235,27 @@ static void at91_ddr_standby(void) /* Those two values allow us to delay self-refresh activation * to the maximum. */ u32 lpr0, lpr1 = 0; + u32 mdr, saved_mdr0, saved_mdr1 = 0; u32 saved_lpr0, saved_lpr1 = 0; - if (at91_ramc_base[1]) { + /* LPDDR1 --> force DDR2 mode during self-refresh */ + saved_mdr0 = at91_ramc_read(0, AT91_DDRSDRC_MDR); + if ((saved_mdr0 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) { + mdr = saved_mdr0 & ~AT91_DDRSDRC_MD; + mdr |= AT91_DDRSDRC_MD_DDR2; + at91_ramc_write(0, AT91_DDRSDRC_MDR, mdr); + } + + if (pm_data.ramc[1]) { saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR); lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB; lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; + saved_mdr1 = at91_ramc_read(1, AT91_DDRSDRC_MDR); + if ((saved_mdr1 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) { + mdr = saved_mdr1 & ~AT91_DDRSDRC_MD; + mdr |= AT91_DDRSDRC_MD_DDR2; + at91_ramc_write(1, AT91_DDRSDRC_MDR, mdr); + } } saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR); @@ -279,14 +264,17 @@ static void at91_ddr_standby(void) /* self-refresh mode now */ at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0); - if (at91_ramc_base[1]) + if (pm_data.ramc[1]) at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1); cpu_do_idle(); + at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr0); at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); - if (at91_ramc_base[1]) + if (pm_data.ramc[1]) { + at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr1); at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); + } } static void sama5d3_ddr_standby(void) @@ -313,7 +301,7 @@ static void at91sam9_sdram_standby(void) u32 lpr0, lpr1 = 0; u32 saved_lpr0, saved_lpr1 = 0; - if (at91_ramc_base[1]) { + if (pm_data.ramc[1]) { saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR); lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB; lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; @@ -325,21 +313,33 @@ static void at91sam9_sdram_standby(void) /* self-refresh mode now */ at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0); - if (at91_ramc_base[1]) + if (pm_data.ramc[1]) at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1); cpu_do_idle(); at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0); - if (at91_ramc_base[1]) + if (pm_data.ramc[1]) at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); } +struct ramc_info { + void (*idle)(void); + unsigned int memctrl; +}; + +static const struct ramc_info ramc_infos[] __initconst = { + { .idle = at91rm9200_standby, .memctrl = AT91_MEMCTRL_MC}, + { .idle = at91sam9_sdram_standby, .memctrl = AT91_MEMCTRL_SDRAMC}, + { .idle = at91_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR}, + { .idle = sama5d3_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR}, +}; + static const struct of_device_id const ramc_ids[] __initconst = { - { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby }, - { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby }, - { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby }, - { .compatible = "atmel,sama5d3-ddramc", .data = sama5d3_ddr_standby }, + { .compatible = "atmel,at91rm9200-sdramc", .data = &ramc_infos[0] }, + { .compatible = "atmel,at91sam9260-sdramc", .data = &ramc_infos[1] }, + { .compatible = "atmel,at91sam9g45-ddramc", .data = &ramc_infos[2] }, + { .compatible = "atmel,sama5d3-ddramc", .data = &ramc_infos[3] }, { /*sentinel*/ } }; @@ -348,15 +348,18 @@ static __init void at91_dt_ramc(void) struct device_node *np; const struct of_device_id *of_id; int idx = 0; - const void *standby = NULL; + void *standby = NULL; + const struct ramc_info *ramc; for_each_matching_node_and_match(np, ramc_ids, &of_id) { - at91_ramc_base[idx] = of_iomap(np, 0); - if (!at91_ramc_base[idx]) + pm_data.ramc[idx] = of_iomap(np, 0); + if (!pm_data.ramc[idx]) panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx); + ramc = of_id->data; if (!standby) - standby = of_id->data; + standby = ramc->idle; + pm_data.memctrl = ramc->memctrl; idx++; } @@ -369,7 +372,7 @@ static __init void at91_dt_ramc(void) return; } - at91_pm_set_standby(standby); + at91_cpuidle_device.dev.platform_data = standby; } static void at91rm9200_idle(void) @@ -378,12 +381,12 @@ static void at91rm9200_idle(void) * Disable the processor clock. The processor will be automatically * re-enabled by an interrupt or by a reset. */ - writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR); + writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR); } static void at91sam9_idle(void) { - writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR); + writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR); cpu_do_idle(); } @@ -433,31 +436,46 @@ static void __init at91_pm_sram_init(void) &at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz); } +struct pmc_info { + unsigned long uhp_udp_mask; +}; + +static const struct pmc_info pmc_infos[] __initconst = { + { .uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP }, + { .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP }, + { .uhp_udp_mask = AT91SAM926x_PMC_UHP }, +}; + static const struct of_device_id atmel_pmc_ids[] __initconst = { - { .compatible = "atmel,at91rm9200-pmc" }, - { .compatible = "atmel,at91sam9260-pmc" }, - { .compatible = "atmel,at91sam9g45-pmc" }, - { .compatible = "atmel,at91sam9n12-pmc" }, - { .compatible = "atmel,at91sam9x5-pmc" }, - { .compatible = "atmel,sama5d3-pmc" }, - { .compatible = "atmel,sama5d2-pmc" }, + { .compatible = "atmel,at91rm9200-pmc", .data = &pmc_infos[0] }, + { .compatible = "atmel,at91sam9260-pmc", .data = &pmc_infos[1] }, + { .compatible = "atmel,at91sam9g45-pmc", .data = &pmc_infos[2] }, + { .compatible = "atmel,at91sam9n12-pmc", .data = &pmc_infos[1] }, + { .compatible = "atmel,at91sam9x5-pmc", .data = &pmc_infos[1] }, + { .compatible = "atmel,sama5d3-pmc", .data = &pmc_infos[1] }, + { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] }, { /* sentinel */ }, }; static void __init at91_pm_init(void (*pm_idle)(void)) { struct device_node *pmc_np; + const struct of_device_id *of_id; + const struct pmc_info *pmc; if (at91_cpuidle_device.dev.platform_data) platform_device_register(&at91_cpuidle_device); - pmc_np = of_find_matching_node(NULL, atmel_pmc_ids); - pmc = of_iomap(pmc_np, 0); - if (!pmc) { + pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id); + pm_data.pmc = of_iomap(pmc_np, 0); + if (!pm_data.pmc) { pr_err("AT91: PM not supported, PMC not found\n"); return; } + pmc = of_id->data; + pm_data.uhp_udp_mask = pmc->uhp_udp_mask; + if (pm_idle) arm_pm_idle = pm_idle; @@ -478,40 +496,17 @@ void __init at91rm9200_pm_init(void) */ at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0); - at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP; - at91_pm_data.memctrl = AT91_MEMCTRL_MC; - at91_pm_init(at91rm9200_idle); } -void __init at91sam9260_pm_init(void) -{ - at91_dt_ramc(); - at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC; - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; - at91_pm_init(at91sam9_idle); -} - -void __init at91sam9g45_pm_init(void) -{ - at91_dt_ramc(); - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP; - at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; - at91_pm_init(at91sam9_idle); -} - -void __init at91sam9x5_pm_init(void) +void __init at91sam9_pm_init(void) { at91_dt_ramc(); - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; - at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; at91_pm_init(at91sam9_idle); } void __init sama5_pm_init(void) { at91_dt_ramc(); - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; - at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; at91_pm_init(NULL); } diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index bf980c6ef294..fc0f7d048187 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h @@ -17,24 +17,20 @@ #include <soc/at91/at91sam9_ddrsdr.h> #include <soc/at91/at91sam9_sdramc.h> -#ifndef __ASSEMBLY__ -#define at91_ramc_read(id, field) \ - __raw_readl(at91_ramc_base[id] + field) - -#define at91_ramc_write(id, field, value) \ - __raw_writel(value, at91_ramc_base[id] + field) -#endif - #define AT91_MEMCTRL_MC 0 #define AT91_MEMCTRL_SDRAMC 1 #define AT91_MEMCTRL_DDRSDR 2 -#define AT91_PM_MEMTYPE_MASK 0x0f - -#define AT91_PM_MODE_OFFSET 4 -#define AT91_PM_MODE_MASK 0x01 -#define AT91_PM_MODE(x) (((x) & AT91_PM_MODE_MASK) << AT91_PM_MODE_OFFSET) - #define AT91_PM_SLOW_CLOCK 0x01 +#ifndef __ASSEMBLY__ +struct at91_pm_data { + void __iomem *pmc; + void __iomem *ramc[2]; + unsigned long uhp_udp_mask; + unsigned int memctrl; + unsigned int mode; +}; +#endif + #endif diff --git a/arch/arm/mach-at91/pm_data-offsets.c b/arch/arm/mach-at91/pm_data-offsets.c new file mode 100644 index 000000000000..30302cb16df0 --- /dev/null +++ b/arch/arm/mach-at91/pm_data-offsets.c @@ -0,0 +1,13 @@ +#include <linux/stddef.h> +#include <linux/kbuild.h> +#include "pm.h" + +int main(void) +{ + DEFINE(PM_DATA_PMC, offsetof(struct at91_pm_data, pmc)); + DEFINE(PM_DATA_RAMC0, offsetof(struct at91_pm_data, ramc[0])); + DEFINE(PM_DATA_RAMC1, offsetof(struct at91_pm_data, ramc[1])); + DEFINE(PM_DATA_MEMCTRL, offsetof(struct at91_pm_data, memctrl)); + DEFINE(PM_DATA_MODE, offsetof(struct at91_pm_data, mode)); + return 0; +} diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index a25defda3d22..96781daa671a 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -4,7 +4,7 @@ * Copyright (C) 2006 Savin Zlobec * * AT91SAM9 support: - * Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee + * Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -14,6 +14,7 @@ #include <linux/linkage.h> #include <linux/clk/at91_pmc.h> #include "pm.h" +#include "generated/at91_pm_data-offsets.h" #define SRAMC_SELF_FRESH_ACTIVE 0x01 #define SRAMC_SELF_FRESH_EXIT 0x00 @@ -72,13 +73,9 @@ tmp2 .req r5 .arm /* - * void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *sdramc, - * void __iomem *ramc1, int memctrl) + * void at91_suspend_sram_fn(struct at91_pm_data*) * @input param: - * @r0: base address of AT91_PMC - * @r1: base address of SDRAM Controller (SDRAM, DDRSDR, or AT91_SYS) - * @r2: base address of second SDRAM Controller or 0 if not present - * @r3: pm information + * @r0: base address of struct at91_pm_data */ /* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */ .align 3 @@ -90,16 +87,16 @@ ENTRY(at91_pm_suspend_in_sram) mov tmp1, #0 mcr p15, 0, tmp1, c7, c10, 4 - str r0, .pmc_base - str r1, .sramc_base - str r2, .sramc1_base - - and r0, r3, #AT91_PM_MEMTYPE_MASK - str r0, .memtype - - lsr r0, r3, #AT91_PM_MODE_OFFSET - and r0, r0, #AT91_PM_MODE_MASK - str r0, .pm_mode + ldr tmp1, [r0, #PM_DATA_PMC] + str tmp1, .pmc_base + ldr tmp1, [r0, #PM_DATA_RAMC0] + str tmp1, .sramc_base + ldr tmp1, [r0, #PM_DATA_RAMC1] + str tmp1, .sramc1_base + ldr tmp1, [r0, #PM_DATA_MEMCTRL] + str tmp1, .memtype + ldr tmp1, [r0, #PM_DATA_MODE] + str tmp1, .pm_mode /* Active the self-refresh mode */ mov r0, #SRAMC_SELF_FRESH_ACTIVE diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c index b272c45b400f..6d157d0ead8e 100644 --- a/arch/arm/mach-at91/sama5.c +++ b/arch/arm/mach-at91/sama5.c @@ -15,60 +15,10 @@ #include <asm/system_misc.h> #include "generic.h" -#include "soc.h" - -static const struct at91_soc sama5_socs[] = { - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, - "sama5d21", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH, - "sama5d22", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH, - "sama5d23", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH, - "sama5d24", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH, - "sama5d24", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH, - "sama5d26", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH, - "sama5d27", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH, - "sama5d27", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, - "sama5d28", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, - "sama5d28", "sama5d2"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, - "sama5d31", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, - "sama5d33", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D34_EXID_MATCH, - "sama5d34", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D35_EXID_MATCH, - "sama5d35", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D36_EXID_MATCH, - "sama5d36", "sama5d3"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D41_EXID_MATCH, - "sama5d41", "sama5d4"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D42_EXID_MATCH, - "sama5d42", "sama5d4"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D43_EXID_MATCH, - "sama5d43", "sama5d4"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D44_EXID_MATCH, - "sama5d44", "sama5d4"), - { /* sentinel */ }, -}; static void __init sama5_dt_device_init(void) { - struct soc_device *soc; - struct device *soc_dev = NULL; - - soc = at91_soc_init(sama5_socs); - if (soc != NULL) - soc_dev = soc_device_to_device(soc); - - of_platform_default_populate(NULL, NULL, soc_dev); + of_platform_default_populate(NULL, NULL, NULL); sama5_pm_init(); } diff --git a/arch/arm/mach-at91/soc.c b/arch/arm/mach-at91/soc.c deleted file mode 100644 index c6fda75ddb89..000000000000 --- a/arch/arm/mach-at91/soc.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2015 Atmel - * - * Alexandre Belloni <alexandre.belloni@free-electrons.com - * Boris Brezillon <boris.brezillon@free-electrons.com - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * - */ - -#define pr_fmt(fmt) "AT91: " fmt - -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_platform.h> -#include <linux/slab.h> -#include <linux/sys_soc.h> - -#include "soc.h" - -#define AT91_DBGU_CIDR 0x40 -#define AT91_DBGU_EXID 0x44 -#define AT91_CHIPID_CIDR 0x00 -#define AT91_CHIPID_EXID 0x04 -#define AT91_CIDR_VERSION(x) ((x) & 0x1f) -#define AT91_CIDR_EXT BIT(31) -#define AT91_CIDR_MATCH_MASK 0x7fffffe0 - -static int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid) -{ - struct device_node *np; - void __iomem *regs; - - np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-dbgu"); - if (!np) - np = of_find_compatible_node(NULL, NULL, - "atmel,at91sam9260-dbgu"); - if (!np) - return -ENODEV; - - regs = of_iomap(np, 0); - of_node_put(np); - - if (!regs) { - pr_warn("Could not map DBGU iomem range"); - return -ENXIO; - } - - *cidr = readl(regs + AT91_DBGU_CIDR); - *exid = readl(regs + AT91_DBGU_EXID); - - iounmap(regs); - - return 0; -} - -static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid) -{ - struct device_node *np; - void __iomem *regs; - - np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid"); - if (!np) - return -ENODEV; - - regs = of_iomap(np, 0); - of_node_put(np); - - if (!regs) { - pr_warn("Could not map DBGU iomem range"); - return -ENXIO; - } - - *cidr = readl(regs + AT91_CHIPID_CIDR); - *exid = readl(regs + AT91_CHIPID_EXID); - - iounmap(regs); - - return 0; -} - -struct soc_device * __init at91_soc_init(const struct at91_soc *socs) -{ - struct soc_device_attribute *soc_dev_attr; - const struct at91_soc *soc; - struct soc_device *soc_dev; - u32 cidr, exid; - int ret; - - /* - * With SAMA5D2 and later SoCs, CIDR and EXID registers are no more - * in the dbgu device but in the chipid device whose purpose is only - * to expose these two registers. - */ - ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid); - if (ret) - ret = at91_get_cidr_exid_from_chipid(&cidr, &exid); - if (ret) { - if (ret == -ENODEV) - pr_warn("Could not find identification node"); - return NULL; - } - - for (soc = socs; soc->name; soc++) { - if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK)) - continue; - - if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid) - break; - } - - if (!soc->name) { - pr_warn("Could not find matching SoC description\n"); - return NULL; - } - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return NULL; - - soc_dev_attr->family = soc->family; - soc_dev_attr->soc_id = soc->name; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", - AT91_CIDR_VERSION(cidr)); - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); - pr_warn("Could not register SoC device\n"); - return NULL; - } - - if (soc->family) - pr_info("Detected SoC family: %s\n", soc->family); - pr_info("Detected SoC: %s, revision %X\n", soc->name, - AT91_CIDR_VERSION(cidr)); - - return soc_dev; -} diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index a0e66d8200c5..f9389c5910e7 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -198,7 +198,9 @@ config ARCH_BRCMSTB select HAVE_ARM_ARCH_TIMER select BRCMSTB_L2_IRQ select BCM7120_L2_IRQ + select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE + select ZONE_DMA if ARM_LPAE select SOC_BRCMSTB select SOC_BUS help diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 6f1e1299cab9..b5625d009288 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -828,6 +828,9 @@ static struct regulator_consumer_supply fixed_supplies[] = { /* Baseboard 1.8V: 5V -> TPS73701DCQ -> 1.8V */ REGULATOR_SUPPLY("DVDD", "1-0018"), + + /* UI card 3.3V: 5V -> TPS73701DCQ -> 3.3V */ + REGULATOR_SUPPLY("vcc", "1-0020"), }; /* TPS65070 voltage regulator support */ @@ -1213,6 +1216,7 @@ static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { static struct vpif_capture_config da850_vpif_capture_config = { .subdev_info = da850_vpif_capture_sdev_info, .subdev_count = ARRAY_SIZE(da850_vpif_capture_sdev_info), + .i2c_adapter_id = 1, .chan_config[0] = { .inputs = da850_ch0_inputs, .input_count = ARRAY_SIZE(da850_ch0_inputs), diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 023480b75244..20f1874a5657 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -744,7 +744,8 @@ static int davinci_phy_fixup(struct phy_device *phydev) return 0; } -#define HAS_ATA IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) +#define HAS_ATA (IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \ + IS_ENABLED(CONFIG_PATA_BK3710)) #define HAS_NOR IS_ENABLED(CONFIG_MTD_PHYSMAP) diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index f702d4fc8eb8..cb176826d1cb 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -119,7 +119,8 @@ static struct platform_device davinci_nand_device = { }, }; -#define HAS_ATA IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) +#define HAS_ATA (IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \ + IS_ENABLED(CONFIG_PATA_BK3710)) #ifdef CONFIG_I2C /* CPLD Register 0 bits to control ATA */ diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index 0a7838852649..0c02aaad0539 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -163,7 +163,8 @@ static struct davinci_mmc_config davinci_ntosd2_mmc_config = { .wires = 4, }; -#define HAS_ATA IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) +#define HAS_ATA (IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \ + IS_ENABLED(CONFIG_PATA_BK3710)) #define HAS_NAND IS_ENABLED(CONFIG_MTD_NAND_DAVINCI) diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index 073c458d0c67..bd88470f3e5c 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -304,6 +304,11 @@ static struct clk usb20_clk = { .gpsc = 1, }; +static struct clk cppi41_clk = { + .name = "cppi41", + .parent = &usb20_clk, +}; + static struct clk aemif_clk = { .name = "aemif", .parent = &pll0_sysclk3, @@ -413,6 +418,7 @@ static struct clk_lookup da830_clks[] = { CLK("davinci-mcasp.1", NULL, &mcasp1_clk), CLK("davinci-mcasp.2", NULL, &mcasp2_clk), CLK("musb-da8xx", "usb20", &usb20_clk), + CLK("cppi41-dmaengine", NULL, &cppi41_clk), CLK(NULL, "aemif", &aemif_clk), CLK(NULL, "aintc", &aintc_clk), CLK(NULL, "secu_mgr", &secu_mgr_clk), diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index ccad2f99dfc9..07d6f0eb8c82 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -401,6 +401,11 @@ static struct clk usb20_clk = { .gpsc = 1, }; +static struct clk cppi41_clk = { + .name = "cppi41", + .parent = &usb20_clk, +}; + static struct clk spi0_clk = { .name = "spi0", .parent = &pll0_sysclk2, @@ -560,6 +565,7 @@ static struct clk_lookup da850_clks[] = { CLK("davinci-nand.0", "aemif", &aemif_nand_clk), CLK("ohci-da8xx", "usb11", &usb11_clk), CLK("musb-da8xx", "usb20", &usb20_clk), + CLK("cppi41-dmaengine", NULL, &cppi41_clk), CLK("spi_davinci.0", NULL, &spi0_clk), CLK("spi_davinci.1", NULL, &spi1_clk), CLK("vpif", NULL, &vpif_clk), diff --git a/arch/arm/mach-davinci/da8xx-dt.c b/arch/arm/mach-davinci/da8xx-dt.c index e3cef503cd8f..5699ce39e64f 100644 --- a/arch/arm/mach-davinci/da8xx-dt.c +++ b/arch/arm/mach-davinci/da8xx-dt.c @@ -53,6 +53,7 @@ static struct of_dev_auxdata da850_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("ti,da830-musb", 0x01e00000, "musb-da8xx", NULL), OF_DEV_AUXDATA("ti,da830-usb-phy", 0x01c1417c, "da8xx-usb-phy", NULL), OF_DEV_AUXDATA("ti,da850-ahci", 0x01e18000, "ahci_da850", NULL), + OF_DEV_AUXDATA("ti,da850-vpif", 0x01e17000, "vpif", NULL), {} }; diff --git a/arch/arm/mach-davinci/pdata-quirks.c b/arch/arm/mach-davinci/pdata-quirks.c index 5b57da475065..329f5402ad1d 100644 --- a/arch/arm/mach-davinci/pdata-quirks.c +++ b/arch/arm/mach-davinci/pdata-quirks.c @@ -10,26 +10,202 @@ #include <linux/kernel.h> #include <linux/of_platform.h> +#include <media/i2c/tvp514x.h> +#include <media/i2c/adv7343.h> + #include <mach/common.h> +#include <mach/da8xx.h> struct pdata_init { const char *compatible; void (*fn)(void); }; +#define TVP5147_CH0 "tvp514x-0" +#define TVP5147_CH1 "tvp514x-1" + +/* VPIF capture configuration */ +static struct tvp514x_platform_data tvp5146_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1, +}; + +#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +static const struct vpif_input da850_ch0_inputs[] = { + { + .input = { + .index = 0, + .name = "Composite", + .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, + .std = TVP514X_STD_ALL, + }, + .input_route = INPUT_CVBS_VI2B, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .subdev_name = TVP5147_CH0, + }, +}; + +static const struct vpif_input da850_ch1_inputs[] = { + { + .input = { + .index = 0, + .name = "S-Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, + .std = TVP514X_STD_ALL, + }, + .input_route = INPUT_SVIDEO_VI2C_VI1C, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .subdev_name = TVP5147_CH1, + }, +}; + +static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { + { + .name = TVP5147_CH0, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5d), + .platform_data = &tvp5146_pdata, + }, + }, + { + .name = TVP5147_CH1, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5c), + .platform_data = &tvp5146_pdata, + }, + }, +}; + +static struct vpif_capture_config da850_vpif_capture_config = { + .subdev_info = da850_vpif_capture_sdev_info, + .subdev_count = ARRAY_SIZE(da850_vpif_capture_sdev_info), + .chan_config[0] = { + .inputs = da850_ch0_inputs, + .input_count = ARRAY_SIZE(da850_ch0_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + .chan_config[1] = { + .inputs = da850_ch1_inputs, + .input_count = ARRAY_SIZE(da850_ch1_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + .card_name = "DA850/OMAP-L138 Video Capture", +}; + +static void __init da850_vpif_legacy_register_capture(void) +{ + int ret; + + ret = da850_register_vpif_capture(&da850_vpif_capture_config); + if (ret) + pr_warn("%s: VPIF capture setup failed: %d\n", + __func__, ret); +} + +static void __init da850_vpif_capture_legacy_init_lcdk(void) +{ + da850_vpif_capture_config.subdev_count = 1; + da850_vpif_legacy_register_capture(); +} + +static void __init da850_vpif_capture_legacy_init_evm(void) +{ + da850_vpif_legacy_register_capture(); +} + +static struct adv7343_platform_data adv7343_pdata = { + .mode_config = { + .dac = { 1, 1, 1 }, + }, + .sd_config = { + .sd_dac_out = { 1 }, + }, +}; + +static struct vpif_subdev_info da850_vpif_subdev[] = { + { + .name = "adv7343", + .board_info = { + I2C_BOARD_INFO("adv7343", 0x2a), + .platform_data = &adv7343_pdata, + }, + }, +}; + +static const struct vpif_output da850_ch0_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPOSITE_ID, + }, + { + .output = { + .index = 1, + .name = "S-Video", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_SVIDEO_ID, + }, +}; + +static struct vpif_display_config da850_vpif_display_config = { + .subdevinfo = da850_vpif_subdev, + .subdev_count = ARRAY_SIZE(da850_vpif_subdev), + .chan_config[0] = { + .outputs = da850_ch0_outputs, + .output_count = ARRAY_SIZE(da850_ch0_outputs), + }, + .card_name = "DA850/OMAP-L138 Video Display", +}; + +static void __init da850_vpif_display_legacy_init_evm(void) +{ + int ret; + + ret = da850_register_vpif_display(&da850_vpif_display_config); + if (ret) + pr_warn("%s: VPIF display setup failed: %d\n", + __func__, ret); +} + static void pdata_quirks_check(struct pdata_init *quirks) { while (quirks->compatible) { if (of_machine_is_compatible(quirks->compatible)) { if (quirks->fn) quirks->fn(); - break; } quirks++; } } static struct pdata_init pdata_quirks[] __initdata = { + { "ti,da850-lcdk", da850_vpif_capture_legacy_init_lcdk, }, + { "ti,da850-evm", da850_vpif_display_legacy_init_evm, }, + { "ti,da850-evm", da850_vpif_capture_legacy_init_evm, }, { /* sentinel */ }, }; diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c index 0afd201ab980..efb80354f303 100644 --- a/arch/arm/mach-davinci/pm.c +++ b/arch/arm/mach-davinci/pm.c @@ -108,7 +108,6 @@ static int davinci_pm_enter(suspend_state_t state) int ret = 0; switch (state) { - case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: davinci_pm_suspend(); break; diff --git a/arch/arm/mach-gemini/Kconfig b/arch/arm/mach-gemini/Kconfig index 6f066ee4bf24..06c8b095154c 100644 --- a/arch/arm/mach-gemini/Kconfig +++ b/arch/arm/mach-gemini/Kconfig @@ -1,40 +1,13 @@ -if ARCH_GEMINI - -menu "Cortina Systems Gemini Implementations" - -config MACH_NAS4220B - bool "Raidsonic NAS-4220-B" - select GEMINI_MEM_SWAP - help - Say Y here if you intend to run this kernel on a - Raidsonic NAS-4220-B. - -config MACH_RUT100 - bool "Teltonika RUT100" - select GEMINI_MEM_SWAP - help - Say Y here if you intend to run this kernel on a - Teltonika 3G Router RUT100. - -config MACH_WBD111 - bool "Wiliboard WBD-111" - select GEMINI_MEM_SWAP - help - Say Y here if you intend to run this kernel on a - Wiliboard WBD-111. - -config MACH_WBD222 - bool "Wiliboard WBD-222" - select GEMINI_MEM_SWAP - help - Say Y here if you intend to run this kernel on a - Wiliboard WBD-222. - -endmenu - -config GEMINI_MEM_SWAP - bool "Gemini memory is swapped" - help - Say Y here if Gemini memory is swapped by bootloader. - -endif +menuconfig ARCH_GEMINI + bool "Cortina Systems Gemini" + depends on ARCH_MULTI_V4 + select ARM_APPENDED_DTB # Old Redboot bootloaders deployed + select FARADAY_FTINTC010 + select FTTMR010_TIMER + select GPIO_FTGPIO010 + select GPIOLIB + select POWER_RESET + select POWER_RESET_GEMINI_POWEROFF + select POWER_RESET_SYSCON + help + Support for the Cortina Systems Gemini family SoCs diff --git a/arch/arm/mach-gemini/Makefile b/arch/arm/mach-gemini/Makefile index 7963a77be637..ca0db5477180 100644 --- a/arch/arm/mach-gemini/Makefile +++ b/arch/arm/mach-gemini/Makefile @@ -1,13 +1,2 @@ -# -# Makefile for the linux kernel. -# - -# Object file lists. - -obj-y := irq.o mm.o time.o devices.o gpio.o idle.o reset.o - -# Board-specific support -obj-$(CONFIG_MACH_NAS4220B) += board-nas4220b.o -obj-$(CONFIG_MACH_RUT100) += board-rut1xx.o -obj-$(CONFIG_MACH_WBD111) += board-wbd111.o -obj-$(CONFIG_MACH_WBD222) += board-wbd222.o +# Makefile for Cortina systems Gemini +obj-y := board-dt.o diff --git a/arch/arm/mach-gemini/Makefile.boot b/arch/arm/mach-gemini/Makefile.boot deleted file mode 100644 index 683f52b20e3d..000000000000 --- a/arch/arm/mach-gemini/Makefile.boot +++ /dev/null @@ -1,9 +0,0 @@ -ifeq ($(CONFIG_GEMINI_MEM_SWAP),y) - zreladdr-y += 0x00008000 -params_phys-y := 0x00000100 -initrd_phys-y := 0x00800000 -else - zreladdr-y += 0x10008000 -params_phys-y := 0x10000100 -initrd_phys-y := 0x10800000 -endif diff --git a/arch/arm/mach-gemini/board-dt.c b/arch/arm/mach-gemini/board-dt.c new file mode 100644 index 000000000000..c0c0ebdd551e --- /dev/null +++ b/arch/arm/mach-gemini/board-dt.c @@ -0,0 +1,62 @@ +/* + * Gemini Device Tree boot support + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/system_misc.h> +#include <asm/proc-fns.h> + +#ifdef CONFIG_DEBUG_GEMINI +/* This is needed for LL-debug/earlyprintk/debug-macro.S */ +static struct map_desc gemini_io_desc[] __initdata = { + { + .virtual = CONFIG_DEBUG_UART_VIRT, + .pfn = __phys_to_pfn(CONFIG_DEBUG_UART_PHYS), + .length = SZ_4K, + .type = MT_DEVICE, + }, +}; + +static void __init gemini_map_io(void) +{ + iotable_init(gemini_io_desc, ARRAY_SIZE(gemini_io_desc)); +} +#else +#define gemini_map_io NULL +#endif + +static void gemini_idle(void) +{ + /* + * Because of broken hardware we have to enable interrupts or the CPU + * will never wakeup... Acctualy it is not very good to enable + * interrupts first since scheduler can miss a tick, but there is + * no other way around this. Platforms that needs it for power saving + * should enable it in init code, since by default it is + * disabled. + */ + + /* FIXME: Enabling interrupts here is racy! */ + local_irq_enable(); + cpu_do_idle(); +} + +static void __init gemini_init_machine(void) +{ + arm_pm_idle = gemini_idle; +} + +static const char *gemini_board_compat[] = { + "cortina,gemini", + NULL, +}; + +DT_MACHINE_START(GEMINI_DT, "Gemini (Device Tree)") + .map_io = gemini_map_io, + .init_machine = gemini_init_machine, + .dt_compat = gemini_board_compat, +MACHINE_END diff --git a/arch/arm/mach-gemini/board-nas4220b.c b/arch/arm/mach-gemini/board-nas4220b.c deleted file mode 100644 index 18b12796acf9..000000000000 --- a/arch/arm/mach-gemini/board-nas4220b.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Support for Raidsonic NAS-4220-B - * - * Copyright (C) 2009 Janos Laube <janos.dev@gmail.com> - * - * based on rut1xx.c - * Copyright (C) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/input.h> -#include <linux/gpio_keys.h> -#include <linux/io.h> - -#include <asm/setup.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <asm/mach/time.h> - -#include <mach/hardware.h> -#include <mach/global_reg.h> - -#include "common.h" - -static struct gpio_led ib4220b_leds[] = { - { - .name = "nas4220b:orange:hdd", - .default_trigger = "none", - .gpio = 60, - }, - { - .name = "nas4220b:green:os", - .default_trigger = "heartbeat", - .gpio = 62, - }, -}; - -static struct gpio_led_platform_data ib4220b_leds_data = { - .num_leds = ARRAY_SIZE(ib4220b_leds), - .leds = ib4220b_leds, -}; - -static struct platform_device ib4220b_led_device = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &ib4220b_leds_data, - }, -}; - -static struct gpio_keys_button ib4220b_keys[] = { - { - .code = KEY_SETUP, - .gpio = 61, - .active_low = 1, - .desc = "Backup Button", - .type = EV_KEY, - }, - { - .code = KEY_RESTART, - .gpio = 63, - .active_low = 1, - .desc = "Softreset Button", - .type = EV_KEY, - }, -}; - -static struct gpio_keys_platform_data ib4220b_keys_data = { - .buttons = ib4220b_keys, - .nbuttons = ARRAY_SIZE(ib4220b_keys), -}; - -static struct platform_device ib4220b_key_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &ib4220b_keys_data, - }, -}; - -static void __init ib4220b_init(void) -{ - gemini_gpio_init(); - platform_register_uart(); - platform_register_pflash(SZ_16M, NULL, 0); - platform_device_register(&ib4220b_led_device); - platform_device_register(&ib4220b_key_device); - platform_register_rtc(); -} - -MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B") - .atag_offset = 0x100, - .map_io = gemini_map_io, - .init_irq = gemini_init_irq, - .init_time = gemini_timer_init, - .init_machine = ib4220b_init, - .restart = gemini_restart, -MACHINE_END diff --git a/arch/arm/mach-gemini/board-rut1xx.c b/arch/arm/mach-gemini/board-rut1xx.c deleted file mode 100644 index 7a675f88ffd6..000000000000 --- a/arch/arm/mach-gemini/board-rut1xx.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Support for Teltonika RUT1xx - * - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/input.h> -#include <linux/gpio_keys.h> -#include <linux/sizes.h> - -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <asm/mach/time.h> - -#include "common.h" - -static struct gpio_keys_button rut1xx_keys[] = { - { - .code = KEY_SETUP, - .gpio = 60, - .active_low = 1, - .desc = "Reset to defaults", - .type = EV_KEY, - }, -}; - -static struct gpio_keys_platform_data rut1xx_keys_data = { - .buttons = rut1xx_keys, - .nbuttons = ARRAY_SIZE(rut1xx_keys), -}; - -static struct platform_device rut1xx_keys_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &rut1xx_keys_data, - }, -}; - -static struct gpio_led rut100_leds[] = { - { - .name = "Power", - .default_trigger = "heartbeat", - .gpio = 17, - }, - { - .name = "GSM", - .default_trigger = "default-on", - .gpio = 7, - .active_low = 1, - }, -}; - -static struct gpio_led_platform_data rut100_leds_data = { - .num_leds = ARRAY_SIZE(rut100_leds), - .leds = rut100_leds, -}; - -static struct platform_device rut1xx_leds = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &rut100_leds_data, - }, -}; - -static void __init rut1xx_init(void) -{ - gemini_gpio_init(); - platform_register_uart(); - platform_register_pflash(SZ_8M, NULL, 0); - platform_device_register(&rut1xx_leds); - platform_device_register(&rut1xx_keys_device); - platform_register_rtc(); -} - -MACHINE_START(RUT100, "Teltonika RUT100") - .atag_offset = 0x100, - .map_io = gemini_map_io, - .init_irq = gemini_init_irq, - .init_time = gemini_timer_init, - .init_machine = rut1xx_init, - .restart = gemini_restart, -MACHINE_END diff --git a/arch/arm/mach-gemini/board-wbd111.c b/arch/arm/mach-gemini/board-wbd111.c deleted file mode 100644 index 14c56f3f0ec2..000000000000 --- a/arch/arm/mach-gemini/board-wbd111.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Support for Wiliboard WBD-111 - * - * Copyright (C) 2009 Imre Kaloz <kaloz@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/input.h> -#include <linux/skbuff.h> -#include <linux/gpio_keys.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <asm/mach/time.h> - - -#include "common.h" - -static struct gpio_keys_button wbd111_keys[] = { - { - .code = KEY_SETUP, - .gpio = 5, - .active_low = 1, - .desc = "reset", - .type = EV_KEY, - }, -}; - -static struct gpio_keys_platform_data wbd111_keys_data = { - .buttons = wbd111_keys, - .nbuttons = ARRAY_SIZE(wbd111_keys), -}; - -static struct platform_device wbd111_keys_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &wbd111_keys_data, - }, -}; - -static struct gpio_led wbd111_leds[] = { - { - .name = "L3red", - .gpio = 1, - }, - { - .name = "L4green", - .gpio = 2, - }, - { - .name = "L4red", - .gpio = 3, - }, - { - .name = "L3green", - .gpio = 5, - }, -}; - -static struct gpio_led_platform_data wbd111_leds_data = { - .num_leds = ARRAY_SIZE(wbd111_leds), - .leds = wbd111_leds, -}; - -static struct platform_device wbd111_leds_device = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &wbd111_leds_data, - }, -}; - -static struct mtd_partition wbd111_partitions[] = { - { - .name = "RedBoot", - .offset = 0, - .size = 0x020000, - .mask_flags = MTD_WRITEABLE, - } , { - .name = "kernel", - .offset = 0x020000, - .size = 0x100000, - } , { - .name = "rootfs", - .offset = 0x120000, - .size = 0x6a0000, - } , { - .name = "VCTL", - .offset = 0x7c0000, - .size = 0x010000, - .mask_flags = MTD_WRITEABLE, - } , { - .name = "cfg", - .offset = 0x7d0000, - .size = 0x010000, - .mask_flags = MTD_WRITEABLE, - } , { - .name = "FIS", - .offset = 0x7e0000, - .size = 0x010000, - .mask_flags = MTD_WRITEABLE, - } -}; -#define wbd111_num_partitions ARRAY_SIZE(wbd111_partitions) - -static void __init wbd111_init(void) -{ - gemini_gpio_init(); - platform_register_uart(); - platform_register_pflash(SZ_8M, wbd111_partitions, - wbd111_num_partitions); - platform_device_register(&wbd111_leds_device); - platform_device_register(&wbd111_keys_device); - platform_register_rtc(); -} - -MACHINE_START(WBD111, "Wiliboard WBD-111") - .atag_offset = 0x100, - .map_io = gemini_map_io, - .init_irq = gemini_init_irq, - .init_time = gemini_timer_init, - .init_machine = wbd111_init, - .restart = gemini_restart, -MACHINE_END diff --git a/arch/arm/mach-gemini/board-wbd222.c b/arch/arm/mach-gemini/board-wbd222.c deleted file mode 100644 index 6070282ce243..000000000000 --- a/arch/arm/mach-gemini/board-wbd222.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Support for Wiliboard WBD-222 - * - * Copyright (C) 2009 Imre Kaloz <kaloz@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/input.h> -#include <linux/skbuff.h> -#include <linux/gpio_keys.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <asm/mach/time.h> - - -#include "common.h" - -static struct gpio_keys_button wbd222_keys[] = { - { - .code = KEY_SETUP, - .gpio = 5, - .active_low = 1, - .desc = "reset", - .type = EV_KEY, - }, -}; - -static struct gpio_keys_platform_data wbd222_keys_data = { - .buttons = wbd222_keys, - .nbuttons = ARRAY_SIZE(wbd222_keys), -}; - -static struct platform_device wbd222_keys_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &wbd222_keys_data, - }, -}; - -static struct gpio_led wbd222_leds[] = { - { - .name = "L3red", - .gpio = 1, - }, - { - .name = "L4green", - .gpio = 2, - }, - { - .name = "L4red", - .gpio = 3, - }, - { - .name = "L3green", - .gpio = 5, - }, -}; - -static struct gpio_led_platform_data wbd222_leds_data = { - .num_leds = ARRAY_SIZE(wbd222_leds), - .leds = wbd222_leds, -}; - -static struct platform_device wbd222_leds_device = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &wbd222_leds_data, - }, -}; - -static struct mtd_partition wbd222_partitions[] = { - { - .name = "RedBoot", - .offset = 0, - .size = 0x020000, - .mask_flags = MTD_WRITEABLE, - } , { - .name = "kernel", - .offset = 0x020000, - .size = 0x100000, - } , { - .name = "rootfs", - .offset = 0x120000, - .size = 0x6a0000, - } , { - .name = "VCTL", - .offset = 0x7c0000, - .size = 0x010000, - .mask_flags = MTD_WRITEABLE, - } , { - .name = "cfg", - .offset = 0x7d0000, - .size = 0x010000, - .mask_flags = MTD_WRITEABLE, - } , { - .name = "FIS", - .offset = 0x7e0000, - .size = 0x010000, - .mask_flags = MTD_WRITEABLE, - } -}; -#define wbd222_num_partitions ARRAY_SIZE(wbd222_partitions) - -static void __init wbd222_init(void) -{ - gemini_gpio_init(); - platform_register_uart(); - platform_register_pflash(SZ_8M, wbd222_partitions, - wbd222_num_partitions); - platform_device_register(&wbd222_leds_device); - platform_device_register(&wbd222_keys_device); - platform_register_rtc(); -} - -MACHINE_START(WBD222, "Wiliboard WBD-222") - .atag_offset = 0x100, - .map_io = gemini_map_io, - .init_irq = gemini_init_irq, - .init_time = gemini_timer_init, - .init_machine = wbd222_init, - .restart = gemini_restart, -MACHINE_END diff --git a/arch/arm/mach-gemini/common.h b/arch/arm/mach-gemini/common.h deleted file mode 100644 index dd883698ff7e..000000000000 --- a/arch/arm/mach-gemini/common.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Common Gemini architecture functions - * - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __GEMINI_COMMON_H__ -#define __GEMINI_COMMON_H__ - -#include <linux/reboot.h> - -struct mtd_partition; - -extern void gemini_map_io(void); -extern void gemini_init_irq(void); -extern void gemini_timer_init(void); -extern void gemini_gpio_init(void); -extern void platform_register_rtc(void); - -/* Common platform devices registration functions */ -extern int platform_register_uart(void); -extern int platform_register_pflash(unsigned int size, - struct mtd_partition *parts, - unsigned int nr_parts); - -extern void gemini_restart(enum reboot_mode mode, const char *cmd); - -#endif /* __GEMINI_COMMON_H__ */ diff --git a/arch/arm/mach-gemini/devices.c b/arch/arm/mach-gemini/devices.c deleted file mode 100644 index 5cff29818b73..000000000000 --- a/arch/arm/mach-gemini/devices.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Common devices definition for Gemini - * - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/serial_8250.h> -#include <linux/mtd/physmap.h> - -#include <mach/irqs.h> -#include <mach/hardware.h> -#include <mach/global_reg.h> - -static struct plat_serial8250_port serial_platform_data[] = { - { - .membase = (void *)IO_ADDRESS(GEMINI_UART_BASE), - .mapbase = GEMINI_UART_BASE, - .irq = IRQ_UART, - .uartclk = UART_CLK, - .regshift = 2, - .iotype = UPIO_MEM, - .type = PORT_16550A, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_FIXED_TYPE, - }, - {}, -}; - -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_platform_data, - }, -}; - -int platform_register_uart(void) -{ - return platform_device_register(&serial_device); -} - -static struct resource flash_resource = { - .start = GEMINI_FLASH_BASE, - .flags = IORESOURCE_MEM, -}; - -static struct physmap_flash_data pflash_platform_data = {}; - -static struct platform_device pflash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &pflash_platform_data, - }, - .resource = &flash_resource, - .num_resources = 1, -}; - -int platform_register_pflash(unsigned int size, struct mtd_partition *parts, - unsigned int nr_parts) -{ - unsigned int reg; - - reg = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_STATUS); - - if ((reg & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) - return -ENXIO; - - if (reg & FLASH_WIDTH_16BIT) - pflash_platform_data.width = 2; - else - pflash_platform_data.width = 1; - - /* enable parallel flash pins and disable others */ - reg = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_MISC_CTRL); - reg &= ~PFLASH_PADS_DISABLE; - reg |= SFLASH_PADS_DISABLE | NAND_PADS_DISABLE; - __raw_writel(reg, IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_MISC_CTRL); - - flash_resource.end = flash_resource.start + size - 1; - - pflash_platform_data.parts = parts; - pflash_platform_data.nr_parts = nr_parts; - - return platform_device_register(&pflash_device); -} - -static struct resource gemini_rtc_resources[] = { - [0] = { - .start = GEMINI_RTC_BASE, - .end = GEMINI_RTC_BASE + 0x24, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_RTC, - .end = IRQ_RTC, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device gemini_rtc_device = { - .name = "rtc-gemini", - .id = 0, - .num_resources = ARRAY_SIZE(gemini_rtc_resources), - .resource = gemini_rtc_resources, -}; - -int __init platform_register_rtc(void) -{ - return platform_device_register(&gemini_rtc_device); -} - diff --git a/arch/arm/mach-gemini/gpio.c b/arch/arm/mach-gemini/gpio.c deleted file mode 100644 index 469a76ea0459..000000000000 --- a/arch/arm/mach-gemini/gpio.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Gemini gpiochip and interrupt routines - * - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * Based on plat-mxc/gpio.c: - * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de> - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/gpio/driver.h> - -#include <mach/hardware.h> -#include <mach/irqs.h> - -#define GPIO_BASE(x) IO_ADDRESS(GEMINI_GPIO_BASE(x)) -#define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE) - -/* GPIO registers definition */ -#define GPIO_DATA_OUT 0x0 -#define GPIO_DATA_IN 0x4 -#define GPIO_DIR 0x8 -#define GPIO_DATA_SET 0x10 -#define GPIO_DATA_CLR 0x14 -#define GPIO_PULL_EN 0x18 -#define GPIO_PULL_TYPE 0x1C -#define GPIO_INT_EN 0x20 -#define GPIO_INT_STAT 0x24 -#define GPIO_INT_MASK 0x2C -#define GPIO_INT_CLR 0x30 -#define GPIO_INT_TYPE 0x34 -#define GPIO_INT_BOTH_EDGE 0x38 -#define GPIO_INT_LEVEL 0x3C -#define GPIO_DEBOUNCE_EN 0x40 -#define GPIO_DEBOUNCE_PRESCALE 0x44 - -#define GPIO_PORT_NUM 3 - -static void _set_gpio_irqenable(void __iomem *base, unsigned int index, - int enable) -{ - unsigned int reg; - - reg = __raw_readl(base + GPIO_INT_EN); - reg = (reg & (~(1 << index))) | (!!enable << index); - __raw_writel(reg, base + GPIO_INT_EN); -} - -static void gpio_ack_irq(struct irq_data *d) -{ - unsigned int gpio = irq_to_gpio(d->irq); - void __iomem *base = GPIO_BASE(gpio / 32); - - __raw_writel(1 << (gpio % 32), base + GPIO_INT_CLR); -} - -static void gpio_mask_irq(struct irq_data *d) -{ - unsigned int gpio = irq_to_gpio(d->irq); - void __iomem *base = GPIO_BASE(gpio / 32); - - _set_gpio_irqenable(base, gpio % 32, 0); -} - -static void gpio_unmask_irq(struct irq_data *d) -{ - unsigned int gpio = irq_to_gpio(d->irq); - void __iomem *base = GPIO_BASE(gpio / 32); - - _set_gpio_irqenable(base, gpio % 32, 1); -} - -static int gpio_set_irq_type(struct irq_data *d, unsigned int type) -{ - unsigned int gpio = irq_to_gpio(d->irq); - unsigned int gpio_mask = 1 << (gpio % 32); - void __iomem *base = GPIO_BASE(gpio / 32); - unsigned int reg_both, reg_level, reg_type; - - reg_type = __raw_readl(base + GPIO_INT_TYPE); - reg_level = __raw_readl(base + GPIO_INT_LEVEL); - reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE); - - switch (type) { - case IRQ_TYPE_EDGE_BOTH: - reg_type &= ~gpio_mask; - reg_both |= gpio_mask; - break; - case IRQ_TYPE_EDGE_RISING: - reg_type &= ~gpio_mask; - reg_both &= ~gpio_mask; - reg_level &= ~gpio_mask; - break; - case IRQ_TYPE_EDGE_FALLING: - reg_type &= ~gpio_mask; - reg_both &= ~gpio_mask; - reg_level |= gpio_mask; - break; - case IRQ_TYPE_LEVEL_HIGH: - reg_type |= gpio_mask; - reg_level &= ~gpio_mask; - break; - case IRQ_TYPE_LEVEL_LOW: - reg_type |= gpio_mask; - reg_level |= gpio_mask; - break; - default: - return -EINVAL; - } - - __raw_writel(reg_type, base + GPIO_INT_TYPE); - __raw_writel(reg_level, base + GPIO_INT_LEVEL); - __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE); - - gpio_ack_irq(d); - - return 0; -} - -static void gpio_irq_handler(struct irq_desc *desc) -{ - unsigned int port = (unsigned int)irq_desc_get_handler_data(desc); - unsigned int gpio_irq_no, irq_stat; - - irq_stat = __raw_readl(GPIO_BASE(port) + GPIO_INT_STAT); - - gpio_irq_no = GPIO_IRQ_BASE + port * 32; - for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) { - - if ((irq_stat & 1) == 0) - continue; - - generic_handle_irq(gpio_irq_no); - } -} - -static struct irq_chip gpio_irq_chip = { - .name = "GPIO", - .irq_ack = gpio_ack_irq, - .irq_mask = gpio_mask_irq, - .irq_unmask = gpio_unmask_irq, - .irq_set_type = gpio_set_irq_type, -}; - -static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, - int dir) -{ - void __iomem *base = GPIO_BASE(offset / 32); - unsigned int reg; - - reg = __raw_readl(base + GPIO_DIR); - if (dir) - reg |= 1 << (offset % 32); - else - reg &= ~(1 << (offset % 32)); - __raw_writel(reg, base + GPIO_DIR); -} - -static void gemini_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - void __iomem *base = GPIO_BASE(offset / 32); - - if (value) - __raw_writel(1 << (offset % 32), base + GPIO_DATA_SET); - else - __raw_writel(1 << (offset % 32), base + GPIO_DATA_CLR); -} - -static int gemini_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *base = GPIO_BASE(offset / 32); - - return (__raw_readl(base + GPIO_DATA_IN) >> (offset % 32)) & 1; -} - -static int gemini_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - _set_gpio_direction(chip, offset, 0); - return 0; -} - -static int gemini_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - _set_gpio_direction(chip, offset, 1); - gemini_gpio_set(chip, offset, value); - return 0; -} - -static struct gpio_chip gemini_gpio_chip = { - .label = "Gemini", - .direction_input = gemini_gpio_direction_input, - .get = gemini_gpio_get, - .direction_output = gemini_gpio_direction_output, - .set = gemini_gpio_set, - .base = 0, - .ngpio = GPIO_PORT_NUM * 32, -}; - -void __init gemini_gpio_init(void) -{ - int i, j; - - for (i = 0; i < GPIO_PORT_NUM; i++) { - /* disable, unmask and clear all interrupts */ - __raw_writel(0x0, GPIO_BASE(i) + GPIO_INT_EN); - __raw_writel(0x0, GPIO_BASE(i) + GPIO_INT_MASK); - __raw_writel(~0x0, GPIO_BASE(i) + GPIO_INT_CLR); - - for (j = GPIO_IRQ_BASE + i * 32; - j < GPIO_IRQ_BASE + (i + 1) * 32; j++) { - irq_set_chip_and_handler(j, &gpio_irq_chip, - handle_edge_irq); - irq_clear_status_flags(j, IRQ_NOREQUEST); - } - - irq_set_chained_handler_and_data(IRQ_GPIO(i), gpio_irq_handler, - (void *)i); - } - - BUG_ON(gpiochip_add_data(&gemini_gpio_chip, NULL)); -} diff --git a/arch/arm/mach-gemini/idle.c b/arch/arm/mach-gemini/idle.c deleted file mode 100644 index ddf8ec9d203b..000000000000 --- a/arch/arm/mach-gemini/idle.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * arch/arm/mach-gemini/idle.c - */ - -#include <linux/init.h> -#include <asm/system_misc.h> -#include <asm/proc-fns.h> - -static void gemini_idle(void) -{ - /* - * Because of broken hardware we have to enable interrupts or the CPU - * will never wakeup... Acctualy it is not very good to enable - * interrupts first since scheduler can miss a tick, but there is - * no other way around this. Platforms that needs it for power saving - * should enable it in init code, since by default it is - * disabled. - */ - - /* FIXME: Enabling interrupts here is racy! */ - local_irq_enable(); - cpu_do_idle(); -} - -static int __init gemini_idle_init(void) -{ - arm_pm_idle = gemini_idle; - return 0; -} - -arch_initcall(gemini_idle_init); diff --git a/arch/arm/mach-gemini/include/mach/entry-macro.S b/arch/arm/mach-gemini/include/mach/entry-macro.S deleted file mode 100644 index f044e430bfa4..000000000000 --- a/arch/arm/mach-gemini/include/mach/entry-macro.S +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Low-level IRQ helper macros for Gemini platform. - * - * Copyright (C) 2001-2006 Storlink, Corp. - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include <mach/hardware.h> - -#define IRQ_STATUS 0x14 - - .macro get_irqnr_preamble, base, tmp - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \irqstat, =IO_ADDRESS(GEMINI_INTERRUPT_BASE + IRQ_STATUS) - ldr \irqnr, [\irqstat] - cmp \irqnr, #0 - beq 2313f - mov \tmp, \irqnr - mov \irqnr, #0 -2312: - tst \tmp, #1 - bne 2313f - add \irqnr, \irqnr, #1 - mov \tmp, \tmp, lsr #1 - cmp \irqnr, #31 - bcc 2312b -2313: - .endm diff --git a/arch/arm/mach-gemini/include/mach/global_reg.h b/arch/arm/mach-gemini/include/mach/global_reg.h deleted file mode 100644 index de7ff7e849fc..000000000000 --- a/arch/arm/mach-gemini/include/mach/global_reg.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * This file contains the hardware definitions for Gemini. - * - * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef __MACH_GLOBAL_REG_H -#define __MACH_GLOBAL_REG_H - -/* Global Word ID Register*/ -#define GLOBAL_ID 0x00 - -#define CHIP_ID(reg) ((reg) >> 8) -#define CHIP_REVISION(reg) ((reg) & 0xFF) - -/* Global Status Register */ -#define GLOBAL_STATUS 0x04 - -#define CPU_BIG_ENDIAN (1 << 31) -#define PLL_OSC_30M (1 << 30) /* else 60MHz */ - -#define OPERATION_MODE_MASK (0xF << 26) -#define OPM_IDDQ (0xF << 26) -#define OPM_NAND (0xE << 26) -#define OPM_RING (0xD << 26) -#define OPM_DIRECT_BOOT (0xC << 26) -#define OPM_USB1_PHY_TEST (0xB << 26) -#define OPM_USB0_PHY_TEST (0xA << 26) -#define OPM_SATA1_PHY_TEST (0x9 << 26) -#define OPM_SATA0_PHY_TEST (0x8 << 26) -#define OPM_ICE_ARM (0x7 << 26) -#define OPM_ICE_FARADAY (0x6 << 26) -#define OPM_PLL_BYPASS (0x5 << 26) -#define OPM_DEBUG (0x4 << 26) -#define OPM_BURN_IN (0x3 << 26) -#define OPM_MBIST (0x2 << 26) -#define OPM_SCAN (0x1 << 26) -#define OPM_REAL (0x0 << 26) - -#define FLASH_TYPE_MASK (0x3 << 24) -#define FLASH_TYPE_NAND_2K (0x3 << 24) -#define FLASH_TYPE_NAND_512 (0x2 << 24) -#define FLASH_TYPE_PARALLEL (0x1 << 24) -#define FLASH_TYPE_SERIAL (0x0 << 24) -/* if parallel */ -#define FLASH_WIDTH_16BIT (1 << 23) /* else 8 bit */ -/* if serial */ -#define FLASH_ATMEL (1 << 23) /* else STM */ - -#define FLASH_SIZE_MASK (0x3 << 21) -#define NAND_256M (0x3 << 21) /* and more */ -#define NAND_128M (0x2 << 21) -#define NAND_64M (0x1 << 21) -#define NAND_32M (0x0 << 21) -#define ATMEL_16M (0x3 << 21) /* and more */ -#define ATMEL_8M (0x2 << 21) -#define ATMEL_4M_2M (0x1 << 21) -#define ATMEL_1M (0x0 << 21) /* and less */ -#define STM_32M (1 << 22) /* and more */ -#define STM_16M (0 << 22) /* and less */ - -#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */ - -#define CPU_AHB_RATIO_MASK (0x3 << 18) -#define CPU_AHB_1_1 (0x0 << 18) -#define CPU_AHB_3_2 (0x1 << 18) -#define CPU_AHB_24_13 (0x2 << 18) -#define CPU_AHB_2_1 (0x3 << 18) - -#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130) -#define AHB_SPEED_TO_REG(x) ((((x - 130)) / 10) << 15) - -/* it is posible to override some settings, use >> OVERRIDE_xxxx_SHIFT */ -#define OVERRIDE_FLASH_TYPE_SHIFT 16 -#define OVERRIDE_FLASH_WIDTH_SHIFT 16 -#define OVERRIDE_FLASH_SIZE_SHIFT 16 -#define OVERRIDE_CPU_AHB_RATIO_SHIFT 15 -#define OVERRIDE_AHB_SPEED_SHIFT 15 - -/* Global PLL Control Register */ -#define GLOBAL_PLL_CTRL 0x08 - -#define PLL_BYPASS (1 << 31) -#define PLL_POWER_DOWN (1 << 8) -#define PLL_CONTROL_Q (0x1F << 0) - -/* Global Soft Reset Control Register */ -#define GLOBAL_RESET 0x0C - -#define RESET_GLOBAL (1 << 31) -#define RESET_CPU1 (1 << 30) -#define RESET_TVE (1 << 28) -#define RESET_SATA1 (1 << 27) -#define RESET_SATA0 (1 << 26) -#define RESET_CIR (1 << 25) -#define RESET_EXT_DEV (1 << 24) -#define RESET_WD (1 << 23) -#define RESET_GPIO2 (1 << 22) -#define RESET_GPIO1 (1 << 21) -#define RESET_GPIO0 (1 << 20) -#define RESET_SSP (1 << 19) -#define RESET_UART (1 << 18) -#define RESET_TIMER (1 << 17) -#define RESET_RTC (1 << 16) -#define RESET_INT1 (1 << 15) -#define RESET_INT0 (1 << 14) -#define RESET_LCD (1 << 13) -#define RESET_LPC (1 << 12) -#define RESET_APB (1 << 11) -#define RESET_DMA (1 << 10) -#define RESET_USB1 (1 << 9) -#define RESET_USB0 (1 << 8) -#define RESET_PCI (1 << 7) -#define RESET_GMAC1 (1 << 6) -#define RESET_GMAC0 (1 << 5) -#define RESET_SECURITY (1 << 4) -#define RESET_RAID (1 << 3) -#define RESET_IDE (1 << 2) -#define RESET_FLASH (1 << 1) -#define RESET_DRAM (1 << 0) - -/* Global IO Pad Driving Capability Control Register */ -#define GLOBAL_IO_DRIVING_CTRL 0x10 - -#define DRIVING_CURRENT_MASK 0x3 - -/* here 00-4mA, 01-8mA, 10-12mA, 11-16mA */ -#define GPIO1_PADS_31_28_SHIFT 28 -#define GPIO0_PADS_31_16_SHIFT 26 -#define GPIO0_PADS_15_0_SHIFT 24 -#define PCI_AND_EXT_RESET_PADS_SHIFT 22 -#define IDE_PADS_SHIFT 20 -#define GMAC1_PADS_SHIFT 18 -#define GMAC0_PADS_SHIFT 16 -/* DRAM is not in mA and poorly documented */ -#define DRAM_CLOCK_PADS_SHIFT 8 -#define DRAM_DATA_PADS_SHIFT 4 -#define DRAM_CONTROL_PADS_SHIFT 0 - -/* Global IO Pad Slew Rate Control Register */ -#define GLOBAL_IO_SLEW_RATE_CTRL 0x14 - -#define GPIO1_PADS_31_28_SLOW (1 << 10) -#define GPIO0_PADS_31_16_SLOW (1 << 9) -#define GPIO0_PADS_15_0_SLOW (1 << 8) -#define PCI_PADS_SLOW (1 << 7) -#define IDE_PADS_SLOW (1 << 6) -#define GMAC1_PADS_SLOW (1 << 5) -#define GMAC0_PADS_SLOW (1 << 4) -#define DRAM_CLOCK_PADS_SLOW (1 << 1) -#define DRAM_IO_PADS_SLOW (1 << 0) - -/* - * General skew control defines - * 16 steps, each step is around 0.2ns - */ -#define SKEW_MASK 0xF - -/* Global IDE PAD Skew Control Register */ -#define GLOBAL_IDE_SKEW_CTRL 0x18 - -#define IDE1_HOST_STROBE_DELAY_SHIFT 28 -#define IDE1_DEVICE_STROBE_DELAY_SHIFT 24 -#define IDE1_OUTPUT_IO_SKEW_SHIFT 20 -#define IDE1_INPUT_IO_SKEW_SHIFT 16 -#define IDE0_HOST_STROBE_DELAY_SHIFT 12 -#define IDE0_DEVICE_STROBE_DELAY_SHIFT 8 -#define IDE0_OUTPUT_IO_SKEW_SHIFT 4 -#define IDE0_INPUT_IO_SKEW_SHIFT 0 - -/* Global GMAC Control Pad Skew Control Register */ -#define GLOBAL_GMAC_CTRL_SKEW_CTRL 0x1C - -#define GMAC1_TXC_SKEW_SHIFT 28 -#define GMAC1_TXEN_SKEW_SHIFT 24 -#define GMAC1_RXC_SKEW_SHIFT 20 -#define GMAC1_RXDV_SKEW_SHIFT 16 -#define GMAC0_TXC_SKEW_SHIFT 12 -#define GMAC0_TXEN_SKEW_SHIFT 8 -#define GMAC0_RXC_SKEW_SHIFT 4 -#define GMAC0_RXDV_SKEW_SHIFT 0 - -/* Global GMAC0 Data PAD Skew Control Register */ -#define GLOBAL_GMAC0_DATA_SKEW_CTRL 0x20 -/* Global GMAC1 Data PAD Skew Control Register */ -#define GLOBAL_GMAC1_DATA_SKEW_CTRL 0x24 - -#define GMAC_TXD_SKEW_SHIFT(x) (((x) * 4) + 16) -#define GMAC_RXD_SKEW_SHIFT(x) ((x) * 4) - -/* CPU has two AHB busses. */ - -/* Global Arbitration0 Control Register */ -#define GLOBAL_ARBITRATION0_CTRL 0x28 - -#define BOOT_CONTROLLER_HIGH_PRIO (1 << 3) -#define DMA_BUS1_HIGH_PRIO (1 << 2) -#define CPU0_HIGH_PRIO (1 << 0) - -/* Global Arbitration1 Control Register */ -#define GLOBAL_ARBITRATION1_CTRL 0x2C - -#define TVE_HIGH_PRIO (1 << 9) -#define PCI_HIGH_PRIO (1 << 8) -#define USB1_HIGH_PRIO (1 << 7) -#define USB0_HIGH_PRIO (1 << 6) -#define GMAC1_HIGH_PRIO (1 << 5) -#define GMAC0_HIGH_PRIO (1 << 4) -#define SECURITY_HIGH_PRIO (1 << 3) -#define RAID_HIGH_PRIO (1 << 2) -#define IDE_HIGH_PRIO (1 << 1) -#define DMA_BUS2_HIGH_PRIO (1 << 0) - -/* Common bits for both arbitration registers */ -#define BURST_LENGTH_SHIFT 16 -#define BURST_LENGTH_MASK (0x3F << 16) - -/* Miscellaneous Control Register */ -#define GLOBAL_MISC_CTRL 0x30 - -#define MEMORY_SPACE_SWAP (1 << 31) -#define USB1_PLUG_MINIB (1 << 30) /* else plug is mini-A */ -#define USB0_PLUG_MINIB (1 << 29) -#define GMAC_GMII (1 << 28) -#define GMAC_1_ENABLE (1 << 27) -/* TODO: define ATA/SATA bits */ -#define USB1_VBUS_ON (1 << 23) -#define USB0_VBUS_ON (1 << 22) -#define APB_CLKOUT_ENABLE (1 << 21) -#define TVC_CLKOUT_ENABLE (1 << 20) -#define EXT_CLKIN_ENABLE (1 << 19) -#define PCI_66MHZ (1 << 18) /* else 33 MHz */ -#define PCI_CLKOUT_ENABLE (1 << 17) -#define LPC_CLKOUT_ENABLE (1 << 16) -#define USB1_WAKEUP_ON (1 << 15) -#define USB0_WAKEUP_ON (1 << 14) -/* TODO: define PCI idle detect bits */ -#define TVC_PADS_ENABLE (1 << 9) -#define SSP_PADS_ENABLE (1 << 8) -#define LCD_PADS_ENABLE (1 << 7) -#define LPC_PADS_ENABLE (1 << 6) -#define PCI_PADS_ENABLE (1 << 5) -#define IDE_PADS_ENABLE (1 << 4) -#define DRAM_PADS_POWER_DOWN (1 << 3) -#define NAND_PADS_DISABLE (1 << 2) -#define PFLASH_PADS_DISABLE (1 << 1) -#define SFLASH_PADS_DISABLE (1 << 0) - -/* Global Clock Control Register */ -#define GLOBAL_CLOCK_CTRL 0x34 - -#define POWER_STATE_G0 (1 << 31) -#define POWER_STATE_S1 (1 << 30) /* else it is S3/S4 state */ -#define SECURITY_APB_AHB (1 << 29) -/* else Security APB clk will be 0.75xAHB */ -/* TODO: TVC clock divider */ -#define PCI_CLKRUN_ENABLE (1 << 16) -#define BOOT_CLK_DISABLE (1 << 13) -#define TVC_CLK_DISABLE (1 << 12) -#define FLASH_CLK_DISABLE (1 << 11) -#define DDR_CLK_DISABLE (1 << 10) -#define PCI_CLK_DISABLE (1 << 9) -#define IDE_CLK_DISABLE (1 << 8) -#define USB1_CLK_DISABLE (1 << 7) -#define USB0_CLK_DISABLE (1 << 6) -#define SATA1_CLK_DISABLE (1 << 5) -#define SATA0_CLK_DISABLE (1 << 4) -#define GMAC1_CLK_DISABLE (1 << 3) -#define GMAC0_CLK_DISABLE (1 << 2) -#define SECURITY_CLK_DISABLE (1 << 1) - -/* TODO: other registers definitions if needed */ - -#endif /* __MACH_GLOBAL_REG_H */ diff --git a/arch/arm/mach-gemini/include/mach/hardware.h b/arch/arm/mach-gemini/include/mach/hardware.h deleted file mode 100644 index f0390f184742..000000000000 --- a/arch/arm/mach-gemini/include/mach/hardware.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file contains the hardware definitions for Gemini. - * - * Copyright (C) 2001-2006 Storlink, Corp. - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef __MACH_HARDWARE_H -#define __MACH_HARDWARE_H - -/* - * Memory Map definitions - */ -#ifdef CONFIG_GEMINI_MEM_SWAP -# define GEMINI_DRAM_BASE 0x00000000 -# define GEMINI_SRAM_BASE 0x70000000 -#else -# define GEMINI_SRAM_BASE 0x00000000 -# define GEMINI_DRAM_BASE 0x10000000 -#endif -#define GEMINI_FLASH_BASE 0x30000000 -#define GEMINI_GLOBAL_BASE 0x40000000 -#define GEMINI_WAQTCHDOG_BASE 0x41000000 -#define GEMINI_UART_BASE 0x42000000 -#define GEMINI_TIMER_BASE 0x43000000 -#define GEMINI_LCD_BASE 0x44000000 -#define GEMINI_RTC_BASE 0x45000000 -#define GEMINI_SATA_BASE 0x46000000 -#define GEMINI_LPC_HOST_BASE 0x47000000 -#define GEMINI_LPC_IO_BASE 0x47800000 -#define GEMINI_INTERRUPT_BASE 0x48000000 -/* TODO: Different interrupt controllers when SMP - * #define GEMINI_INTERRUPT0_BASE 0x48000000 - * #define GEMINI_INTERRUPT1_BASE 0x49000000 - */ -#define GEMINI_SSP_CTRL_BASE 0x4A000000 -#define GEMINI_POWER_CTRL_BASE 0x4B000000 -#define GEMINI_CIR_BASE 0x4C000000 -#define GEMINI_GPIO_BASE(x) (0x4D000000 + (x) * 0x1000000) -#define GEMINI_PCI_IO_BASE 0x50000000 -#define GEMINI_PCI_MEM_BASE 0x58000000 -#define GEMINI_TOE_BASE 0x60000000 -#define GEMINI_GMAC0_BASE 0x6000A000 -#define GEMINI_GMAC1_BASE 0x6000E000 -#define GEMINI_SECURITY_BASE 0x62000000 -#define GEMINI_IDE0_BASE 0x63000000 -#define GEMINI_IDE1_BASE 0x63400000 -#define GEMINI_RAID_BASE 0x64000000 -#define GEMINI_FLASH_CTRL_BASE 0x65000000 -#define GEMINI_DRAM_CTRL_BASE 0x66000000 -#define GEMINI_GENERAL_DMA_BASE 0x67000000 -#define GEMINI_USB0_BASE 0x68000000 -#define GEMINI_USB1_BASE 0x69000000 -#define GEMINI_BIG_ENDIAN_BASE 0x80000000 - - -/* - * UART Clock when System clk is 150MHz - */ -#define UART_CLK 48000000 - -/* - * macro to get at IO space when running virtually - */ -#define IO_ADDRESS(x) IOMEM((((x) & 0xFFF00000) >> 4) | ((x) & 0x000FFFFF) | 0xF0000000) - -#endif diff --git a/arch/arm/mach-gemini/include/mach/irqs.h b/arch/arm/mach-gemini/include/mach/irqs.h deleted file mode 100644 index 06bc47e77e8b..000000000000 --- a/arch/arm/mach-gemini/include/mach/irqs.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2001-2006 Storlink, Corp. - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __MACH_IRQS_H__ -#define __MACH_IRQS_H__ - -#define IRQ_SERIRQ1 31 -#define IRQ_SERIRQ0 30 -#define IRQ_PCID 29 -#define IRQ_PCIC 28 -#define IRQ_PCIB 27 -#define IRQ_PWR 26 -#define IRQ_CIR 25 -#define IRQ_GPIO(x) (22 + (x)) -#define IRQ_SSP 21 -#define IRQ_LPC 20 -#define IRQ_LCD 19 -#define IRQ_UART 18 -#define IRQ_RTC 17 -#define IRQ_TIMER3 16 -#define IRQ_TIMER2 15 -#define IRQ_TIMER1 14 -#define IRQ_FLASH 12 -#define IRQ_USB1 11 -#define IRQ_USB0 10 -#define IRQ_DMA 9 -#define IRQ_PCI 8 -#define IRQ_IPSEC 7 -#define IRQ_RAID 6 -#define IRQ_IDE1 5 -#define IRQ_IDE0 4 -#define IRQ_WATCHDOG 3 -#define IRQ_GMAC1 2 -#define IRQ_GMAC0 1 -#define IRQ_IPI 0 - -#define NORMAL_IRQ_NUM 32 - -#define GPIO_IRQ_BASE NORMAL_IRQ_NUM -#define GPIO_IRQ_NUM (3 * 32) - -#define ARCH_TIMER_IRQ IRQ_TIMER2 - -#define NR_IRQS (NORMAL_IRQ_NUM + GPIO_IRQ_NUM) - -#endif /* __MACH_IRQS_H__ */ diff --git a/arch/arm/mach-gemini/include/mach/uncompress.h b/arch/arm/mach-gemini/include/mach/uncompress.h deleted file mode 100644 index 02e225673acb..000000000000 --- a/arch/arm/mach-gemini/include/mach/uncompress.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * Based on mach-pxa/include/mach/uncompress.h: - * Copyright: (C) 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __MACH_UNCOMPRESS_H -#define __MACH_UNCOMPRESS_H - -#include <linux/serial_reg.h> -#include <mach/hardware.h> - -static volatile unsigned long * const UART = (unsigned long *)GEMINI_UART_BASE; - -/* - * The following code assumes the serial port has already been - * initialized by the bootloader. If you didn't setup a port in - * your bootloader then nothing will appear (which might be desired). - */ -static inline void putc(char c) -{ - while (!(UART[UART_LSR] & UART_LSR_THRE)) - barrier(); - UART[UART_TX] = c; -} - -static inline void flush(void) -{ -} - -/* - * nothing to do - */ -#define arch_decomp_setup() - -#endif /* __MACH_UNCOMPRESS_H */ diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c deleted file mode 100644 index d929b3ff18fd..000000000000 --- a/arch/arm/mach-gemini/irq.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Interrupt routines for Gemini - * - * Copyright (C) 2001-2006 Storlink, Corp. - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include <linux/init.h> -#include <linux/io.h> -#include <linux/ioport.h> -#include <linux/stddef.h> -#include <linux/list.h> -#include <linux/sched.h> -#include <linux/cpu.h> - -#include <asm/irq.h> -#include <asm/mach/irq.h> -#include <asm/system_misc.h> -#include <mach/hardware.h> - -#define IRQ_SOURCE(base_addr) (base_addr + 0x00) -#define IRQ_MASK(base_addr) (base_addr + 0x04) -#define IRQ_CLEAR(base_addr) (base_addr + 0x08) -#define IRQ_TMODE(base_addr) (base_addr + 0x0C) -#define IRQ_TLEVEL(base_addr) (base_addr + 0x10) -#define IRQ_STATUS(base_addr) (base_addr + 0x14) -#define FIQ_SOURCE(base_addr) (base_addr + 0x20) -#define FIQ_MASK(base_addr) (base_addr + 0x24) -#define FIQ_CLEAR(base_addr) (base_addr + 0x28) -#define FIQ_TMODE(base_addr) (base_addr + 0x2C) -#define FIQ_LEVEL(base_addr) (base_addr + 0x30) -#define FIQ_STATUS(base_addr) (base_addr + 0x34) - -static void gemini_ack_irq(struct irq_data *d) -{ - __raw_writel(1 << d->irq, IRQ_CLEAR(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); -} - -static void gemini_mask_irq(struct irq_data *d) -{ - unsigned int mask; - - mask = __raw_readl(IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); - mask &= ~(1 << d->irq); - __raw_writel(mask, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); -} - -static void gemini_unmask_irq(struct irq_data *d) -{ - unsigned int mask; - - mask = __raw_readl(IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); - mask |= (1 << d->irq); - __raw_writel(mask, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); -} - -static struct irq_chip gemini_irq_chip = { - .name = "INTC", - .irq_ack = gemini_ack_irq, - .irq_mask = gemini_mask_irq, - .irq_unmask = gemini_unmask_irq, -}; - -static struct resource irq_resource = { - .name = "irq_handler", - .start = GEMINI_INTERRUPT_BASE, - .end = FIQ_STATUS(GEMINI_INTERRUPT_BASE) + 4, -}; - -void __init gemini_init_irq(void) -{ - unsigned int i, mode = 0, level = 0; - - /* - * Disable the idle handler by default since it is buggy - * For more info see arch/arm/mach-gemini/idle.c - */ - cpu_idle_poll_ctrl(true); - - request_resource(&iomem_resource, &irq_resource); - - for (i = 0; i < NR_IRQS; i++) { - irq_set_chip(i, &gemini_irq_chip); - if((i >= IRQ_TIMER1 && i <= IRQ_TIMER3) || (i >= IRQ_SERIRQ0 && i <= IRQ_SERIRQ1)) { - irq_set_handler(i, handle_edge_irq); - mode |= 1 << i; - level |= 1 << i; - } else { - irq_set_handler(i, handle_level_irq); - } - irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); - } - - /* Disable all interrupts */ - __raw_writel(0, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); - __raw_writel(0, FIQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); - - /* Set interrupt mode */ - __raw_writel(mode, IRQ_TMODE(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); - __raw_writel(level, IRQ_TLEVEL(IO_ADDRESS(GEMINI_INTERRUPT_BASE))); -} diff --git a/arch/arm/mach-gemini/mm.c b/arch/arm/mach-gemini/mm.c deleted file mode 100644 index 2c2cd284bb6a..000000000000 --- a/arch/arm/mach-gemini/mm.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Static mappings for Gemini - * - * Copyright (C) 2001-2006 Storlink, Corp. - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include <linux/mm.h> -#include <linux/init.h> - -#include <asm/mach/map.h> - -#include <mach/hardware.h> - -/* Page table mapping for I/O region */ -static struct map_desc gemini_io_desc[] __initdata = { - { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_GLOBAL_BASE), - .pfn =__phys_to_pfn(GEMINI_GLOBAL_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_UART_BASE), - .pfn = __phys_to_pfn(GEMINI_UART_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_TIMER_BASE), - .pfn = __phys_to_pfn(GEMINI_TIMER_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_INTERRUPT_BASE), - .pfn = __phys_to_pfn(GEMINI_INTERRUPT_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_POWER_CTRL_BASE), - .pfn = __phys_to_pfn(GEMINI_POWER_CTRL_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_GPIO_BASE(0)), - .pfn = __phys_to_pfn(GEMINI_GPIO_BASE(0)), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_GPIO_BASE(1)), - .pfn = __phys_to_pfn(GEMINI_GPIO_BASE(1)), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_GPIO_BASE(2)), - .pfn = __phys_to_pfn(GEMINI_GPIO_BASE(2)), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_FLASH_CTRL_BASE), - .pfn = __phys_to_pfn(GEMINI_FLASH_CTRL_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_DRAM_CTRL_BASE), - .pfn = __phys_to_pfn(GEMINI_DRAM_CTRL_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_GENERAL_DMA_BASE), - .pfn = __phys_to_pfn(GEMINI_GENERAL_DMA_BASE), - .length = SZ_512K, - .type = MT_DEVICE, - }, -}; - -void __init gemini_map_io(void) -{ - iotable_init(gemini_io_desc, ARRAY_SIZE(gemini_io_desc)); -} diff --git a/arch/arm/mach-gemini/reset.c b/arch/arm/mach-gemini/reset.c deleted file mode 100644 index 21a6d6d4f9c4..000000000000 --- a/arch/arm/mach-gemini/reset.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2001-2006 Storlink, Corp. - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef __MACH_SYSTEM_H -#define __MACH_SYSTEM_H - -#include <linux/io.h> -#include <mach/hardware.h> -#include <mach/global_reg.h> - -#include "common.h" - -void gemini_restart(enum reboot_mode mode, const char *cmd) -{ - __raw_writel(RESET_GLOBAL | RESET_CPU1, - IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_RESET); -} - -#endif /* __MACH_SYSTEM_H */ diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c deleted file mode 100644 index f5f18df5aacd..000000000000 --- a/arch/arm/mach-gemini/time.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2001-2006 Storlink, Corp. - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <mach/hardware.h> -#include <mach/global_reg.h> -#include <asm/mach/time.h> -#include <linux/clockchips.h> -#include <linux/clocksource.h> -#include <linux/sched_clock.h> - -/* - * Register definitions for the timers - */ - -#define TIMER1_BASE GEMINI_TIMER_BASE -#define TIMER2_BASE (GEMINI_TIMER_BASE + 0x10) -#define TIMER3_BASE (GEMINI_TIMER_BASE + 0x20) - -#define TIMER_COUNT(BASE) (IO_ADDRESS(BASE) + 0x00) -#define TIMER_LOAD(BASE) (IO_ADDRESS(BASE) + 0x04) -#define TIMER_MATCH1(BASE) (IO_ADDRESS(BASE) + 0x08) -#define TIMER_MATCH2(BASE) (IO_ADDRESS(BASE) + 0x0C) -#define TIMER_CR (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x30) -#define TIMER_INTR_STATE (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x34) -#define TIMER_INTR_MASK (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x38) - -#define TIMER_1_CR_ENABLE (1 << 0) -#define TIMER_1_CR_CLOCK (1 << 1) -#define TIMER_1_CR_INT (1 << 2) -#define TIMER_2_CR_ENABLE (1 << 3) -#define TIMER_2_CR_CLOCK (1 << 4) -#define TIMER_2_CR_INT (1 << 5) -#define TIMER_3_CR_ENABLE (1 << 6) -#define TIMER_3_CR_CLOCK (1 << 7) -#define TIMER_3_CR_INT (1 << 8) -#define TIMER_1_CR_UPDOWN (1 << 9) -#define TIMER_2_CR_UPDOWN (1 << 10) -#define TIMER_3_CR_UPDOWN (1 << 11) -#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \ - TIMER_3_CR_ENABLE | \ - TIMER_3_CR_UPDOWN) - -#define TIMER_1_INT_MATCH1 (1 << 0) -#define TIMER_1_INT_MATCH2 (1 << 1) -#define TIMER_1_INT_OVERFLOW (1 << 2) -#define TIMER_2_INT_MATCH1 (1 << 3) -#define TIMER_2_INT_MATCH2 (1 << 4) -#define TIMER_2_INT_OVERFLOW (1 << 5) -#define TIMER_3_INT_MATCH1 (1 << 6) -#define TIMER_3_INT_MATCH2 (1 << 7) -#define TIMER_3_INT_OVERFLOW (1 << 8) -#define TIMER_INT_ALL_MASK 0x1ff - - -static unsigned int tick_rate; - -static u64 notrace gemini_read_sched_clock(void) -{ - return readl(TIMER_COUNT(TIMER3_BASE)); -} - -static int gemini_timer_set_next_event(unsigned long cycles, - struct clock_event_device *evt) -{ - u32 cr; - - /* Setup the match register */ - cr = readl(TIMER_COUNT(TIMER1_BASE)); - writel(cr + cycles, TIMER_MATCH1(TIMER1_BASE)); - if (readl(TIMER_COUNT(TIMER1_BASE)) - cr > cycles) - return -ETIME; - - return 0; -} - -static int gemini_timer_shutdown(struct clock_event_device *evt) -{ - u32 cr; - - /* - * Disable also for oneshot: the set_next() call will arm the timer - * instead. - */ - /* Stop timer and interrupt. */ - cr = readl(TIMER_CR); - cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); - writel(cr, TIMER_CR); - - /* Setup counter start from 0 */ - writel(0, TIMER_COUNT(TIMER1_BASE)); - writel(0, TIMER_LOAD(TIMER1_BASE)); - - /* enable interrupt */ - cr = readl(TIMER_INTR_MASK); - cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); - cr |= TIMER_1_INT_MATCH1; - writel(cr, TIMER_INTR_MASK); - - /* start the timer */ - cr = readl(TIMER_CR); - cr |= TIMER_1_CR_ENABLE; - writel(cr, TIMER_CR); - - return 0; -} - -static int gemini_timer_set_periodic(struct clock_event_device *evt) -{ - u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); - u32 cr; - - /* Stop timer and interrupt */ - cr = readl(TIMER_CR); - cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); - writel(cr, TIMER_CR); - - /* Setup timer to fire at 1/HT intervals. */ - cr = 0xffffffff - (period - 1); - writel(cr, TIMER_COUNT(TIMER1_BASE)); - writel(cr, TIMER_LOAD(TIMER1_BASE)); - - /* enable interrupt on overflow */ - cr = readl(TIMER_INTR_MASK); - cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); - cr |= TIMER_1_INT_OVERFLOW; - writel(cr, TIMER_INTR_MASK); - - /* Start the timer */ - cr = readl(TIMER_CR); - cr |= TIMER_1_CR_ENABLE; - cr |= TIMER_1_CR_INT; - writel(cr, TIMER_CR); - - return 0; -} - -/* Use TIMER1 as clock event */ -static struct clock_event_device gemini_clockevent = { - .name = "TIMER1", - /* Reasonably fast and accurate clock event */ - .rating = 300, - .shift = 32, - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = gemini_timer_set_next_event, - .set_state_shutdown = gemini_timer_shutdown, - .set_state_periodic = gemini_timer_set_periodic, - .set_state_oneshot = gemini_timer_shutdown, - .tick_resume = gemini_timer_shutdown, -}; - -/* - * IRQ handler for the timer - */ -static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = &gemini_clockevent; - - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static struct irqaction gemini_timer_irq = { - .name = "Gemini Timer Tick", - .flags = IRQF_TIMER, - .handler = gemini_timer_interrupt, -}; - -/* - * Set up timer interrupt, and return the current time in seconds. - */ -void __init gemini_timer_init(void) -{ - u32 reg_v; - - reg_v = readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS)); - tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000; - - printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000); - - tick_rate /= 6; /* APB bus run AHB*(1/6) */ - - switch(reg_v & CPU_AHB_RATIO_MASK) { - case CPU_AHB_1_1: - printk(KERN_CONT "(1/1)\n"); - break; - case CPU_AHB_3_2: - printk(KERN_CONT "(3/2)\n"); - break; - case CPU_AHB_24_13: - printk(KERN_CONT "(24/13)\n"); - break; - case CPU_AHB_2_1: - printk(KERN_CONT "(2/1)\n"); - break; - } - - /* - * Reset the interrupt mask and status - */ - writel(TIMER_INT_ALL_MASK, TIMER_INTR_MASK); - writel(0, TIMER_INTR_STATE); - writel(TIMER_DEFAULT_FLAGS, TIMER_CR); - - /* - * Setup free-running clocksource timer (interrupts - * disabled.) - */ - writel(0, TIMER_COUNT(TIMER3_BASE)); - writel(0, TIMER_LOAD(TIMER3_BASE)); - writel(0, TIMER_MATCH1(TIMER3_BASE)); - writel(0, TIMER_MATCH2(TIMER3_BASE)); - clocksource_mmio_init(TIMER_COUNT(TIMER3_BASE), - "gemini_clocksource", tick_rate, - 300, 32, clocksource_mmio_readl_up); - sched_clock_register(gemini_read_sched_clock, 32, tick_rate); - - /* - * Setup clockevent timer (interrupt-driven.) - */ - writel(0, TIMER_COUNT(TIMER1_BASE)); - writel(0, TIMER_LOAD(TIMER1_BASE)); - writel(0, TIMER_MATCH1(TIMER1_BASE)); - writel(0, TIMER_MATCH2(TIMER1_BASE)); - setup_irq(IRQ_TIMER1, &gemini_timer_irq); - gemini_clockevent.cpumask = cpumask_of(0); - clockevents_config_and_register(&gemini_clockevent, tick_rate, - 1, 0xffffffff); - -} diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c index a6c117622d67..f66815c3dd07 100644 --- a/arch/arm/mach-hisi/platmcpm.c +++ b/arch/arm/mach-hisi/platmcpm.c @@ -279,6 +279,8 @@ static int __init hip04_smp_init(void) &hip04_boot_method[0], 4); if (ret) goto err; + + ret = -ENODEV; np_sctl = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); if (!np_sctl) goto err; diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 1dc2a34b9dbd..93f584ba0130 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -10,26 +10,17 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include <linux/clk.h> -#include <linux/delay.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/irqchip.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/platform_device.h> -#include <linux/pm_domain.h> -#include <linux/regulator/consumer.h> #include <linux/irqchip/arm-gic.h> #include "common.h" #include "hardware.h" -#define GPC_CNTR 0x000 #define GPC_IMR1 0x008 -#define GPC_PGC_GPU_PDN 0x260 -#define GPC_PGC_GPU_PUPSCR 0x264 -#define GPC_PGC_GPU_PDNSCR 0x268 #define GPC_PGC_CPU_PDN 0x2a0 #define GPC_PGC_CPU_PUPSCR 0x2a4 #define GPC_PGC_CPU_PDNSCR 0x2a8 @@ -39,18 +30,6 @@ #define IMR_NUM 4 #define GPC_MAX_IRQS (IMR_NUM * 32) -#define GPU_VPU_PUP_REQ BIT(1) -#define GPU_VPU_PDN_REQ BIT(0) - -#define GPC_CLK_MAX 6 - -struct pu_domain { - struct generic_pm_domain base; - struct regulator *reg; - struct clk *clk[GPC_CLK_MAX]; - int num_clks; -}; - static void __iomem *gpc_base; static u32 gpc_wake_irqs[IMR_NUM]; static u32 gpc_saved_imrs[IMR_NUM]; @@ -296,199 +275,3 @@ void __init imx_gpc_check_dt(void) gpc_base = of_iomap(np, 0); } } - -static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) -{ - int iso, iso2sw; - u32 val; - - /* Read ISO and ISO2SW power down delays */ - val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR); - iso = val & 0x3f; - iso2sw = (val >> 8) & 0x3f; - - /* Gate off PU domain when GPU/VPU when powered down */ - writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); - - /* Request GPC to power down GPU/VPU */ - val = readl_relaxed(gpc_base + GPC_CNTR); - val |= GPU_VPU_PDN_REQ; - writel_relaxed(val, gpc_base + GPC_CNTR); - - /* Wait ISO + ISO2SW IPG clock cycles */ - ndelay((iso + iso2sw) * 1000 / 66); -} - -static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) -{ - struct pu_domain *pu = container_of(genpd, struct pu_domain, base); - - _imx6q_pm_pu_power_off(genpd); - - if (pu->reg) - regulator_disable(pu->reg); - - return 0; -} - -static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd) -{ - struct pu_domain *pu = container_of(genpd, struct pu_domain, base); - int i, ret, sw, sw2iso; - u32 val; - - if (pu->reg) - ret = regulator_enable(pu->reg); - if (pu->reg && ret) { - pr_err("%s: failed to enable regulator: %d\n", __func__, ret); - return ret; - } - - /* Enable reset clocks for all devices in the PU domain */ - for (i = 0; i < pu->num_clks; i++) - clk_prepare_enable(pu->clk[i]); - - /* Gate off PU domain when GPU/VPU when powered down */ - writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); - - /* Read ISO and ISO2SW power down delays */ - val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR); - sw = val & 0x3f; - sw2iso = (val >> 8) & 0x3f; - - /* Request GPC to power up GPU/VPU */ - val = readl_relaxed(gpc_base + GPC_CNTR); - val |= GPU_VPU_PUP_REQ; - writel_relaxed(val, gpc_base + GPC_CNTR); - - /* Wait ISO + ISO2SW IPG clock cycles */ - ndelay((sw + sw2iso) * 1000 / 66); - - /* Disable reset clocks for all devices in the PU domain */ - for (i = 0; i < pu->num_clks; i++) - clk_disable_unprepare(pu->clk[i]); - - return 0; -} - -static struct generic_pm_domain imx6q_arm_domain = { - .name = "ARM", -}; - -static struct pu_domain imx6q_pu_domain = { - .base = { - .name = "PU", - .power_off = imx6q_pm_pu_power_off, - .power_on = imx6q_pm_pu_power_on, - }, -}; - -static struct generic_pm_domain imx6sl_display_domain = { - .name = "DISPLAY", -}; - -static struct generic_pm_domain *imx_gpc_domains[] = { - &imx6q_arm_domain, - &imx6q_pu_domain.base, - &imx6sl_display_domain, -}; - -static struct genpd_onecell_data imx_gpc_onecell_data = { - .domains = imx_gpc_domains, - .num_domains = ARRAY_SIZE(imx_gpc_domains), -}; - -static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) -{ - struct clk *clk; - int i, ret; - - imx6q_pu_domain.reg = pu_reg; - - for (i = 0; ; i++) { - clk = of_clk_get(dev->of_node, i); - if (IS_ERR(clk)) - break; - if (i >= GPC_CLK_MAX) { - dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX); - goto clk_err; - } - imx6q_pu_domain.clk[i] = clk; - } - imx6q_pu_domain.num_clks = i; - - /* Enable power always in case bootloader disabled it. */ - imx6q_pm_pu_power_on(&imx6q_pu_domain.base); - - if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) - return 0; - - imx6q_pu_domain.base.states = devm_kzalloc(dev, - sizeof(*imx6q_pu_domain.base.states), - GFP_KERNEL); - if (!imx6q_pu_domain.base.states) - return -ENOMEM; - - imx6q_pu_domain.base.states[0].power_off_latency_ns = 25000; - imx6q_pu_domain.base.states[0].power_on_latency_ns = 2000000; - imx6q_pu_domain.base.state_count = 1; - - for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++) - pm_genpd_init(imx_gpc_domains[i], NULL, false); - - ret = of_genpd_add_provider_onecell(dev->of_node, - &imx_gpc_onecell_data); - if (ret) - goto power_off; - - return 0; - -power_off: - imx6q_pm_pu_power_off(&imx6q_pu_domain.base); -clk_err: - while (i--) - clk_put(imx6q_pu_domain.clk[i]); - imx6q_pu_domain.reg = NULL; - return -EINVAL; -} - -static int imx_gpc_probe(struct platform_device *pdev) -{ - struct regulator *pu_reg; - int ret; - - /* bail out if DT too old and doesn't provide the necessary info */ - if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells")) - return 0; - - pu_reg = devm_regulator_get_optional(&pdev->dev, "pu"); - if (PTR_ERR(pu_reg) == -ENODEV) - pu_reg = NULL; - if (IS_ERR(pu_reg)) { - ret = PTR_ERR(pu_reg); - dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret); - return ret; - } - - return imx_gpc_genpd_init(&pdev->dev, pu_reg); -} - -static const struct of_device_id imx_gpc_dt_ids[] = { - { .compatible = "fsl,imx6q-gpc" }, - { .compatible = "fsl,imx6sl-gpc" }, - { } -}; - -static struct platform_driver imx_gpc_driver = { - .driver = { - .name = "imx-gpc", - .of_match_table = imx_gpc_dt_ids, - }, - .probe = imx_gpc_probe, -}; - -static int __init imx_pgc_init(void) -{ - return platform_driver_register(&imx_gpc_driver); -} -subsys_initcall(imx_pgc_init); diff --git a/arch/arm/mach-imx/mach-imx25.c b/arch/arm/mach-imx/mach-imx25.c index 32dcb5e99e23..353b86e3808f 100644 --- a/arch/arm/mach-imx/mach-imx25.c +++ b/arch/arm/mach-imx/mach-imx25.c @@ -23,6 +23,11 @@ static void __init imx25_init_early(void) mxc_set_cpu_type(MXC_CPU_MX25); } +static void __init imx25_dt_init(void) +{ + imx_aips_allow_unprivileged_access("fsl,imx25-aips"); +} + static void __init mx25_init_irq(void) { struct device_node *np; @@ -41,6 +46,7 @@ static const char * const imx25_dt_board_compat[] __initconst = { DT_MACHINE_START(IMX25_DT, "Freescale i.MX25 (Device Tree Support)") .init_early = imx25_init_early, + .init_machine = imx25_dt_init, .init_late = imx25_pm_init, .init_irq = mx25_init_irq, .dt_compat = imx25_dt_board_compat, diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c index 558e5f8589cb..68c3f0799d5b 100644 --- a/arch/arm/mach-imx/mach-mx31_3ds.c +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -375,6 +375,8 @@ static struct imx_ssi_platform_data mx31_3ds_ssi_pdata = { /* SPI */ static int spi0_internal_chipselect[] = { + MXC_SPI_CS(0), + MXC_SPI_CS(1), MXC_SPI_CS(2), }; @@ -385,6 +387,7 @@ static const struct spi_imx_master spi0_pdata __initconst = { static int spi1_internal_chipselect[] = { MXC_SPI_CS(0), + MXC_SPI_CS(1), MXC_SPI_CS(2), }; @@ -398,7 +401,7 @@ static struct spi_board_info mx31_3ds_spi_devs[] __initdata = { .modalias = "mc13783", .max_speed_hz = 1000000, .bus_num = 1, - .chip_select = 1, /* SS2 */ + .chip_select = 2, /* SS2 */ .platform_data = &mc13783_pdata, /* irq number is run-time assigned */ .mode = SPI_CS_HIGH, @@ -406,7 +409,7 @@ static struct spi_board_info mx31_3ds_spi_devs[] __initdata = { .modalias = "l4f00242t03", .max_speed_hz = 5000000, .bus_num = 0, - .chip_select = 0, /* SS2 */ + .chip_select = 2, /* SS2 */ .platform_data = &mx31_3ds_l4f00242t03_pdata, }, }; diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index cc867682520e..bde9a9af6714 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -296,14 +296,14 @@ static struct spi_board_info moboard_spi_board_info[] __initdata = { /* irq number is run-time assigned */ .max_speed_hz = 300000, .bus_num = 1, - .chip_select = 0, + .chip_select = 1, .platform_data = &moboard_pmic, .mode = SPI_CS_HIGH, }, }; static int moboard_spi2_cs[] = { - MXC_SPI_CS(1), + MXC_SPI_CS(0), MXC_SPI_CS(1), }; static const struct spi_imx_master moboard_spi2_pdata __initconst = { diff --git a/arch/arm/mach-imx/mach-pcm037_eet.c b/arch/arm/mach-imx/mach-pcm037_eet.c index 8fd8255068ee..95bd97710494 100644 --- a/arch/arm/mach-imx/mach-pcm037_eet.c +++ b/arch/arm/mach-imx/mach-pcm037_eet.c @@ -50,13 +50,13 @@ static struct spi_board_info pcm037_spi_dev[] = { .modalias = "dac124s085", .max_speed_hz = 400000, .bus_num = 0, - .chip_select = 0, /* Index in pcm037_spi1_cs[] */ + .chip_select = 1, /* Index in pcm037_spi1_cs[] */ .mode = SPI_CPHA, }, }; /* Platform Data for MXC CSPI */ -static int pcm037_spi1_cs[] = {MXC_SPI_CS(1), IOMUX_TO_GPIO(MX31_PIN_KEY_COL7)}; +static int pcm037_spi1_cs[] = { MXC_SPI_CS(0), MXC_SPI_CS(1), }; static const struct spi_imx_master pcm037_spi1_pdata __initconst = { .chipselect = pcm037_spi1_cs, diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index c03bf28d8bbc..78262899a590 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -1,4 +1,5 @@ /* + * Copyright 2017 NXP * Copyright 2011,2016 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * @@ -47,6 +48,7 @@ #define PROFILE_SEL 0x10 #define MMDC_MADPCR0 0x410 +#define MMDC_MADPCR1 0x414 #define MMDC_MADPSR0 0x418 #define MMDC_MADPSR1 0x41C #define MMDC_MADPSR2 0x420 @@ -57,6 +59,7 @@ #define MMDC_NUM_COUNTERS 6 #define MMDC_FLAG_PROFILE_SEL 0x1 +#define MMDC_PRF_AXI_ID_CLEAR 0x0 #define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu) @@ -87,7 +90,7 @@ static DEFINE_IDA(mmdc_ida); PMU_EVENT_ATTR_STRING(total-cycles, mmdc_pmu_total_cycles, "event=0x00") PMU_EVENT_ATTR_STRING(busy-cycles, mmdc_pmu_busy_cycles, "event=0x01") PMU_EVENT_ATTR_STRING(read-accesses, mmdc_pmu_read_accesses, "event=0x02") -PMU_EVENT_ATTR_STRING(write-accesses, mmdc_pmu_write_accesses, "config=0x03") +PMU_EVENT_ATTR_STRING(write-accesses, mmdc_pmu_write_accesses, "event=0x03") PMU_EVENT_ATTR_STRING(read-bytes, mmdc_pmu_read_bytes, "event=0x04") PMU_EVENT_ATTR_STRING(read-bytes.unit, mmdc_pmu_read_bytes_unit, "MB"); PMU_EVENT_ATTR_STRING(read-bytes.scale, mmdc_pmu_read_bytes_scale, "0.000001"); @@ -161,8 +164,11 @@ static struct attribute_group mmdc_pmu_events_attr_group = { }; PMU_FORMAT_ATTR(event, "config:0-63"); +PMU_FORMAT_ATTR(axi_id, "config1:0-63"); + static struct attribute *mmdc_pmu_format_attrs[] = { &format_attr_event.attr, + &format_attr_axi_id.attr, NULL, }; @@ -345,6 +351,14 @@ static void mmdc_pmu_event_start(struct perf_event *event, int flags) writel(DBG_RST, reg); + /* + * Write the AXI id parameter to MADPCR1. + */ + val = event->attr.config1; + reg = mmdc_base + MMDC_MADPCR1; + writel(val, reg); + + reg = mmdc_base + MMDC_MADPCR0; val = DBG_EN; if (pmu_mmdc->devtype_data->flags & MMDC_FLAG_PROFILE_SEL) val |= PROFILE_SEL; @@ -382,6 +396,10 @@ static void mmdc_pmu_event_stop(struct perf_event *event, int flags) reg = mmdc_base + MMDC_MADPCR0; writel(PRF_FRZ, reg); + + reg = mmdc_base + MMDC_MADPCR1; + writel(MMDC_PRF_AXI_ID_CLEAR, reg); + mmdc_pmu_event_update(event); } diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig index 554357035f30..db122356b410 100644 --- a/arch/arm/mach-keystone/Kconfig +++ b/arch/arm/mach-keystone/Kconfig @@ -10,6 +10,7 @@ config ARCH_KEYSTONE select ARCH_SUPPORTS_BIG_ENDIAN select ZONE_DMA if ARM_LPAE select PINCTRL + select PM_GENERIC_DOMAINS if PM help Support for boards based on the Texas Instruments Keystone family of SoCs. diff --git a/arch/arm/mach-keystone/pm_domain.c b/arch/arm/mach-keystone/pm_domain.c index 8cbb35765a19..fe57e2692629 100644 --- a/arch/arm/mach-keystone/pm_domain.c +++ b/arch/arm/mach-keystone/pm_domain.c @@ -32,7 +32,9 @@ static struct pm_clk_notifier_block platform_domain_notifier = { }; static const struct of_device_id of_keystone_table[] = { - {.compatible = "ti,keystone"}, + {.compatible = "ti,k2hk"}, + {.compatible = "ti,k2e"}, + {.compatible = "ti,k2l"}, { /* end of list */ }, }; diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c index ac6633d0b69b..28fe64c6e2f5 100644 --- a/arch/arm/mach-mmp/clock.c +++ b/arch/arm/mach-mmp/clock.c @@ -67,6 +67,9 @@ void clk_disable(struct clk *clk) { unsigned long flags; + if (!clk) + return; + WARN_ON(clk->enabled == 0); spin_lock_irqsave(&clocks_lock, flags); diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index e4f21086b42b..1c6062d240c8 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -419,7 +419,8 @@ static void __init mxs_machine_init(void) crystalfontz_init(); else if (of_machine_is_compatible("eukrea,mbmx283lc")) eukrea_mbmx283lc_init(); - else if (of_machine_is_compatible("i2se,duckbill")) + else if (of_machine_is_compatible("i2se,duckbill") || + of_machine_is_compatible("i2se,duckbill-2")) duckbill_init(); else if (of_machine_is_compatible("msr,m28cu3")) m28cu3_init(); diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index ee5460b8ec2e..f1135bf8940e 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -581,7 +581,6 @@ static int omap_pm_enter(suspend_state_t state) { switch (state) { - case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: omap1_pm_suspend(); break; diff --git a/arch/arm/mach-omap2/clockdomains81xx_data.c b/arch/arm/mach-omap2/clockdomains81xx_data.c index 3b5fb05ae701..65fbd136b20c 100644 --- a/arch/arm/mach-omap2/clockdomains81xx_data.c +++ b/arch/arm/mach-omap2/clockdomains81xx_data.c @@ -91,6 +91,14 @@ static struct clockdomain default_l3_slow_81xx_clkdm = { .flags = CLKDM_CAN_SWSUP, }; +static struct clockdomain default_sata_81xx_clkdm = { + .name = "default_clkdm", + .pwrdm = { .name = "default_pwrdm" }, + .cm_inst = TI81XX_CM_DEFAULT_MOD, + .clkdm_offs = TI816X_CM_DEFAULT_SATA_CLKDM, + .flags = CLKDM_CAN_SWSUP, +}; + /* 816x only */ static struct clockdomain alwon_mpu_816x_clkdm = { @@ -173,6 +181,7 @@ static struct clockdomain *clockdomains_ti814x[] __initdata = { &mmu_81xx_clkdm, &mmu_cfg_81xx_clkdm, &default_l3_slow_81xx_clkdm, + &default_sata_81xx_clkdm, NULL, }; @@ -200,6 +209,7 @@ static struct clockdomain *clockdomains_ti816x[] __initdata = { &default_ducati_816x_clkdm, &default_pci_816x_clkdm, &default_l3_slow_81xx_clkdm, + &default_sata_81xx_clkdm, NULL, }; diff --git a/arch/arm/mach-omap2/cm81xx.h b/arch/arm/mach-omap2/cm81xx.h index 3a0ccf07c76f..5d73a1057c82 100644 --- a/arch/arm/mach-omap2/cm81xx.h +++ b/arch/arm/mach-omap2/cm81xx.h @@ -57,5 +57,6 @@ #define TI816X_CM_DEFAULT_PCI_CLKDM 0x0010 #define TI816X_CM_DEFAULT_L3_SLOW_CLKDM 0x0014 #define TI816X_CM_DEFAULT_DUCATI_CLKDM 0x0018 +#define TI816X_CM_DEFAULT_SATA_CLKDM 0x0060 #endif diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 3fdb94599184..473951203104 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -121,7 +121,7 @@ static inline void omap_init_mcspi(void) {} * * Bind the RNG hwmod to the RNG omap_device. No return value. */ -static void omap_init_rng(void) +static void __init omap_init_rng(void) { struct omap_hwmod *oh; struct platform_device *pdev; diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 0da4f2ea76c4..8bcea0d83fa0 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -138,7 +138,6 @@ #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/slab.h> -#include <linux/bootmem.h> #include <linux/cpu.h> #include <linux/of.h> #include <linux/of_address.h> @@ -216,49 +215,12 @@ static LIST_HEAD(omap_hwmod_list); /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ static struct omap_hwmod *mpu_oh; -/* - * linkspace: ptr to a buffer that struct omap_hwmod_link records are - * allocated from - used to reduce the number of small memory - * allocations, which has a significant impact on performance - */ -static struct omap_hwmod_link *linkspace; - -/* - * free_ls, max_ls: array indexes into linkspace; representing the - * next free struct omap_hwmod_link index, and the maximum number of - * struct omap_hwmod_link records allocated (respectively) - */ -static unsigned short free_ls, max_ls, ls_supp; - /* inited: set to true once the hwmod code is initialized */ static bool inited; /* Private functions */ /** - * _fetch_next_ocp_if - return the next OCP interface in a list - * @p: ptr to a ptr to the list_head inside the ocp_if to return - * @i: pointer to the index of the element pointed to by @p in the list - * - * Return a pointer to the struct omap_hwmod_ocp_if record - * containing the struct list_head pointed to by @p, and increment - * @p such that a future call to this routine will return the next - * record. - */ -static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p, - int *i) -{ - struct omap_hwmod_ocp_if *oi; - - oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if; - *p = (*p)->next; - - *i = *i + 1; - - return oi; -} - -/** * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy * @oh: struct omap_hwmod * * @@ -794,15 +756,10 @@ static int _init_main_clk(struct omap_hwmod *oh) static int _init_interface_clks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p; struct clk *c; - int i = 0; int ret = 0; - p = oh->slave_ports.next; - - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); + list_for_each_entry(os, &oh->slave_ports, node) { if (!os->clk) continue; @@ -905,19 +862,13 @@ static void _disable_optional_clocks(struct omap_hwmod *oh) static int _enable_clocks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p; - int i = 0; pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); if (oh->_clk) clk_enable(oh->_clk); - p = oh->slave_ports.next; - - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); - + list_for_each_entry(os, &oh->slave_ports, node) { if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) clk_enable(os->_clk); } @@ -939,19 +890,13 @@ static int _enable_clocks(struct omap_hwmod *oh) static int _disable_clocks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p; - int i = 0; pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); if (oh->_clk) clk_disable(oh->_clk); - p = oh->slave_ports.next; - - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); - + list_for_each_entry(os, &oh->slave_ports, node) { if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) clk_disable(os->_clk); } @@ -1190,16 +1135,11 @@ static int _get_sdma_req_by_name(struct omap_hwmod *oh, const char *name, static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, u32 *pa_start, u32 *pa_end) { - int i, j; + int j; struct omap_hwmod_ocp_if *os; - struct list_head *p = NULL; bool found = false; - p = oh->slave_ports.next; - - i = 0; - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); + list_for_each_entry(os, &oh->slave_ports, node) { if (!os->addr) return -ENOENT; @@ -1239,18 +1179,13 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, static void __init _save_mpu_port_index(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os = NULL; - struct list_head *p; - int i = 0; if (!oh) return; oh->_int_flags |= _HWMOD_NO_MPU_PORT; - p = oh->slave_ports.next; - - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); + list_for_each_entry(os, &oh->slave_ports, node) { if (os->user & OCP_USER_MPU) { oh->_mpu_port = os; oh->_int_flags &= ~_HWMOD_NO_MPU_PORT; @@ -1393,7 +1328,7 @@ static void _enable_sysc(struct omap_hwmod *oh) */ if ((oh->flags & HWMOD_SET_DEFAULT_CLOCKACT) && (sf & SYSC_HAS_CLOCKACTIVITY)) - _set_clockactivity(oh, oh->class->sysc->clockact, &v); + _set_clockactivity(oh, CLOCKACT_TEST_ICLK, &v); _write_sysconfig(v, oh); @@ -2092,7 +2027,7 @@ static int _enable(struct omap_hwmod *oh) r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) : -EINVAL; - if (oh->clkdm) + if (oh->clkdm && !(oh->flags & HWMOD_CLKDM_NOAUTO)) clkdm_allow_idle(oh->clkdm); if (!r) { @@ -2149,7 +2084,12 @@ static int _idle(struct omap_hwmod *oh) _idle_sysc(oh); _del_initiator_dep(oh, mpu_oh); - if (oh->clkdm) + /* + * If HWMOD_CLKDM_NOAUTO is set then we don't + * deny idle the clkdm again since idle was already denied + * in _enable() + */ + if (oh->clkdm && !(oh->flags & HWMOD_CLKDM_NOAUTO)) clkdm_deny_idle(oh->clkdm); if (oh->flags & HWMOD_BLOCK_WFI) @@ -2451,15 +2391,11 @@ static int __init _init(struct omap_hwmod *oh, void *data) static void __init _setup_iclk_autoidle(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p; - int i = 0; + if (oh->_state != _HWMOD_STATE_INITIALIZED) return; - p = oh->slave_ports.next; - - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); + list_for_each_entry(os, &oh->slave_ports, node) { if (!os->_clk) continue; @@ -2657,7 +2593,6 @@ static int __init _register(struct omap_hwmod *oh) list_add_tail(&oh->node, &omap_hwmod_list); - INIT_LIST_HEAD(&oh->master_ports); INIT_LIST_HEAD(&oh->slave_ports); spin_lock_init(&oh->_lock); lockdep_set_class(&oh->_lock, &oh->hwmod_key); @@ -2675,49 +2610,10 @@ static int __init _register(struct omap_hwmod *oh) } /** - * _alloc_links - return allocated memory for hwmod links - * @ml: pointer to a struct omap_hwmod_link * for the master link - * @sl: pointer to a struct omap_hwmod_link * for the slave link - * - * Return pointers to two struct omap_hwmod_link records, via the - * addresses pointed to by @ml and @sl. Will first attempt to return - * memory allocated as part of a large initial block, but if that has - * been exhausted, will allocate memory itself. Since ideally this - * second allocation path will never occur, the number of these - * 'supplemental' allocations will be logged when debugging is - * enabled. Returns 0. - */ -static int __init _alloc_links(struct omap_hwmod_link **ml, - struct omap_hwmod_link **sl) -{ - unsigned int sz; - - if ((free_ls + LINKS_PER_OCP_IF) <= max_ls) { - *ml = &linkspace[free_ls++]; - *sl = &linkspace[free_ls++]; - return 0; - } - - sz = sizeof(struct omap_hwmod_link) * LINKS_PER_OCP_IF; - - *sl = NULL; - *ml = memblock_virt_alloc(sz, 0); - - *sl = (void *)(*ml) + sizeof(struct omap_hwmod_link); - - ls_supp++; - pr_debug("omap_hwmod: supplemental link allocations needed: %d\n", - ls_supp * LINKS_PER_OCP_IF); - - return 0; -}; - -/** * _add_link - add an interconnect between two IP blocks * @oi: pointer to a struct omap_hwmod_ocp_if record * - * Add struct omap_hwmod_link records connecting the master IP block - * specified in @oi->master to @oi, and connecting the slave IP block + * Add struct omap_hwmod_link records connecting the slave IP block * specified in @oi->slave to @oi. This code is assumed to run before * preemption or SMP has been enabled, thus avoiding the need for * locking in this code. Changes to this assumption will require @@ -2725,19 +2621,10 @@ static int __init _alloc_links(struct omap_hwmod_link **ml, */ static int __init _add_link(struct omap_hwmod_ocp_if *oi) { - struct omap_hwmod_link *ml, *sl; - pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name, oi->slave->name); - _alloc_links(&ml, &sl); - - ml->ocp_if = oi; - list_add(&ml->node, &oi->master->master_ports); - oi->master->masters_cnt++; - - sl->ocp_if = oi; - list_add(&sl->node, &oi->slave->slave_ports); + list_add(&oi->node, &oi->slave->slave_ports); oi->slave->slaves_cnt++; return 0; @@ -2784,45 +2671,6 @@ static int __init _register_link(struct omap_hwmod_ocp_if *oi) return 0; } -/** - * _alloc_linkspace - allocate large block of hwmod links - * @ois: pointer to an array of struct omap_hwmod_ocp_if records to count - * - * Allocate a large block of struct omap_hwmod_link records. This - * improves boot time significantly by avoiding the need to allocate - * individual records one by one. If the number of records to - * allocate in the block hasn't been manually specified, this function - * will count the number of struct omap_hwmod_ocp_if records in @ois - * and use that to determine the allocation size. For SoC families - * that require multiple list registrations, such as OMAP3xxx, this - * estimation process isn't optimal, so manual estimation is advised - * in those cases. Returns -EEXIST if the allocation has already occurred - * or 0 upon success. - */ -static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) -{ - unsigned int i = 0; - unsigned int sz; - - if (linkspace) { - WARN(1, "linkspace already allocated\n"); - return -EEXIST; - } - - if (max_ls == 0) - while (ois[i++]) - max_ls += LINKS_PER_OCP_IF; - - sz = sizeof(struct omap_hwmod_link) * max_ls; - - pr_debug("omap_hwmod: %s: allocating %d byte linkspace (%d links)\n", - __func__, sz, max_ls); - - linkspace = memblock_virt_alloc(sz, 0); - - return 0; -} - /* Static functions intended only for use in soc_ops field function pointers */ /** @@ -3180,13 +3028,6 @@ int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois) if (ois[0] == NULL) /* Empty list */ return 0; - if (!linkspace) { - if (_alloc_linkspace(ois)) { - pr_err("omap_hwmod: could not allocate link space\n"); - return -ENOMEM; - } - } - i = 0; do { r = _register_link(ois[i]); @@ -3398,14 +3239,10 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh, unsigned long flags) ret += _count_sdma_reqs(oh); if (flags & IORESOURCE_MEM) { - int i = 0; struct omap_hwmod_ocp_if *os; - struct list_head *p = oh->slave_ports.next; - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); + list_for_each_entry(os, &oh->slave_ports, node) ret += _count_ocp_if_addr_spaces(os); - } } return ret; @@ -3424,7 +3261,6 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh, unsigned long flags) int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) { struct omap_hwmod_ocp_if *os; - struct list_head *p; int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt; int r = 0; @@ -3454,11 +3290,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) r++; } - p = oh->slave_ports.next; - - i = 0; - while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, &i); + list_for_each_entry(os, &oh->slave_ports, node) { addr_cnt = _count_ocp_if_addr_spaces(os); for (j = 0; j < addr_cnt; j++) { diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 78904017f18c..a8f779381fd8 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -313,6 +313,7 @@ struct omap_hwmod_ocp_if { struct omap_hwmod_addr_space *addr; const char *clk; struct clk *_clk; + struct list_head node; union { struct omap_hwmod_omap2_firewall omap2; } fw; @@ -410,7 +411,6 @@ struct omap_hwmod_class_sysconfig { struct omap_hwmod_sysc_fields *sysc_fields; u8 srst_udelay; u8 idlemodes; - u8 clockact; }; /** @@ -531,6 +531,10 @@ struct omap_hwmod_omap4_prcm { * operate and they need to be handled at the same time as the main_clk. * HWMOD_NO_IDLE: Do not idle the hwmod at all. Useful to handle certain * IPs like CPSW on DRA7, where clocks to this module cannot be disabled. + * HWMOD_CLKDM_NOAUTO: Allows the hwmod's clockdomain to be prevented from + * entering HW_AUTO while hwmod is active. This is needed to workaround + * some modules which don't function correctly with HW_AUTO. For example, + * DCAN on DRA7x SoC needs this to workaround errata i893. */ #define HWMOD_SWSUP_SIDLE (1 << 0) #define HWMOD_SWSUP_MSTANDBY (1 << 1) @@ -548,6 +552,7 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_RECONFIG_IO_CHAIN (1 << 13) #define HWMOD_OPT_CLKS_NEEDED (1 << 14) #define HWMOD_NO_IDLE (1 << 15) +#define HWMOD_CLKDM_NOAUTO (1 << 16) /* * omap_hwmod._int_flags definitions @@ -617,16 +622,6 @@ struct omap_hwmod_class { }; /** - * struct omap_hwmod_link - internal structure linking hwmods with ocp_ifs - * @ocp_if: OCP interface structure record pointer - * @node: list_head pointing to next struct omap_hwmod_link in a list - */ -struct omap_hwmod_link { - struct omap_hwmod_ocp_if *ocp_if; - struct list_head node; -}; - -/** * struct omap_hwmod - integration data for OMAP hardware "modules" (IP blocks) * @name: name of the hwmod * @class: struct omap_hwmod_class * to the class of this hwmod @@ -686,9 +681,8 @@ struct omap_hwmod { const char *main_clk; struct clk *_clk; struct omap_hwmod_opt_clk *opt_clks; - char *clkdm_name; + const char *clkdm_name; struct clockdomain *clkdm; - struct list_head master_ports; /* connect to *_IA */ struct list_head slave_ports; /* connect to *_TA */ void *dev_attr; u32 _sysc_cache; @@ -698,12 +692,11 @@ struct omap_hwmod { struct list_head node; struct omap_hwmod_ocp_if *_mpu_port; unsigned int (*xlate_irq)(unsigned int); - u16 flags; + u32 flags; u8 mpu_rt_idx; u8 response_lat; u8 rst_lines_cnt; u8 opt_clks_cnt; - u8 masters_cnt; u8 slaves_cnt; u8 hwmods_cnt; u8 _int_flags; diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c index e047033caa3e..d190f1ad97b7 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c @@ -55,7 +55,6 @@ static struct omap_hwmod_class_sysconfig omap2xxx_timer_sysc = { SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap_hwmod_sysc_type1, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 1435fee39a89..1c6ca4d5fa2d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -149,7 +149,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = { SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap_hwmod_sysc_type1, }; @@ -424,7 +423,6 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = { SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap_hwmod_sysc_type1, }; @@ -1045,7 +1043,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sysc = { SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), .sysc_fields = &omap_hwmod_sysc_type1, - .clockact = 0x2, }; static struct omap_hwmod_class omap3xxx_mcbsp_hwmod_class = { @@ -1210,7 +1207,6 @@ static struct omap_hwmod_sysc_fields omap34xx_sr_sysc_fields = { static struct omap_hwmod_class_sysconfig omap34xx_sr_sysc = { .sysc_offs = 0x24, .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_NO_CACHE), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap34xx_sr_sysc_fields, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index dad871a4cd96..94f09c720f29 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1320,7 +1320,6 @@ static struct omap_hwmod_class_sysconfig omap44xx_i2c_sysc = { SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | SIDLE_SMART_WKUP), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap_hwmod_sysc_type1, }; @@ -2548,7 +2547,6 @@ static struct omap_hwmod_class_sysconfig omap44xx_timer_1ms_sysc = { SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap_hwmod_sysc_type1, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index a2d763a4cc57..9a67f013ebad 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -839,7 +839,6 @@ static struct omap_hwmod_class_sysconfig omap54xx_i2c_sysc = { SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | SIDLE_SMART_WKUP), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap_hwmod_sysc_type1, }; @@ -1530,7 +1529,6 @@ static struct omap_hwmod_class_sysconfig omap54xx_timer_1ms_sysc = { .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | SIDLE_SMART_WKUP), .sysc_fields = &omap_hwmod_sysc_type2, - .clockact = CLOCKACT_TEST_ICLK, }; static struct omap_hwmod_class omap54xx_timer_1ms_hwmod_class = { diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index d0585293a381..b3abb8d8b2f6 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -359,6 +359,7 @@ static struct omap_hwmod dra7xx_dcan1_hwmod = { .class = &dra7xx_dcan_hwmod_class, .clkdm_name = "wkupaon_clkdm", .main_clk = "dcan1_sys_clk_mux", + .flags = HWMOD_CLKDM_NOAUTO, .prcm = { .omap4 = { .clkctrl_offs = DRA7XX_CM_WKUPAON_DCAN1_CLKCTRL_OFFSET, @@ -374,6 +375,7 @@ static struct omap_hwmod dra7xx_dcan2_hwmod = { .class = &dra7xx_dcan_hwmod_class, .clkdm_name = "l4per2_clkdm", .main_clk = "sys_clkin1", + .flags = HWMOD_CLKDM_NOAUTO, .prcm = { .omap4 = { .clkctrl_offs = DRA7XX_CM_L4PER2_DCAN2_CLKCTRL_OFFSET, @@ -1098,7 +1100,6 @@ static struct omap_hwmod_class_sysconfig dra7xx_i2c_sysc = { SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | SIDLE_SMART_WKUP), - .clockact = CLOCKACT_TEST_ICLK, .sysc_fields = &omap_hwmod_sysc_type1, }; @@ -2700,6 +2701,7 @@ static struct omap_hwmod dra7xx_usb_otg_ss1_hwmod = { .class = &dra7xx_usb_otg_ss_hwmod_class, .clkdm_name = "l3init_clkdm", .main_clk = "dpll_core_h13x2_ck", + .flags = HWMOD_CLKDM_NOAUTO, .prcm = { .omap4 = { .clkctrl_offs = DRA7XX_CM_L3INIT_USB_OTG_SS1_CLKCTRL_OFFSET, @@ -2721,6 +2723,7 @@ static struct omap_hwmod dra7xx_usb_otg_ss2_hwmod = { .class = &dra7xx_usb_otg_ss_hwmod_class, .clkdm_name = "l3init_clkdm", .main_clk = "dpll_core_h13x2_ck", + .flags = HWMOD_CLKDM_NOAUTO, .prcm = { .omap4 = { .clkctrl_offs = DRA7XX_CM_L3INIT_USB_OTG_SS2_CLKCTRL_OFFSET, diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c index b82b77cff24c..310afe474ec4 100644 --- a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c @@ -106,6 +106,7 @@ */ #define DM81XX_CM_DEFAULT_OFFSET 0x500 #define DM81XX_CM_DEFAULT_USB_CLKCTRL (0x558 - DM81XX_CM_DEFAULT_OFFSET) +#define DM81XX_CM_DEFAULT_SATA_CLKCTRL (0x560 - DM81XX_CM_DEFAULT_OFFSET) /* L3 Interconnect entries clocked at 125, 250 and 500MHz */ static struct omap_hwmod dm81xx_alwon_l3_slow_hwmod = { @@ -973,6 +974,38 @@ static struct omap_hwmod_ocp_if dm816x_l4_hs__emac1 = { .user = OCP_USER_MPU, }; +static struct omap_hwmod_class_sysconfig dm81xx_sata_sysc = { + .sysc_offs = 0x1100, + .sysc_flags = SYSC_HAS_SIDLEMODE, + .idlemodes = SIDLE_FORCE, + .sysc_fields = &omap_hwmod_sysc_type3, +}; + +static struct omap_hwmod_class dm81xx_sata_hwmod_class = { + .name = "sata", + .sysc = &dm81xx_sata_sysc, +}; + +static struct omap_hwmod dm81xx_sata_hwmod = { + .name = "sata", + .clkdm_name = "default_sata_clkdm", + .flags = HWMOD_NO_IDLEST, + .prcm = { + .omap4 = { + .clkctrl_offs = DM81XX_CM_DEFAULT_SATA_CLKCTRL, + .modulemode = MODULEMODE_SWCTRL, + }, + }, + .class = &dm81xx_sata_hwmod_class, +}; + +static struct omap_hwmod_ocp_if dm81xx_l4_hs__sata = { + .master = &dm81xx_l4_hs_hwmod, + .slave = &dm81xx_sata_hwmod, + .clk = "sysclk5_ck", + .user = OCP_USER_MPU, +}; + static struct omap_hwmod_class_sysconfig dm81xx_mmc_sysc = { .rev_offs = 0x0, .sysc_offs = 0x110, @@ -1474,6 +1507,7 @@ static struct omap_hwmod_ocp_if *dm816x_hwmod_ocp_ifs[] __initdata = { &dm81xx_l4_hs__emac0, &dm81xx_emac0__mdio, &dm816x_l4_hs__emac1, + &dm81xx_l4_hs__sata, &dm81xx_alwon_l3_fast__tpcc, &dm81xx_alwon_l3_fast__tptc0, &dm81xx_alwon_l3_fast__tptc1, diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 0598630c1778..63027e60cc20 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -163,7 +163,6 @@ static int omap_pm_enter(suspend_state_t suspend_state) return -ENOENT; /* XXX doublecheck */ switch (suspend_state) { - case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: ret = omap_pm_suspend(); break; diff --git a/arch/arm/mach-oxnas/Kconfig b/arch/arm/mach-oxnas/Kconfig index 8fa4557e27a9..e3610c5b309b 100644 --- a/arch/arm/mach-oxnas/Kconfig +++ b/arch/arm/mach-oxnas/Kconfig @@ -28,7 +28,6 @@ config MACH_OX820 depends on ARCH_MULTI_V6 select ARM_GIC select DMA_CACHE_RWFO if SMP - select CPU_V6K select HAVE_SMP select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig new file mode 100644 index 000000000000..2d1419eb0896 --- /dev/null +++ b/arch/arm/mach-stm32/Kconfig @@ -0,0 +1,26 @@ +config ARCH_STM32 + bool "STMicrolectronics STM32" + depends on ARM_SINGLE_ARMV7M + select ARCH_HAS_RESET_CONTROLLER + select ARMV7M_SYSTICK + select CLKSRC_STM32 + select PINCTRL + select RESET_CONTROLLER + select STM32_EXTI + help + Support for STMicroelectronics STM32 processors. + +config MACH_STM32F429 + bool "STMicrolectronics STM32F429" + depends on ARCH_STM32 + default y + +config MACH_STM32F746 + bool "STMicrolectronics STM32F746" + depends on ARCH_STM32 + default y + +config MACH_STM32H743 + bool "STMicrolectronics STM32H743" + depends on ARCH_STM32 + default y diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c index c354222a4158..e918686e4191 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -12,6 +12,7 @@ static const char *const stm32_compat[] __initconst = { "st,stm32f429", "st,stm32f469", "st,stm32f746", + "st,stm32h743", NULL }; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index b9863f9a35fa..58153cdf025b 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -6,6 +6,7 @@ menuconfig ARCH_SUNXI select GENERIC_IRQ_CHIP select GPIOLIB select PINCTRL + select PM_OPP select SUN4I_TIMER select RESET_CONTROLLER diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index fffad2426ee4..3b33f0bb78ae 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -2,7 +2,6 @@ asflags-y += -march=armv7-a obj-y += io.o obj-y += irq.o -obj-y += flowctrl.o obj-y += pm.o obj-y += reset.o obj-y += reset-handler.o diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index afcee04f2616..76e4c83cd5c8 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -26,12 +26,13 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <soc/tegra/flowctrl.h> + #include <asm/cpuidle.h> #include <asm/smp_plat.h> #include <asm/suspend.h> #include "cpuidle.h" -#include "flowctrl.h" #include "iomap.h" #include "irq.h" #include "pm.h" diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 75620ae73913..b5a2afe99101 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -21,6 +21,7 @@ #include <linux/jiffies.h> #include <linux/smp.h> +#include <soc/tegra/flowctrl.h> #include <soc/tegra/fuse.h> #include <soc/tegra/pmc.h> @@ -30,7 +31,6 @@ #include <asm/smp_scu.h> #include "common.h" -#include "flowctrl.h" #include "iomap.h" #include "reset.h" diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index b0f48a3946fa..1ad5719779b0 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -27,6 +27,7 @@ #include <linux/spinlock.h> #include <linux/suspend.h> +#include <soc/tegra/flowctrl.h> #include <soc/tegra/fuse.h> #include <soc/tegra/pm.h> #include <soc/tegra/pmc.h> @@ -38,7 +39,6 @@ #include <asm/suspend.h> #include <asm/tlbflush.h> -#include "flowctrl.h" #include "iomap.h" #include "pm.h" #include "reset.h" diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index e3070fdab80b..805f306fa6f7 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -17,12 +17,12 @@ #include <linux/init.h> #include <linux/linkage.h> +#include <soc/tegra/flowctrl.h> #include <soc/tegra/fuse.h> #include <asm/asm-offsets.h> #include <asm/cache.h> -#include "flowctrl.h" #include "iomap.h" #include "reset.h" #include "sleep.h" diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S index f5d19667484e..5c8e638ee51a 100644 --- a/arch/arm/mach-tegra/sleep-tegra20.S +++ b/arch/arm/mach-tegra/sleep-tegra20.S @@ -20,6 +20,8 @@ #include <linux/linkage.h> +#include <soc/tegra/flowctrl.h> + #include <asm/assembler.h> #include <asm/proc-fns.h> #include <asm/cp15.h> @@ -27,7 +29,6 @@ #include "irammap.h" #include "sleep.h" -#include "flowctrl.h" #define EMC_CFG 0xc #define EMC_ADR_CFG 0x10 diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S index 16e5ff03383c..dd4a67dabd91 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S @@ -16,13 +16,13 @@ #include <linux/linkage.h> +#include <soc/tegra/flowctrl.h> #include <soc/tegra/fuse.h> #include <asm/asm-offsets.h> #include <asm/assembler.h> #include <asm/cache.h> -#include "flowctrl.h" #include "irammap.h" #include "sleep.h" diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S index f024a5109e8e..5e3496753df1 100644 --- a/arch/arm/mach-tegra/sleep.S +++ b/arch/arm/mach-tegra/sleep.S @@ -30,8 +30,6 @@ #include <asm/hardware/cache-l2x0.h> #include "iomap.h" - -#include "flowctrl.h" #include "sleep.h" #define CLK_RESET_CCLK_BURST 0x20 diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index e01cbca196b5..649e9e8c7bcc 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -48,7 +48,6 @@ #include "board.h" #include "common.h" #include "cpuidle.h" -#include "flowctrl.h" #include "iomap.h" #include "irq.h" #include "pm.h" @@ -75,7 +74,6 @@ static void __init tegra_init_early(void) { of_register_trusted_foundations(); tegra_cpu_reset_handler_init(); - tegra_flowctrl_init(); } static void __init tegra_dt_init_irq(void) diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c index 2c371ff22e51..ac6fd1a2cb59 100644 --- a/arch/arm/mach-w90x900/clock.c +++ b/arch/arm/mach-w90x900/clock.c @@ -46,6 +46,9 @@ void clk_disable(struct clk *clk) { unsigned long flags; + if (!clk) + return; + WARN_ON(clk->enabled == 0); spin_lock_irqsave(&clocks_lock, flags); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 0268584f1fa0..c742dfd2967b 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2408,6 +2408,15 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, const struct dma_map_ops *dma_ops; dev->archdata.dma_coherent = coherent; + + /* + * Don't override the dma_ops if they have already been set. Ideally + * this should be the only location where dma_ops are set, remove this + * check when all other callers of set_dma_ops will have disappeared. + */ + if (dev->dma_ops) + return; + if (arm_setup_iommu_dma_ops(dev, dma_base, size, iommu)) dma_ops = arm_get_iommu_dma_map_ops(coherent); else diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 03fac123676d..dc269d9143bc 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -10,7 +10,6 @@ * published by the Free Software Foundation. */ -#include <linux/amba/pl330.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/interrupt.h> diff --git a/arch/arm/plat-versatile/include/plat/clock.h b/arch/arm/plat-versatile/include/plat/clock.h deleted file mode 100644 index 3cfb024ccd70..000000000000 --- a/arch/arm/plat-versatile/include/plat/clock.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef PLAT_CLOCK_H -#define PLAT_CLOCK_H - -#include <asm/hardware/icst.h> - -struct clk_ops { - long (*round)(struct clk *, unsigned long); - int (*set)(struct clk *, unsigned long); - void (*setvco)(struct clk *, struct icst_vco); -}; - -int icst_clk_set(struct clk *, unsigned long); -long icst_clk_round(struct clk *, unsigned long); - -#endif diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 129cc5ae4091..4afcffcb46cb 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -2,9 +2,10 @@ menu "Platform selection" config ARCH_SUNXI bool "Allwinner sunxi 64-bit SoC Family" + select ARCH_HAS_RESET_CONTROLLER select GENERIC_IRQ_CHIP select PINCTRL - select PINCTRL_SUN50I_A64 + select RESET_CONTROLLER help This enables support for Allwinner sunxi based SoCs like the A64. @@ -54,6 +55,8 @@ config ARCH_BRCMSTB config ARCH_EXYNOS bool "ARMv8 based Samsung Exynos SoC family" select COMMON_CLK_SAMSUNG + select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS + select EXYNOS_PMU select HAVE_S3C2410_WATCHDOG if WATCHDOG select HAVE_S3C_RTC if RTC_CLASS select PINCTRL diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile index bc6f342be59f..244e8b7565f9 100644 --- a/arch/arm64/boot/dts/allwinner/Makefile +++ b/arch/arm64/boot/dts/allwinner/Makefile @@ -1,5 +1,6 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-bananapi-m64.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-plus.dtb sun50i-a64-pine64.dtb +dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-pc2.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 0565779e66fa..c7f669f5884f 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -98,6 +98,14 @@ clock-output-names = "osc32k"; }; + iosc: internal-osc-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16000000>; + clock-accuracy = <300000000>; + clock-output-names = "iosc"; + }; + psci { compatible = "arm,psci-0.2"; method = "smc"; @@ -394,5 +402,26 @@ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; }; + + r_ccu: clock@1f01400 { + compatible = "allwinner,sun50i-a64-r-ccu"; + reg = <0x01f01400 0x100>; + clocks = <&osc24M>, <&osc32k>, <&iosc>; + clock-names = "hosc", "losc", "iosc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + r_pio: pinctrl@01f02c00 { + compatible = "allwinner,sun50i-a64-r-pinctrl"; + reg = <0x01f02c00 0x400>; + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu 3>, <&osc24M>, <&osc32k>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + }; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts new file mode 100644 index 000000000000..dfecc17dcc92 --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2016 ARM Ltd. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "sun50i-h5.dtsi" + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> + +/ { + model = "Xunlong Orange Pi PC 2"; + compatible = "xunlong,orangepi-pc2", "allwinner,sun50i-h5"; + + reg_vcc3v3: vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + pwr { + label = "orangepi:green:pwr"; + gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + status { + label = "orangepi:red:status"; + gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>; + }; + }; + + r-gpio-keys { + compatible = "gpio-keys"; + + sw4 { + label = "sw4"; + linux,code = <BTN_0>; + gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; + }; + }; + + reg_usb0_vbus: usb0-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb0-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */ + status = "okay"; + }; +}; + +&codec { + allwinner,audio-routing = + "Line Out", "LINEOUT", + "MIC1", "Mic", + "Mic", "MBIAS"; + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&ehci2 { + status = "okay"; +}; + +&ehci3 { + status = "okay"; +}; + +&ir { + pinctrl-names = "default"; + pinctrl-0 = <&ir_pins_a>; + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>; + vmmc-supply = <®_vcc3v3>; + bus-width = <4>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&ohci2 { + status = "okay"; +}; + +&ohci3 { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_a>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "disabled"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "disabled"; +}; + +&usb_otg { + dr_mode = "otg"; + status = "okay"; +}; + +&usbphy { + /* USB Type-A ports' VBUS is always on */ + usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */ + usb0_vbus-supply = <®_usb0_vbus>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi new file mode 100644 index 000000000000..4d314a253fd9 --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 ARM Ltd. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi-h3-h5.dtsi" + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <0>; + enable-method = "psci"; + }; + + cpu@1 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <1>; + enable-method = "psci"; + }; + + cpu@2 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <2>; + enable-method = "psci"; + }; + + cpu@3 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <3>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + }; +}; + +&ccu { + compatible = "allwinner,sun50i-h5-ccu"; +}; + +&mmc0 { + compatible = "allwinner,sun50i-h5-mmc", + "allwinner,sun50i-a64-mmc"; + clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>; + clock-names = "ahb", "mmc"; +}; + +&mmc1 { + compatible = "allwinner,sun50i-h5-mmc", + "allwinner,sun50i-a64-mmc"; + clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>; + clock-names = "ahb", "mmc"; +}; + +&mmc2 { + compatible = "allwinner,sun50i-h5-emmc", + "allwinner,sun50i-a64-emmc"; + clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>; + clock-names = "ahb", "mmc"; +}; + +&pio { + compatible = "allwinner,sun50i-h5-pinctrl"; +}; diff --git a/arch/arm64/boot/dts/allwinner/sunxi-h3-h5.dtsi b/arch/arm64/boot/dts/allwinner/sunxi-h3-h5.dtsi new file mode 120000 index 000000000000..036f01dc2b9b --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sunxi-h3-h5.dtsi @@ -0,0 +1 @@ +../../../../arm/boot/dts/sunxi-h3-h5.dtsi
\ No newline at end of file diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 3f94bce33b7f..b9ad2db7398b 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -7,9 +7,11 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-meta.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-telos.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-wetek-hub.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-wetek-play2.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-khadas-vim.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-hwacom-amazetv.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-nexbox-a95x.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q200.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q201.dtb diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi index 7a078bef04cd..a84e27622639 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi @@ -98,6 +98,27 @@ clocks = <&wifi32k>; clock-names = "ext_clock"; }; + + cvbs-connector { + compatible = "composite-video-connector"; + + port { + cvbs_connector_in: endpoint { + remote-endpoint = <&cvbs_vdac_out>; + }; + }; + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; }; /* This UART is brought out to the DB9 connector */ @@ -188,3 +209,21 @@ ðmac { status = "okay"; }; + +&cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; + }; +}; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi index 620495a43363..436b875060e7 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi @@ -71,6 +71,14 @@ reg = <0x0 0x10000000 0x0 0x200000>; no-map; }; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0xbc00000>; + alignment = <0x0 0x400000>; + linux,cma-default; + }; }; cpus { @@ -233,7 +241,7 @@ }; i2c_A: i2c@8500 { - compatible = "amlogic,meson-gxbb-i2c"; + compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c"; reg = <0x0 0x08500 0x0 0x20>; interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>; #address-cells = <1>; @@ -279,7 +287,7 @@ }; i2c_B: i2c@87c0 { - compatible = "amlogic,meson-gxbb-i2c"; + compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c"; reg = <0x0 0x087c0 0x0 0x20>; interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>; #address-cells = <1>; @@ -288,7 +296,7 @@ }; i2c_C: i2c@87e0 { - compatible = "amlogic,meson-gxbb-i2c"; + compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c"; reg = <0x0 0x087e0 0x0 0x20>; interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>; #address-cells = <1>; @@ -296,6 +304,14 @@ status = "disabled"; }; + spifc: spi@8c80 { + compatible = "amlogic,meson-gx-spifc", "amlogic,meson-gxbb-spifc"; + reg = <0x0 0x08c80 0x0 0x80>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + watchdog@98d0 { compatible = "amlogic,meson-gx-wdt", "amlogic,meson-gxbb-wdt"; reg = <0x0 0x098d0 0x0 0x10>; @@ -317,7 +333,7 @@ }; sram: sram@c8000000 { - compatible = "amlogic,meson-gxbb-sram", "mmio-sram"; + compatible = "amlogic,meson-gx-sram", "amlogic,meson-gxbb-sram", "mmio-sram"; reg = <0x0 0xc8000000 0x0 0x14000>; #address-cells = <1>; @@ -325,12 +341,12 @@ ranges = <0 0x0 0xc8000000 0x14000>; cpu_scp_lpri: scp-shmem@0 { - compatible = "amlogic,meson-gxbb-scp-shmem"; + compatible = "amlogic,meson-gx-scp-shmem", "amlogic,meson-gxbb-scp-shmem"; reg = <0x13000 0x400>; }; cpu_scp_hpri: scp-shmem@200 { - compatible = "amlogic,meson-gxbb-scp-shmem"; + compatible = "amlogic,meson-gx-scp-shmem", "amlogic,meson-gxbb-scp-shmem"; reg = <0x13400 0x400>; }; }; @@ -342,6 +358,13 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>; + clkc_AO: clock-controller@040 { + compatible = "amlogic,gx-aoclkc", "amlogic,gxbb-aoclkc"; + reg = <0x0 0x00040 0x0 0x4>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + uart_AO: serial@4c0 { compatible = "amlogic,meson-uart"; reg = <0x0 0x004c0 0x0 0x14>; @@ -358,6 +381,15 @@ status = "disabled"; }; + i2c_AO: i2c@500 { + compatible = "amlogic,meson-gx-i2c", "amlogic,meson-gxbb-i2c"; + reg = <0x0 0x500 0x0 0x20>; + interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pwm_AO_ab: pwm@550 { compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm"; reg = <0x0 0x00550 0x0 0x10>; @@ -366,7 +398,7 @@ }; ir: ir@580 { - compatible = "amlogic,meson-gxbb-ir"; + compatible = "amlogic,meson-gx-ir", "amlogic,meson-gxbb-ir"; reg = <0x0 0x00580 0x0 0x40>; interrupts = <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>; status = "disabled"; @@ -386,7 +418,6 @@ }; }; - hiubus: hiubus@c883c000 { compatible = "simple-bus"; reg = <0x0 0xc883c000 0x0 0x2000>; @@ -410,7 +441,6 @@ 0x0 0xc8834540 0x0 0x4>; interrupts = <0 8 1>; interrupt-names = "macirq"; - phy-mode = "rgmii"; status = "disabled"; }; @@ -457,6 +487,38 @@ cvbs_vdac_port: port@0 { reg = <0>; }; + + /* HDMI-TX output port */ + hdmi_tx_port: port@1 { + reg = <1>; + + hdmi_tx_out: endpoint { + remote-endpoint = <&hdmi_tx_in>; + }; + }; + }; + + hdmi_tx: hdmi-tx@c883a000 { + compatible = "amlogic,meson-gx-dw-hdmi"; + reg = <0x0 0xc883a000 0x0 0x1c>; + interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + /* VPU VENC Input */ + hdmi_tx_venc_port: port@0 { + reg = <0>; + + hdmi_tx_in: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + + /* TMDS Output */ + hdmi_tx_tmds_port: port@1 { + reg = <1>; + }; }; }; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts index 4cbd626a9e88..87198eafb04b 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts @@ -152,6 +152,17 @@ }; }; }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; }; &uart_AO { @@ -164,7 +175,24 @@ status = "okay"; pinctrl-0 = <ð_rmii_pins>; pinctrl-names = "default"; + + phy-handle = <ð_phy0>; phy-mode = "rmii"; + + snps,reset-gpio = <&gpio GPIOZ_14 0>; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-active-low; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + eth_phy0: ethernet-phy@0 { + /* IC Plus IP101GR (0x02430c54) */ + reg = <0>; + }; + }; }; &ir { @@ -245,3 +273,15 @@ remote-endpoint = <&cvbs_connector_in>; }; }; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts index c59403adb387..54a9c6a6b392 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts @@ -96,7 +96,7 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - gpio = <&gpio_ao GPIOAO_12 GPIO_ACTIVE_HIGH>; + gpio = <&gpio GPIOY_12 GPIO_ACTIVE_HIGH>; enable-active-high; }; @@ -152,6 +152,13 @@ pinctrl-0 = <ð_rgmii_pins>; pinctrl-names = "default"; phy-handle = <ð_phy0>; + phy-mode = "rgmii"; + + snps,reset-gpio = <&gpio GPIOZ_14 0>; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-active-low; + + amlogic,tx-delay-ns = <2>; mdio { compatible = "snps,dwmac-mdio"; @@ -165,6 +172,57 @@ }; }; +&pinctrl_aobus { + gpio-line-names = "UART TX", "UART RX", "VCCK En", "TF 3V3/1V8 En", + "USB HUB nRESET", "USB OTG Power En", + "J7 Header Pin2", "IR In", "J7 Header Pin4", + "J7 Header Pin6", "J7 Header Pin5", "J7 Header Pin7", + "HDMI CEC", "SYS LED"; +}; + +&pinctrl_periphs { + gpio-line-names = /* Bank GPIOZ */ + "Eth MDIO", "Eth MDC", "Eth RGMII RX Clk", + "Eth RX DV", "Eth RX D0", "Eth RX D1", "Eth RX D2", + "Eth RX D3", "Eth RGMII TX Clk", "Eth TX En", + "Eth TX D0", "Eth TX D1", "Eth TX D2", "Eth TX D3", + "Eth PHY nRESET", "Eth PHY Intc", + /* Bank GPIOH */ + "HDMI HPD", "HDMI DDC SDA", "HDMI DDC SCL", "", + /* Bank BOOT */ + "eMMC D0", "eMMC D1", "eMMC D2", "eMMC D3", "eMMC D4", + "eMMC D5", "eMMC D6", "eMMC D7", "eMMC Clk", + "eMMC Reset", "eMMC CMD", + "", "", "", "", "", "", "", + /* Bank CARD */ + "SDCard D1", "SDCard D0", "SDCard CLK", "SDCard CMD", + "SDCard D3", "SDCard D2", "SDCard Det", + /* Bank GPIODV */ + "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", + "I2C A SDA", "I2C A SCK", "I2C B SDA", "I2C B SCK", + "PWM D", "PWM B", + /* Bank GPIOY */ + "Revision Bit0", "Revision Bit1", "", + "J2 Header Pin35", "", "", "", "J2 Header Pin36", + "J2 Header Pin31", "", "", "", "TF VDD En", + "J2 Header Pin32", "J2 Header Pin26", "", "", + /* Bank GPIOX */ + "J2 Header Pin29", "J2 Header Pin24", + "J2 Header Pin23", "J2 Header Pin22", + "J2 Header Pin21", "J2 Header Pin18", + "J2 Header Pin33", "J2 Header Pin19", + "J2 Header Pin16", "J2 Header Pin15", + "J2 Header Pin12", "J2 Header Pin13", + "J2 Header Pin8", "J2 Header Pin10", + "", "", "", "", "", + "J2 Header Pin11", "", "J2 Header Pin7", + /* Bank GPIOCLK */ + "", "", "", "", + /* GPIO_TEST_N */ + ""; +}; + &ir { status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; @@ -177,6 +235,21 @@ pinctrl-names = "default"; }; +&gpio_ao { + /* + * WARNING: The USB Hub on the Odroid-C2 needs a reset signal + * to be turned high in order to be detected by the USB Controller + * This signal should be handled by a USB specific power sequence + * in order to reset the Hub when USB bus is powered down. + */ + usb-hub { + gpio-hog; + gpios = <GPIOAO_4 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "usb-hub-reset"; + }; +}; + &usb0_phy { status = "okay"; phy-supply = <&usb_otg_pwr>; @@ -194,6 +267,11 @@ status = "okay"; }; +&saradc { + status = "okay"; + vref-supply = <&vcc1v8>; +}; + /* SD */ &sd_emmc_b { status = "okay"; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts index fc0e86cb4cde..2054a474e0a9 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts @@ -96,6 +96,31 @@ }; }; +ðmac { + status = "okay"; + pinctrl-0 = <ð_rgmii_pins>; + pinctrl-names = "default"; + phy-handle = <ð_phy0>; + phy-mode = "rgmii"; + + amlogic,tx-delay-ns = <2>; + + snps,reset-gpio = <&gpio GPIOZ_14 0>; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-active-low; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + eth_phy0: ethernet-phy@3 { + /* Micrel KSZ9031 (0x00221620) */ + reg = <3>; + }; + }; +}; + &i2c_B { status = "okay"; pinctrl-0 = <&i2c_b_pins>; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts index 39bb037a3e47..ae3194663d64 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts @@ -50,3 +50,14 @@ compatible = "amlogic,p201", "amlogic,meson-gxbb"; model = "Amlogic Meson GXBB P201 Development Board"; }; + +ðmac { + status = "okay"; + pinctrl-0 = <ð_rmii_pins>; + pinctrl-names = "default"; + phy-mode = "rmii"; + + snps,reset-gpio = <&gpio GPIOZ_14 0>; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-active-low; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi index 4a96e0f6f926..3c6c0b7f4187 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi @@ -135,6 +135,17 @@ }; }; }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; }; /* This UART is brought out to the DB9 connector */ @@ -144,12 +155,6 @@ pinctrl-names = "default"; }; -ðmac { - status = "okay"; - pinctrl-0 = <ð_rgmii_pins>; - pinctrl-names = "default"; -}; - &ir { status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; @@ -250,3 +255,15 @@ remote-endpoint = <&cvbs_connector_in>; }; }; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi index 86709929fd20..aefa66dff72d 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi @@ -115,7 +115,6 @@ status = "okay"; pinctrl-0 = <&uart_ao_a_pins>; pinctrl-names = "default"; - }; &ir { @@ -128,6 +127,26 @@ status = "okay"; pinctrl-0 = <ð_rgmii_pins>; pinctrl-names = "default"; + + phy-handle = <ð_phy0>; + phy-mode = "rgmii"; + + amlogic,tx-delay-ns = <2>; + + snps,reset-gpio = <&gpio GPIOZ_14 0>; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-active-low; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + eth_phy0: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + }; + }; }; &usb0_phy { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts index 56f855901262..f057fb48fee5 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts @@ -64,3 +64,29 @@ status = "disabled"; }; }; + +ðmac { + status = "okay"; + pinctrl-0 = <ð_rgmii_pins>; + pinctrl-names = "default"; + + phy-handle = <ð_phy0>; + phy-mode = "rgmii"; + + amlogic,tx-delay-ns = <2>; + + snps,reset-gpio = <&gpio GPIOZ_14 0>; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-active-low; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + eth_phy0: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts index ea79fdd2c248..743acb5f5d06 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts @@ -87,6 +87,32 @@ }; }; +ðmac { + status = "okay"; + pinctrl-0 = <ð_rgmii_pins>; + pinctrl-names = "default"; + + phy-handle = <ð_phy0>; + phy-mode = "rgmii"; + + amlogic,tx-delay-ns = <2>; + + snps,reset-gpio = <&gpio GPIOZ_14 0>; + snps,reset-delays-us = <0 10000 1000000>; + snps,reset-active-low; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + eth_phy0: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + }; + }; +}; + &i2c_A { status = "okay"; pinctrl-0 = <&i2c_a_pins>; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi index a375cb21cc8b..86105a69690a 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi @@ -97,17 +97,6 @@ }; }; -&cbus { - spifc: spi@8c80 { - compatible = "amlogic,meson-gxbb-spifc"; - reg = <0x0 0x08c80 0x0 0x80>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkc CLKID_SPI>; - status = "disabled"; - }; -}; - ðmac { clocks = <&clkc CLKID_ETH>, <&clkc CLKID_FCLK_DIV2>, @@ -129,6 +118,7 @@ reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aobus 0 0 14>; }; uart_ao_a_pins: uart_ao_a { @@ -203,30 +193,62 @@ function = "pwm_ao_b"; }; }; - }; - clkc_AO: clock-controller@040 { - compatible = "amlogic,gxbb-aoclkc"; - reg = <0x0 0x00040 0x0 0x4>; - #clock-cells = <1>; - #reset-cells = <1>; - }; + i2s_am_clk_pins: i2s_am_clk { + mux { + groups = "i2s_am_clk"; + function = "i2s_out_ao"; + }; + }; - pwm_ab_AO: pwm@550 { - compatible = "amlogic,meson-gxbb-pwm"; - reg = <0x0 0x0550 0x0 0x10>; - #pwm-cells = <3>; - status = "disabled"; - }; + i2s_out_ao_clk_pins: i2s_out_ao_clk { + mux { + groups = "i2s_out_ao_clk"; + function = "i2s_out_ao"; + }; + }; - i2c_AO: i2c@500 { - compatible = "amlogic,meson-gxbb-i2c"; - reg = <0x0 0x500 0x0 0x20>; - interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>; - clocks = <&clkc CLKID_AO_I2C>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; + i2s_out_lr_clk_pins: i2s_out_lr_clk { + mux { + groups = "i2s_out_lr_clk"; + function = "i2s_out_ao"; + }; + }; + + i2s_out_ch01_ao_pins: i2s_out_ch01_ao { + mux { + groups = "i2s_out_ch01_ao"; + function = "i2s_out_ao"; + }; + }; + + i2s_out_ch23_ao_pins: i2s_out_ch23_ao { + mux { + groups = "i2s_out_ch23_ao"; + function = "i2s_out_ao"; + }; + }; + + i2s_out_ch45_ao_pins: i2s_out_ch45_ao { + mux { + groups = "i2s_out_ch45_ao"; + function = "i2s_out_ao"; + }; + }; + + spdif_out_ao_6_pins: spdif_out_ao_6 { + mux { + groups = "spdif_out_ao_6"; + function = "spdif_out_ao"; + }; + }; + + spdif_out_ao_13_pins: spdif_out_ao_13 { + mux { + groups = "spdif_out_ao_13"; + function = "spdif_out_ao"; + }; + }; }; }; @@ -245,6 +267,7 @@ reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_periphs 0 14 120>; }; emmc_pins: emmc { @@ -467,6 +490,34 @@ function = "hdmi_i2c"; }; }; + + i2sout_ch23_y_pins: i2sout_ch23_y { + mux { + groups = "i2sout_ch23_y"; + function = "i2s_out"; + }; + }; + + i2sout_ch45_y_pins: i2sout_ch45_y { + mux { + groups = "i2sout_ch45_y"; + function = "i2s_out"; + }; + }; + + i2sout_ch67_y_pins: i2sout_ch67_y { + mux { + groups = "i2sout_ch67_y"; + function = "i2s_out"; + }; + }; + + spdif_out_y_pins: spdif_out_y { + mux { + groups = "spdif_out_y"; + function = "spdif_out"; + }; + }; }; }; @@ -478,10 +529,51 @@ }; }; +&apb { + mali: gpu@c0000 { + compatible = "amlogic,meson-gxbb-mali", "arm,mali-450"; + reg = <0x0 0xc0000 0x0 0x40000>; + interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "gp", "gpmmu", "pp", "pmu", + "pp0", "ppmmu0", "pp1", "ppmmu1", + "pp2", "ppmmu2"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>; + clock-names = "bus", "core"; + + /* + * Mali clocking is provided by two identical clock paths + * MALI_0 and MALI_1 muxed to a single clock by a glitch + * free mux to safely change frequency while running. + */ + assigned-clocks = <&clkc CLKID_MALI_0_SEL>, + <&clkc CLKID_MALI_0>, + <&clkc CLKID_MALI>; /* Glitch free mux */ + assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, + <0>, /* Do Nothing */ + <&clkc CLKID_MALI_0>; + assigned-clock-rates = <0>, /* Do Nothing */ + <666666666>, + <0>; /* Do Nothing */ + }; +}; + &i2c_A { clocks = <&clkc CLKID_I2C>; }; +&i2c_AO { + clocks = <&clkc CLKID_AO_I2C>; +}; + &i2c_B { clocks = <&clkc CLKID_I2C>; }; @@ -521,6 +613,10 @@ clock-names = "core", "clkin0", "clkin1"; }; +&spifc { + clocks = <&clkc CLKID_SPI>; +}; + &vpu { compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; }; @@ -529,3 +625,15 @@ clocks = <&clkc CLKID_RNG0>; clock-names = "core"; }; + +&hdmi_tx { + compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; + resets = <&reset RESET_HDMITX_CAPB3>, + <&reset RESET_HDMI_SYSTEM_RESET>, + <&reset RESET_HDMI_TX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; + clocks = <&clkc CLKID_HDMI_PCLK>, + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi new file mode 100644 index 000000000000..f06cc234693b --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 BayLibre SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +&apb { + mali: gpu@c0000 { + compatible = "amlogic,meson-gxbb-mali", "arm,mali-450"; + reg = <0x0 0xc0000 0x0 0x40000>; + interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "gp", "gpmmu", "pp", "pmu", + "pp0", "ppmmu0", "pp1", "ppmmu1", + "pp2", "ppmmu2"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>; + clock-names = "bus", "core"; + + /* + * Mali clocking is provided by two identical clock paths + * MALI_0 and MALI_1 muxed to a single clock by a glitch + * free mux to safely change frequency while running. + */ + assigned-clocks = <&clkc CLKID_MALI_0_SEL>, + <&clkc CLKID_MALI_0>, + <&clkc CLKID_MALI>; /* Glitch free mux */ + assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, + <0>, /* Do Nothing */ + <&clkc CLKID_MALI_0>; + assigned-clock-rates = <0>, /* Do Nothing */ + <666666666>, + <0>; /* Do Nothing */ + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts index f66939cacd37..f9fbfdad8dde 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts @@ -43,12 +43,47 @@ /dts-v1/; +#include <dt-bindings/input/input.h> + #include "meson-gxl-s905d.dtsi" #include "meson-gx-p23x-q20x.dtsi" / { compatible = "amlogic,p230", "amlogic,s905d", "amlogic,meson-gxl"; model = "Amlogic Meson GXL (S905D) P230 Development Board"; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + + button-function { + label = "Update"; + linux,code = <KEY_VENDOR>; + press-threshold-microvolt = <10000>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "power"; + linux,code = <KEY_POWER>; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + }; + + vddio_ao18: regulator-vddio_ao18 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; }; /* P230 has exclusive choice between internal or external PHY */ @@ -59,6 +94,8 @@ /* Select external PHY by default */ phy-handle = <&external_phy>; + amlogic,tx-delay-ns = <2>; + /* External PHY reset is shared with internal PHY Led signals */ snps,reset-gpio = <&gpio GPIOZ_14 0>; snps,reset-delays-us = <0 10000 1000000>; @@ -75,3 +112,8 @@ max-speed = <1000>; }; }; + +&saradc { + status = "okay"; + vref-supply = <&vddio_ao18>; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi index 615308e55576..5a90e30c1006 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi @@ -42,6 +42,7 @@ */ #include "meson-gxl.dtsi" +#include "meson-gxl-mali.dtsi" / { compatible = "amlogic,s905d", "amlogic,meson-gxl"; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts new file mode 100644 index 000000000000..2a5804ce7f4b --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017 Carlo Caione + * Copyright (c) 2016 BayLibre, Inc. + * Author: Neil Armstrong <narmstrong@kernel.org> + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/dts-v1/; + +#include "meson-gxl-s905x.dtsi" + +/ { + compatible = "hwacom,amazetv", "amlogic,s905x", "amlogic,meson-gxl"; + model = "Hwacom AmazeTV (S905X)"; + + aliases { + serial0 = &uart_AO; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + vddio_card: gpio-regulator { + compatible = "regulator-gpio"; + + regulator-name = "VDDIO_CARD"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + gpios = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + + /* Based on P200 schematics, signal CARD_1.8V/3.3V_CTR */ + states = <1800000 0 + 3300000 1>; + }; + + vddio_boot: regulator-vddio_boot { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_BOOT"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vddao_3v3: regulator-vddao_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vcc_3v3: regulator-vcc_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; + }; + + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + clocks = <&wifi32k>; + clock-names = "ext_clock"; + }; + + cvbs-connector { + compatible = "composite-video-connector"; + + port { + cvbs_connector_in: endpoint { + remote-endpoint = <&cvbs_vdac_out>; + }; + }; + }; +}; + +&cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; + }; +}; + +ðmac { + status = "okay"; + phy-mode = "rmii"; + phy-handle = <&internal_phy>; +}; + +&ir { + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; +}; + +&pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; + pinctrl-names = "default"; + clocks = <&clkc CLKID_FCLK_DIV4>; + clock-names = "clkin0"; +}; + +/* SD card */ +&sd_emmc_b { + status = "okay"; + pinctrl-0 = <&sdcard_pins>; + pinctrl-names = "default"; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <100000000>; + disable-wp; + + cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>; + cd-inverted; + + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddio_card>; +}; + +/* eMMC */ +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_pins>; + pinctrl-names = "default"; + + bus-width = <8>; + cap-sd-highspeed; + cap-mmc-highspeed; + max-frequency = <100000000>; + non-removable; + disable-wp; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vddio_boot>; +}; + +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts new file mode 100644 index 000000000000..3c8b0b51ef27 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>. + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/dts-v1/; + +#include <dt-bindings/input/input.h> + +#include "meson-gxl-s905x-p212.dtsi" + +/ { + compatible = "khadas,vim", "amlogic,s905x", "amlogic,meson-gxl"; + model = "Khadas VIM"; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + + button-function { + label = "Function"; + linux,code = <KEY_FN>; + press-threshold-microvolt = <10000>; + }; + }; + + aliases { + serial2 = &uart_AO_B; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "power"; + linux,code = <KEY_POWER>; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + + power { + label = "vim:red:power"; + pwms = <&pwm_AO_ab 1 7812500 0>; + max-brightness = <255>; + linux,default-trigger = "default-on"; + }; + }; +}; + +&i2c_A { + status = "okay"; + pinctrl-0 = <&i2c_a_pins>; + pinctrl-names = "default"; +}; + +&i2c_B { + status = "okay"; + pinctrl-0 = <&i2c_b_pins>; + pinctrl-names = "default"; + + rtc: rtc@51 { + /* has to be enabled manually when a battery is connected: */ + status = "disabled"; + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "xin32k"; + }; +}; + +&ir { + linux,rc-map-name = "rc-geekbox"; +}; + +&pwm_AO_ab { + status = "okay"; + pinctrl-0 = <&pwm_ao_a_3_pins>, <&pwm_ao_b_pins>; + pinctrl-names = "default"; + clocks = <&clkc CLKID_FCLK_DIV4>; + clock-names = "clkin0"; +}; + +&pwm_ef { + pinctrl-0 = <&pwm_e_pins>, <&pwm_f_clk_pins>; +}; + +&sd_emmc_a { + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +/* This is brought out on the Linux_RX (18) and Linux_TX (19) pins: */ +&uart_AO { + status = "okay"; +}; + +/* This is brought out on the UART_RX_AO_B (15) and UART_TX_AO_B (16) pins: */ +&uart_AO_B { + status = "okay"; + pinctrl-0 = <&uart_ao_b_pins>; + pinctrl-names = "default"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts index cea4a3eded9b..8873c058fad2 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts @@ -127,6 +127,17 @@ }; }; }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; }; &uart_AO { @@ -219,3 +230,15 @@ remote-endpoint = <&cvbs_connector_in>; }; }; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts index 9639f012b02b..db31e093f40e 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts @@ -43,23 +43,26 @@ /dts-v1/; -#include "meson-gxl-s905x.dtsi" +#include "meson-gxl-s905x-p212.dtsi" / { compatible = "amlogic,p212", "amlogic,s905x", "amlogic,meson-gxl"; model = "Amlogic Meson GXL (S905X) P212 Development Board"; - aliases { - serial0 = &uart_AO; - }; + cvbs-connector { + compatible = "composite-video-connector"; - chosen { - stdout-path = "serial0:115200n8"; + port { + cvbs_connector_in: endpoint { + remote-endpoint = <&cvbs_vdac_out>; + }; + }; }; +}; - memory@0 { - device_type = "memory"; - reg = <0x0 0x0 0x0 0x80000000>; +&cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; }; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi new file mode 100644 index 000000000000..f3eea8e89d12 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>. + * Based on meson-gx-p23x-q20x.dtsi: + * - Copyright (c) 2016 Endless Computers, Inc. + * Author: Carlo Caione <carlo@endlessm.com> + * - Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/* Common DTSI for devices which are based on the P212 reference board. */ + +#include "meson-gxl-s905x.dtsi" + +/ { + aliases { + serial0 = &uart_AO; + serial1 = &uart_A; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + vddio_boot: regulator-vddio_boot { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_BOOT"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vddao_3v3: regulator-vddao_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vddio_ao18: regulator-vddio_ao18 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vcc_3v3: regulator-vcc_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; + }; + + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + clocks = <&wifi32k>; + clock-names = "ext_clock"; + }; +}; + +ðmac { + status = "okay"; +}; + +&ir { + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddio_ao18>; +}; + +/* Wireless SDIO Module */ +&sd_emmc_a { + status = "okay"; + pinctrl-0 = <&sdio_pins>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <100000000>; + + non-removable; + disable-wp; + + mmc-pwrseq = <&sdio_pwrseq>; + + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddio_boot>; +}; + +/* SD card */ +&sd_emmc_b { + status = "okay"; + pinctrl-0 = <&sdcard_pins>; + pinctrl-names = "default"; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <100000000>; + disable-wp; + + cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>; + cd-inverted; + + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddio_boot>; +}; + +/* eMMC */ +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_pins>; + pinctrl-names = "default"; + + bus-width = <8>; + cap-sd-highspeed; + cap-mmc-highspeed; + max-frequency = <200000000>; + non-removable; + disable-wp; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vddio_boot>; +}; + +&pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; + pinctrl-names = "default"; + clocks = <&clkc CLKID_FCLK_DIV4>; + clock-names = "clkin0"; +}; + +/* This is connected to the Bluetooth module: */ +&uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; + uart-has-rtscts; +}; + +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi index 08237ee1e362..0f78d836edaf 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x.dtsi @@ -42,6 +42,7 @@ */ #include "meson-gxl.dtsi" +#include "meson-gxl-mali.dtsi" / { compatible = "amlogic,s905x", "amlogic,meson-gxl"; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi index fe11b5fc61f7..d8e096dff10a 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi @@ -44,6 +44,7 @@ #include "meson-gx.dtsi" #include <dt-bindings/clock/gxbb-clkc.h> #include <dt-bindings/gpio/meson-gxl-gpio.h> +#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h> / { compatible = "amlogic,meson-gxl"; @@ -79,6 +80,7 @@ reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aobus 0 0 14>; }; uart_ao_a_pins: uart_ao_a { @@ -103,6 +105,13 @@ }; }; + uart_ao_b_0_1_pins: uart_ao_b_0_1 { + mux { + groups = "uart_tx_ao_b_0", "uart_rx_ao_b_1"; + function = "uart_ao_b"; + }; + }; + uart_ao_b_cts_rts_pins: uart_ao_b_cts_rts { mux { groups = "uart_cts_ao_b", @@ -118,12 +127,69 @@ }; }; + i2c_ao_pins: i2c_ao { + mux { + groups = "i2c_sck_ao", + "i2c_sda_ao"; + function = "i2c_ao"; + }; + }; + + pwm_ao_a_3_pins: pwm_ao_a_3 { + mux { + groups = "pwm_ao_a_3"; + function = "pwm_ao_a"; + }; + }; + + pwm_ao_a_8_pins: pwm_ao_a_8 { + mux { + groups = "pwm_ao_a_8"; + function = "pwm_ao_a"; + }; + }; + pwm_ao_b_pins: pwm_ao_b { mux { groups = "pwm_ao_b"; function = "pwm_ao_b"; }; }; + + pwm_ao_b_6_pins: pwm_ao_b_6 { + mux { + groups = "pwm_ao_b_6"; + function = "pwm_ao_b"; + }; + }; + + i2s_out_ch23_ao_pins: i2s_out_ch23_ao { + mux { + groups = "i2s_out_ch23_ao"; + function = "i2s_out_ao"; + }; + }; + + i2s_out_ch45_ao_pins: i2s_out_ch45_ao { + mux { + groups = "i2s_out_ch45_ao"; + function = "i2s_out_ao"; + }; + }; + + spdif_out_ao_6_pins: spdif_out_ao_6 { + mux { + groups = "spdif_out_ao_6"; + function = "spdif_out_ao"; + }; + }; + + spdif_out_ao_9_pins: spdif_out_ao_9 { + mux { + groups = "spdif_out_ao_9"; + function = "spdif_out_ao"; + }; + }; }; }; @@ -142,6 +208,7 @@ reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; + gpio-ranges = <&pinctrl_periphs 0 14 101>; }; emmc_pins: emmc { @@ -154,6 +221,16 @@ }; }; + nor_pins: nor { + mux { + groups = "nor_d", + "nor_q", + "nor_c", + "nor_cs"; + function = "nor"; + }; + }; + sdcard_pins: sdcard { mux { groups = "sdcard_d0", @@ -277,6 +354,34 @@ }; }; + pwm_a_pins: pwm_a { + mux { + groups = "pwm_a"; + function = "pwm_a"; + }; + }; + + pwm_b_pins: pwm_b { + mux { + groups = "pwm_b"; + function = "pwm_b"; + }; + }; + + pwm_c_pins: pwm_c { + mux { + groups = "pwm_c"; + function = "pwm_c"; + }; + }; + + pwm_d_pins: pwm_d { + mux { + groups = "pwm_d"; + function = "pwm_d"; + }; + }; + pwm_e_pins: pwm_e { mux { groups = "pwm_e"; @@ -284,6 +389,20 @@ }; }; + pwm_f_clk_pins: pwm_f_clk { + mux { + groups = "pwm_f_clk"; + function = "pwm_f"; + }; + }; + + pwm_f_x_pins: pwm_f_x { + mux { + groups = "pwm_f_x"; + function = "pwm_f"; + }; + }; + hdmi_hpd_pins: hdmi_hpd { mux { groups = "hdmi_hpd"; @@ -297,6 +416,61 @@ function = "hdmi_i2c"; }; }; + + i2s_am_clk_pins: i2s_am_clk { + mux { + groups = "i2s_am_clk"; + function = "i2s_out"; + }; + }; + + i2s_out_ao_clk_pins: i2s_out_ao_clk { + mux { + groups = "i2s_out_ao_clk"; + function = "i2s_out"; + }; + }; + + i2s_out_lr_clk_pins: i2s_out_lr_clk { + mux { + groups = "i2s_out_lr_clk"; + function = "i2s_out"; + }; + }; + + i2s_out_ch01_pins: i2s_out_ch01 { + mux { + groups = "i2s_out_ch01"; + function = "i2s_out"; + }; + }; + i2sout_ch23_z_pins: i2sout_ch23_z { + mux { + groups = "i2sout_ch23_z"; + function = "i2s_out"; + }; + }; + + i2sout_ch45_z_pins: i2sout_ch45_z { + mux { + groups = "i2sout_ch45_z"; + function = "i2s_out"; + }; + }; + + i2sout_ch67_z_pins: i2sout_ch67_z { + mux { + groups = "i2sout_ch67_z"; + function = "i2s_out"; + }; + }; + + spdif_out_h_pins: spdif_out_ao_h { + mux { + groups = "spdif_out_h"; + function = "spdif_out"; + }; + }; }; eth-phy-mux { @@ -339,6 +513,10 @@ clocks = <&clkc CLKID_I2C>; }; +&i2c_AO { + clocks = <&clkc CLKID_AO_I2C>; +}; + &i2c_B { clocks = <&clkc CLKID_I2C>; }; @@ -378,6 +556,22 @@ clock-names = "core", "clkin0", "clkin1"; }; +&spifc { + clocks = <&clkc CLKID_SPI>; +}; + &vpu { compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu"; }; + +&hdmi_tx { + compatible = "amlogic,meson-gxl-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; + resets = <&reset RESET_HDMITX_CAPB3>, + <&reset RESET_HDMI_SYSTEM_RESET>, + <&reset RESET_HDMI_TX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; + clocks = <&clkc CLKID_HDMI_PCLK>, + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts index 5a337d339df1..11b0bf46a95c 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts @@ -100,6 +100,17 @@ }; }; }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; }; /* This UART is brought out to the DB9 connector */ @@ -162,6 +173,8 @@ /* Select external PHY by default */ phy-handle = <&external_phy>; + amlogic,tx-delay-ns = <2>; + snps,reset-gpio = <&gpio GPIOZ_14 0>; snps,reset-delays-us = <0 10000 1000000>; snps,reset-active-low; @@ -183,3 +196,15 @@ remote-endpoint = <&cvbs_connector_in>; }; }; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts index 5dbc66088355..b65776b01911 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts @@ -43,12 +43,47 @@ /dts-v1/; +#include <dt-bindings/input/input.h> + #include "meson-gxm.dtsi" #include "meson-gx-p23x-q20x.dtsi" / { compatible = "amlogic,q200", "amlogic,s912", "amlogic,meson-gxm"; model = "Amlogic Meson GXM (S912) Q200 Development Board"; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + + button-function { + label = "Update"; + linux,code = <KEY_VENDOR>; + press-threshold-microvolt = <10000>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "power"; + linux,code = <KEY_POWER>; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + }; + + vddio_ao18: regulator-vddio_ao18 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; }; /* Q200 has exclusive choice between internal or external PHY */ @@ -59,6 +94,8 @@ /* Select external PHY by default */ phy-handle = <&external_phy>; + amlogic,tx-delay-ns = <2>; + /* External PHY reset is shared with internal PHY Led signals */ snps,reset-gpio = <&gpio GPIOZ_14 0>; snps,reset-delays-us = <0 10000 1000000>; @@ -75,3 +112,8 @@ max-speed = <1000>; }; }; + +&saradc { + status = "okay"; + vref-supply = <&vddio_ao18>; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi index ddea7305c644..fe451cce93e7 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi @@ -130,3 +130,6 @@ compatible = "amlogic,meson-gxm-vpu", "amlogic,meson-gx-vpu"; }; +&hdmi_tx { + compatible = "amlogic,meson-gxm-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; +}; diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index df539e865b90..bfe7d683a42e 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -428,7 +428,7 @@ }; }; - pcie_ctlr: pcie-controller@40000000 { + pcie_ctlr: pcie@40000000 { compatible = "arm,juno-r1-pcie", "plda,xpressrich3-axi", "pci-host-ecam-generic"; device_type = "pci"; reg = <0 0x40000000 0 0x10000000>; /* ECAM config space */ @@ -699,7 +699,7 @@ <0x00000008 0x80000000 0x1 0x80000000>; }; - smb@08000000 { + smb@8000000 { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; diff --git a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi index 098601657f82..2ac43221ddb6 100644 --- a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi +++ b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi @@ -137,7 +137,7 @@ #size-cells = <1>; ranges = <0 3 0 0x200000>; - v2m_sysctl: sysctl@020000 { + v2m_sysctl: sysctl@20000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x020000 0x1000>; clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&mb_clk24mhz>; @@ -148,7 +148,7 @@ assigned-clock-parents = <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>; }; - apbregs@010000 { + apbregs@10000 { compatible = "syscon", "simple-mfd"; reg = <0x010000 0x1000>; @@ -216,7 +216,7 @@ }; }; - mmci@050000 { + mmci@50000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x050000 0x1000>; interrupts = <5>; @@ -228,7 +228,7 @@ clock-names = "mclk", "apb_pclk"; }; - kmi@060000 { + kmi@60000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x060000 0x1000>; interrupts = <8>; @@ -236,7 +236,7 @@ clock-names = "KMIREFCLK", "apb_pclk"; }; - kmi@070000 { + kmi@70000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x070000 0x1000>; interrupts = <8>; @@ -244,7 +244,7 @@ clock-names = "KMIREFCLK", "apb_pclk"; }; - wdt@0f0000 { + wdt@f0000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f0000 0x10000>; interrupts = <7>; diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts index 0033c59a64b5..0e8943ab94d7 100644 --- a/arch/arm64/boot/dts/arm/juno-r1.dts +++ b/arch/arm64/boot/dts/arm/juno-r1.dts @@ -89,6 +89,12 @@ reg = <0x0 0x0>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; next-level-cache = <&A57_L2>; clocks = <&scpi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -100,6 +106,12 @@ reg = <0x0 0x1>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; next-level-cache = <&A57_L2>; clocks = <&scpi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -111,6 +123,12 @@ reg = <0x0 0x100>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -122,6 +140,12 @@ reg = <0x0 0x101>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -133,6 +157,12 @@ reg = <0x0 0x102>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -144,6 +174,12 @@ reg = <0x0 0x103>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -152,10 +188,16 @@ A57_L2: l2-cache0 { compatible = "cache"; + cache-size = <0x200000>; + cache-line-size = <64>; + cache-sets = <2048>; }; A53_L2: l2-cache1 { compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; }; }; diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts index 218d0e4736a8..405e2fba025b 100644 --- a/arch/arm64/boot/dts/arm/juno-r2.dts +++ b/arch/arm64/boot/dts/arm/juno-r2.dts @@ -89,6 +89,12 @@ reg = <0x0 0x0>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; next-level-cache = <&A72_L2>; clocks = <&scpi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -100,6 +106,12 @@ reg = <0x0 0x1>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; next-level-cache = <&A72_L2>; clocks = <&scpi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -111,6 +123,12 @@ reg = <0x0 0x100>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -122,6 +140,12 @@ reg = <0x0 0x101>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -133,6 +157,12 @@ reg = <0x0 0x102>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -144,6 +174,12 @@ reg = <0x0 0x103>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -152,10 +188,16 @@ A72_L2: l2-cache0 { compatible = "cache"; + cache-size = <0x200000>; + cache-line-size = <64>; + cache-sets = <2048>; }; A53_L2: l2-cache1 { compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; }; }; diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index bb2820ef3d5b..0220494c9b80 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -88,6 +88,12 @@ reg = <0x0 0x0>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; next-level-cache = <&A57_L2>; clocks = <&scpi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -99,6 +105,12 @@ reg = <0x0 0x1>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; next-level-cache = <&A57_L2>; clocks = <&scpi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -110,6 +122,12 @@ reg = <0x0 0x100>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -121,6 +139,12 @@ reg = <0x0 0x101>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -132,6 +156,12 @@ reg = <0x0 0x102>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -143,6 +173,12 @@ reg = <0x0 0x103>; device_type = "cpu"; enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; next-level-cache = <&A53_L2>; clocks = <&scpi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; @@ -151,10 +187,16 @@ A57_L2: l2-cache0 { compatible = "cache"; + cache-size = <0x200000>; + cache-line-size = <64>; + cache-sets = <2048>; }; A53_L2: l2-cache1 { compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; }; }; diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile index f1caece9d3a7..bfa8f8e4c5af 100644 --- a/arch/arm64/boot/dts/broadcom/Makefile +++ b/arch/arm64/boot/dts/broadcom/Makefile @@ -1,6 +1,5 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-b.dtb dtb-$(CONFIG_ARCH_BCM_IPROC) += ns2-svk.dtb ns2-xmc.dtb -dtb-$(CONFIG_ARCH_VULCAN) += vulcan-eval.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts index 5ae08161649e..ec19fbf928a1 100644 --- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts +++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts @@ -57,55 +57,55 @@ }; &enet { - status = "ok"; + status = "okay"; }; &pci_phy0 { - status = "ok"; + status = "okay"; }; &pci_phy1 { - status = "ok"; + status = "okay"; }; &pcie0 { - status = "ok"; + status = "okay"; }; &pcie4 { - status = "ok"; + status = "okay"; }; &pcie8 { - status = "ok"; + status = "okay"; }; &i2c0 { - status = "ok"; + status = "okay"; }; &i2c1 { - status = "ok"; + status = "okay"; }; &uart0 { - status = "ok"; + status = "okay"; }; &uart1 { - status = "ok"; + status = "okay"; }; &uart2 { - status = "ok"; + status = "okay"; }; &uart3 { - status = "ok"; + status = "okay"; }; &ssp0 { - status = "ok"; + status = "okay"; slic@0 { compatible = "silabs,si3226x"; @@ -126,7 +126,7 @@ }; &ssp1 { - status = "ok"; + status = "okay"; at25@0 { compatible = "atmel,at25"; @@ -150,23 +150,23 @@ }; &sata_phy0 { - status = "ok"; + status = "okay"; }; &sata_phy1 { - status = "ok"; + status = "okay"; }; &sata { - status = "ok"; + status = "okay"; }; &sdio0 { - status = "ok"; + status = "okay"; }; &sdio1 { - status = "ok"; + status = "okay"; }; &nand { diff --git a/arch/arm64/boot/dts/broadcom/ns2-xmc.dts b/arch/arm64/boot/dts/broadcom/ns2-xmc.dts index 99a2723cccd2..ab4ae1a32fab 100644 --- a/arch/arm64/boot/dts/broadcom/ns2-xmc.dts +++ b/arch/arm64/boot/dts/broadcom/ns2-xmc.dts @@ -54,15 +54,15 @@ }; &enet { - status = "ok"; + status = "okay"; }; &i2c0 { - status = "ok"; + status = "okay"; }; &i2c1 { - status = "ok"; + status = "okay"; }; &mdio_mux_iproc { @@ -122,27 +122,27 @@ }; &pci_phy0 { - status = "ok"; + status = "okay"; }; &pcie0 { - status = "ok"; + status = "okay"; }; &pcie8 { - status = "ok"; + status = "okay"; }; &sata_phy0 { - status = "ok"; + status = "okay"; }; &sata_phy1 { - status = "ok"; + status = "okay"; }; &sata { - status = "ok"; + status = "okay"; }; &qspi { @@ -187,5 +187,5 @@ }; &uart3 { - status = "ok"; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi index bcb03fc32665..35a309ae3ed8 100644 --- a/arch/arm64/boot/dts/broadcom/ns2.dtsi +++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi @@ -222,6 +222,12 @@ brcm,use-bcm-hdr; }; + crypto0: crypto@612d0000 { + compatible = "brcm,spum-crypto"; + reg = <0x612d0000 0x900>; + mboxes = <&pdc0 0>; + }; + pdc1: iproc-pdc1@612e0000 { compatible = "brcm,iproc-pdc-mbox"; reg = <0x612e0000 0x445>; /* PDC FS1 regs */ @@ -232,6 +238,12 @@ brcm,use-bcm-hdr; }; + crypto1: crypto@612f0000 { + compatible = "brcm,spum-crypto"; + reg = <0x612f0000 0x900>; + mboxes = <&pdc1 0>; + }; + pdc2: iproc-pdc2@61300000 { compatible = "brcm,iproc-pdc-mbox"; reg = <0x61300000 0x445>; /* PDC FS2 regs */ @@ -242,6 +254,12 @@ brcm,use-bcm-hdr; }; + crypto2: crypto@61310000 { + compatible = "brcm,spum-crypto"; + reg = <0x61310000 0x900>; + mboxes = <&pdc2 0>; + }; + pdc3: iproc-pdc3@61320000 { compatible = "brcm,iproc-pdc-mbox"; reg = <0x61320000 0x445>; /* PDC FS3 regs */ @@ -252,6 +270,12 @@ brcm,use-bcm-hdr; }; + crypto3: crypto@61330000 { + compatible = "brcm,spum-crypto"; + reg = <0x61330000 0x900>; + mboxes = <&pdc3 0>; + }; + dma0: dma@61360000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x61360000 0x1000>; diff --git a/arch/arm64/boot/dts/cavium/Makefile b/arch/arm64/boot/dts/cavium/Makefile index e34f89ddabb2..581b2c1c400a 100644 --- a/arch/arm64/boot/dts/cavium/Makefile +++ b/arch/arm64/boot/dts/cavium/Makefile @@ -1,4 +1,5 @@ dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb +dtb-$(CONFIG_ARCH_THUNDER2) += thunder2-99xx.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/broadcom/vulcan-eval.dts b/arch/arm64/boot/dts/cavium/thunder2-99xx.dts index 9ee8d3da0e3f..6c6fb8692fde 100644 --- a/arch/arm64/boot/dts/broadcom/vulcan-eval.dts +++ b/arch/arm64/boot/dts/cavium/thunder2-99xx.dts @@ -1,6 +1,7 @@ /* - * dts file for Broadcom (BRCM) Vulcan Evaluation Platform + * dts file for Cavium ThunderX2 CN99XX Evaluation Platform * + * Copyright (c) 2017 Cavium Inc. * Copyright (c) 2013-2016 Broadcom * * This program is free software; you can redistribute it and/or @@ -11,11 +12,11 @@ /dts-v1/; -#include "vulcan.dtsi" +#include "thunder2-99xx.dtsi" / { - model = "Broadcom Vulcan Eval Platform"; - compatible = "brcm,vulcan-eval", "brcm,vulcan-soc"; + model = "Cavium ThunderX2 CN99XX"; + compatible = "cavium,thunderx2-cn9900", "brcm,vulcan-soc"; memory { device_type = "memory"; diff --git a/arch/arm64/boot/dts/broadcom/vulcan.dtsi b/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi index 34e11a9db2a0..4220fbdcb24a 100644 --- a/arch/arm64/boot/dts/broadcom/vulcan.dtsi +++ b/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi @@ -1,6 +1,7 @@ /* - * dtsi file for Broadcom (BRCM) Vulcan processor + * dtsi file for Cavium ThunderX2 CN99XX processor * + * Copyright (c) 2017 Cavium Inc. * Copyright (c) 2013-2016 Broadcom * Author: Zi Shen Lim <zlim@broadcom.com> * @@ -13,8 +14,8 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> / { - model = "Broadcom Vulcan"; - compatible = "brcm,vulcan-soc"; + model = "Cavium ThunderX2 CN99XX"; + compatible = "cavium,thunderx2-cn9900", "brcm,vulcan-soc"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; @@ -26,28 +27,28 @@ cpu@0 { device_type = "cpu"; - compatible = "brcm,vulcan", "arm,armv8"; + compatible = "cavium,thunder2", "brcm,vulcan", "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; }; cpu@1 { device_type = "cpu"; - compatible = "brcm,vulcan", "arm,armv8"; + compatible = "cavium,thunder2", "brcm,vulcan", "arm,armv8"; reg = <0x0 0x1>; enable-method = "psci"; }; cpu@2 { device_type = "cpu"; - compatible = "brcm,vulcan", "arm,armv8"; + compatible = "cavium,thunder2", "brcm,vulcan", "arm,armv8"; reg = <0x0 0x2>; enable-method = "psci"; }; cpu@3 { device_type = "cpu"; - compatible = "brcm,vulcan", "arm,armv8"; + compatible = "cavium,thunder2", "brcm,vulcan", "arm,armv8"; reg = <0x0 0x3>; enable-method = "psci"; }; diff --git a/arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi index c42dc39c3223..ec11343dc528 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi @@ -94,27 +94,27 @@ compatible = "operating-points-v2"; opp-shared; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <1075000>; }; - opp@267000000 { + opp-267000000 { opp-hz = /bits/ 64 <267000000>; opp-microvolt = <1000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <975000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; opp-microvolt = <962500>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; opp-microvolt = <950000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <937500>; }; @@ -123,19 +123,19 @@ bus_g2d_266_opp_table: opp_table3 { compatible = "operating-points-v2"; - opp@267000000 { + opp-267000000 { opp-hz = /bits/ 64 <267000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; }; @@ -143,13 +143,13 @@ bus_gscl_opp_table: opp_table4 { compatible = "operating-points-v2"; - opp@333000000 { + opp-333000000 { opp-hz = /bits/ 64 <333000000>; }; - opp@222000000 { + opp-222000000 { opp-hz = /bits/ 64 <222000000>; }; - opp@166500000 { + opp-166500000 { opp-hz = /bits/ 64 <166500000>; }; }; @@ -158,22 +158,22 @@ compatible = "operating-points-v2"; opp-shared; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; }; - opp@267000000 { + opp-267000000 { opp-hz = /bits/ 64 <267000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; - opp@160000000 { + opp-160000000 { opp-hz = /bits/ 64 <160000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; }; @@ -181,16 +181,16 @@ bus_noc2_opp_table: opp_table6 { compatible = "operating-points-v2"; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; }; - opp@134000000 { + opp-134000000 { opp-hz = /bits/ 64 <134000000>; }; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; }; }; diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi index 098ad557fee3..e2b0da2c0bc7 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi @@ -106,6 +106,13 @@ }; }; + irda_regulator: irda-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpr3 3 GPIO_ACTIVE_HIGH>; + regulator-name = "irda_regulator"; + }; + sound { compatible = "samsung,tm2-audio"; audio-codec = <&wm5110>; @@ -298,6 +305,8 @@ status = "okay"; vddcore-supply = <&ldo6_reg>; vddio-supply = <&ldo7_reg>; + samsung,burst-clock-frequency = <512000000>; + samsung,esc-clock-frequency = <16000000>; samsung,pll-clock-frequency = <24000000>; pinctrl-names = "default"; pinctrl-0 = <&te_irq>; @@ -749,6 +758,19 @@ }; }; +&hsi2c_5 { + status = "okay"; + + stmfts: touchscreen@49 { + compatible = "st,stmfts"; + reg = <0x49>; + interrupt-parent = <&gpa1>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <&ldo30_reg>; + vdd-supply = <&ldo31_reg>; + }; +}; + &hsi2c_7 { status = "okay"; @@ -894,7 +916,7 @@ PIN(INPUT, gpa0-7, NONE, FAST_SR1); PIN(INPUT, gpa1-0, UP, FAST_SR1); - PIN(INPUT, gpa1-1, NONE, FAST_SR1); + PIN(INPUT, gpa1-1, UP, FAST_SR1); PIN(INPUT, gpa1-2, NONE, FAST_SR1); PIN(INPUT, gpa1-3, DOWN, FAST_SR1); PIN(INPUT, gpa1-4, DOWN, FAST_SR1); @@ -1074,7 +1096,6 @@ PIN(INPUT, gpg3-0, DOWN, FAST_SR1); PIN(INPUT, gpg3-1, DOWN, FAST_SR1); PIN(INPUT, gpg3-5, DOWN, FAST_SR1); - PIN(INPUT, gpg3-7, DOWN, FAST_SR1); }; }; @@ -1152,6 +1173,24 @@ }; }; +&spi_3 { + status = "okay"; + no-cs-readback; + + irled@0 { + compatible = "ir-spi-led"; + reg = <0x0>; + spi-max-frequency = <5000000>; + power-supply = <&irda_regulator>; + duty-cycle = <60>; + led-active-low; + + controller-data { + samsung,spi-feedback-delay = <0>; + }; + }; +}; + &timer { clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts index dea0a6f5bc18..3ff95277a8ec 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts @@ -52,6 +52,18 @@ assigned-clock-rates = <250000000>, <400000000>; }; +&dsi { + panel@0 { + compatible = "samsung,s6e3ha2"; + reg = <0>; + vdd3-supply = <&ldo27_reg>; + vci-supply = <&ldo28_reg>; + reset-gpios = <&gpg0 0 GPIO_ACTIVE_LOW>; + enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>; + te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>; + }; +}; + &hsi2c_9 { status = "okay"; @@ -76,3 +88,8 @@ regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; }; + +&stmfts { + touchscreen-size-x = <1439>; + touchscreen-size-y = <2559>; +}; diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts index 7891a31adc17..b73e1231a86f 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts @@ -52,6 +52,17 @@ assigned-clock-rates = <278000000>, <400000000>; }; +&dsi { + panel@0 { + compatible = "samsung,s6e3hf2"; + reg = <0>; + vdd3-supply = <&ldo27_reg>; + vci-supply = <&ldo28_reg>; + reset-gpios = <&gpg0 0 GPIO_ACTIVE_LOW>; + enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>; + }; +}; + &ldo31_reg { regulator-name = "TSP_VDD_1.8V_AP"; regulator-min-microvolt = <1800000>; @@ -63,3 +74,10 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; + +&stmfts { + touchscreen-size-x = <1599>; + touchscreen-size-y = <2559>; + touch-key-connected; + ledvdd-supply = <&ldo33_reg>; +}; diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi index 16072c1c3ed3..727f36abf3d4 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi @@ -119,43 +119,43 @@ compatible = "operating-points-v2"; opp-shared; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <900000>; }; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <925000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <950000>; }; - opp@700000000 { + opp-700000000 { opp-hz = /bits/ 64 <700000000>; opp-microvolt = <975000>; }; - opp@800000000 { + opp-800000000 { opp-hz = /bits/ 64 <800000000>; opp-microvolt = <1000000>; }; - opp@900000000 { + opp-900000000 { opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1050000>; }; - opp@1000000000 { + opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <1075000>; }; - opp@1100000000 { + opp-1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <1112500>; }; - opp@1200000000 { + opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1112500>; }; - opp@1300000000 { + opp-1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1150000>; }; @@ -165,63 +165,63 @@ compatible = "operating-points-v2"; opp-shared; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <900000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <900000>; }; - opp@700000000 { + opp-700000000 { opp-hz = /bits/ 64 <700000000>; opp-microvolt = <912500>; }; - opp@800000000 { + opp-800000000 { opp-hz = /bits/ 64 <800000000>; opp-microvolt = <912500>; }; - opp@900000000 { + opp-900000000 { opp-hz = /bits/ 64 <900000000>; opp-microvolt = <937500>; }; - opp@1000000000 { + opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <975000>; }; - opp@1100000000 { + opp-1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <1012500>; }; - opp@1200000000 { + opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1037500>; }; - opp@1300000000 { + opp-1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1062500>; }; - opp@1400000000 { + opp-1400000000 { opp-hz = /bits/ 64 <1400000000>; opp-microvolt = <1087500>; }; - opp@1500000000 { + opp-1500000000 { opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1125000>; }; - opp@1600000000 { + opp-1600000000 { opp-hz = /bits/ 64 <1600000000>; opp-microvolt = <1137500>; }; - opp@1700000000 { + opp-1700000000 { opp-hz = /bits/ 64 <1700000000>; opp-microvolt = <1175000>; }; - opp@1800000000 { + opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1212500>; }; - opp@1900000000 { + opp-1900000000 { opp-hz = /bits/ 64 <1900000000>; opp-microvolt = <1262500>; }; diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 39db645b268e..72c4b525726f 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -5,9 +5,13 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-qds.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-simu.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-qds.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-rdb.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts index a619f6496a4c..17fae8112e4d 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts @@ -113,3 +113,7 @@ &sai2 { status = "okay"; }; + +&sata { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts index 14a67f1709e7..e2a93d53d3d8 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts @@ -126,3 +126,7 @@ &sai2 { status = "okay"; }; + +&sata { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts index 62c5c7123a15..ed77f6b0937b 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts @@ -57,3 +57,7 @@ &i2c0 { status = "okay"; }; + +&sata { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index cffebb4b3df1..b497ac196ccc 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -42,7 +42,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/thermal/thermal.h> / { compatible = "fsl,ls1012a"; @@ -50,6 +51,15 @@ #address-cells = <2>; #size-cells = <2>; + aliases { + crypto = &crypto; + rtic_a = &rtic_a; + rtic_b = &rtic_b; + rtic_c = &rtic_c; + rtic_d = &rtic_d; + sec_mon = &sec_mon; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -113,6 +123,95 @@ big-endian; }; + crypto: crypto@1700000 { + compatible = "fsl,sec-v5.4", "fsl,sec-v5.0", + "fsl,sec-v4.0"; + fsl,sec-era = <8>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x1700000 0x100000>; + reg = <0x00 0x1700000 0x0 0x100000>; + interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; + + sec_jr0: jr@10000 { + compatible = "fsl,sec-v5.4-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x10000 0x10000>; + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + }; + + sec_jr1: jr@20000 { + compatible = "fsl,sec-v5.4-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x20000 0x10000>; + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + }; + + sec_jr2: jr@30000 { + compatible = "fsl,sec-v5.4-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x30000 0x10000>; + interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; + }; + + sec_jr3: jr@40000 { + compatible = "fsl,sec-v5.4-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x40000 0x10000>; + interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; + }; + + rtic@60000 { + compatible = "fsl,sec-v5.4-rtic", + "fsl,sec-v5.0-rtic", + "fsl,sec-v4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x60000 0x100 0x60e00 0x18>; + ranges = <0x0 0x60100 0x500>; + + rtic_a: rtic-a@0 { + compatible = "fsl,sec-v5.4-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x100>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,sec-v5.4-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x100>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,sec-v5.4-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x100>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,sec-v5.4-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x60 0x20 0x400 0x100>; + }; + }; + }; + + sec_mon: sec_mon@1e90000 { + compatible = "fsl,sec-v5.4-mon", "fsl,sec-v5.0-mon", + "fsl,sec-v4.0-mon"; + reg = <0x0 0x1e90000 0x0 0x10000>; + interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; + }; + dcfg: dcfg@1ee0000 { compatible = "fsl,ls1012a-dcfg", "syscon"; @@ -127,6 +226,82 @@ clocks = <&sysclk>; }; + tmu: tmu@1f00000 { + compatible = "fsl,qoriq-tmu"; + reg = <0x0 0x1f00000 0x0 0x10000>; + interrupts = <0 33 0x4>; + fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; + fsl,tmu-calibration = <0x00000000 0x00000026 + 0x00000001 0x0000002d + 0x00000002 0x00000032 + 0x00000003 0x00000039 + 0x00000004 0x0000003f + 0x00000005 0x00000046 + 0x00000006 0x0000004d + 0x00000007 0x00000054 + 0x00000008 0x0000005a + 0x00000009 0x00000061 + 0x0000000a 0x0000006a + 0x0000000b 0x00000071 + + 0x00010000 0x00000025 + 0x00010001 0x0000002c + 0x00010002 0x00000035 + 0x00010003 0x0000003d + 0x00010004 0x00000045 + 0x00010005 0x0000004e + 0x00010006 0x00000057 + 0x00010007 0x00000061 + 0x00010008 0x0000006b + 0x00010009 0x00000076 + + 0x00020000 0x00000029 + 0x00020001 0x00000033 + 0x00020002 0x0000003d + 0x00020003 0x00000049 + 0x00020004 0x00000056 + 0x00020005 0x00000061 + 0x00020006 0x0000006d + + 0x00030000 0x00000021 + 0x00030001 0x0000002a + 0x00030002 0x0000003c + 0x00030003 0x0000004e>; + big-endian; + #thermal-sensor-cells = <1>; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <5000>; + thermal-sensors = <&tmu 0>; + + trips { + cpu_alert: cpu-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_crit: cpu-crit { + temperature = <95000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert>; + cooling-device = + <&cpu0 THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + }; + i2c0: i2c@2180000 { compatible = "fsl,vf610-i2c"; #address-cells = <1>; @@ -238,9 +413,12 @@ sata: sata@3200000 { compatible = "fsl,ls1012a-ahci", "fsl,ls1043a-ahci"; - reg = <0x0 0x3200000 0x0 0x10000>; + reg = <0x0 0x3200000 0x0 0x10000>, + <0x0 0x20140520 0x0 0x4>; + reg-names = "ahci", "sata-ecc"; interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clockgen 4 0>; + dma-coherent; status = "disabled"; }; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index ec13a6ecb754..45cface08cbb 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -582,7 +582,9 @@ sata: sata@3200000 { compatible = "fsl,ls1043a-ahci"; - reg = <0x0 0x3200000 0x0 0x10000>; + reg = <0x0 0x3200000 0x0 0x10000>, + <0x0 0x20140520 0x0 0x4>; + reg-names = "ahci", "sata-ecc"; interrupts = <0 69 0x4>; clocks = <&clockgen 4 0>; dma-coherent; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 4a164b801882..f4b8b7edaf9d 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -587,7 +587,9 @@ sata: sata@3200000 { compatible = "fsl,ls1046a-ahci"; - reg = <0x0 0x3200000 0x0 0x10000>; + reg = <0x0 0x3200000 0x0 0x10000>, + <0x0 0x20140520 0x0 0x4>; + reg-names = "ahci", "sata-ecc"; interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clockgen 4 1>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts new file mode 100644 index 000000000000..8c3cae530f8f --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts @@ -0,0 +1,123 @@ +/* + * Device Tree file for NXP LS1088A QDS Board. + * + * Copyright 2017 NXP + * + * Harninder Rai <harninder.rai@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "fsl-ls1088a.dtsi" + +/ { + model = "LS1088A QDS Board"; + compatible = "fsl,ls1088a-qds", "fsl,ls1088a"; +}; + +&i2c0 { + status = "okay"; + + i2c-switch@77 { + compatible = "nxp,pca9547"; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; + + ina220@40 { + compatible = "ti,ina220"; + reg = <0x40>; + shunt-resistor = <1000>; + }; + + ina220@41 { + compatible = "ti,ina220"; + reg = <0x41>; + shunt-resistor = <1000>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3>; + + temp-sensor@4c { + compatible = "adi,adt7461a"; + reg = <0x4c>; + }; + + rtc@51 { + compatible = "nxp,pcf2129"; + reg = <0x51>; + /* IRQ10_B */ + interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>; + }; + + eeprom@56 { + compatible = "atmel,24c512"; + reg = <0x56>; + }; + + eeprom@57 { + compatible = "atmel,24c512"; + reg = <0x57>; + }; + }; + }; +}; + +&duart0 { + status = "okay"; +}; + +&duart1 { + status = "okay"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts new file mode 100644 index 000000000000..8a04fbb25cb4 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts @@ -0,0 +1,107 @@ +/* + * Device Tree file for NXP LS1088A RDB Board. + * + * Copyright 2017 NXP + * + * Harninder Rai <harninder.rai@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "fsl-ls1088a.dtsi" + +/ { + model = "L1088A RDB Board"; + compatible = "fsl,ls1088a-rdb", "fsl,ls1088a"; +}; + +&i2c0 { + status = "okay"; + + i2c-switch@77 { + compatible = "nxp,pca9547"; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; + + ina220@40 { + compatible = "ti,ina220"; + reg = <0x40>; + shunt-resistor = <1000>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3>; + + temp-sensor@4c { + compatible = "adi,adt7461a"; + reg = <0x4c>; + }; + + rtc@51 { + compatible = "nxp,pcf2129"; + reg = <0x51>; + /* IRQ10_B */ + interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + }; +}; + +&duart0 { + status = "okay"; +}; + +&duart1 { + status = "okay"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi new file mode 100644 index 000000000000..2946fd797121 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -0,0 +1,275 @@ +/* + * Device Tree Include file for NXP Layerscape-1088A family SoC. + * + * Copyright 2017 NXP + * + * Harninder Rai <harninder.rai@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include <dt-bindings/interrupt-controller/arm-gic.h> + +/ { + compatible = "fsl,ls1088a"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + /* We have 2 clusters having 4 Cortex-A53 cores each */ + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0>; + clocks = <&clockgen 1 0>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1>; + clocks = <&clockgen 1 0>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clocks = <&clockgen 1 0>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clocks = <&clockgen 1 0>; + }; + + cpu4: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x100>; + clocks = <&clockgen 1 1>; + }; + + cpu5: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x101>; + clocks = <&clockgen 1 1>; + }; + + cpu6: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x102>; + clocks = <&clockgen 1 1>; + }; + + cpu7: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x103>; + clocks = <&clockgen 1 1>; + }; + }; + + gic: interrupt-controller@6000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ + <0x0 0x06100000 0 0x100000>, /* GICR(RD_base+SGI_base)*/ + <0x0 0x0c0c0000 0 0x2000>, /* GICC */ + <0x0 0x0c0d0000 0 0x1000>, /* GICH */ + <0x0 0x0c0e0000 0 0x20000>; /* GICV */ + interrupts = <1 9 IRQ_TYPE_LEVEL_HIGH>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>,/* Physical Secure PPI */ + <1 14 IRQ_TYPE_LEVEL_LOW>,/* Physical Non-Secure PPI */ + <1 11 IRQ_TYPE_LEVEL_LOW>,/* Virtual PPI */ + <1 10 IRQ_TYPE_LEVEL_LOW>;/* Hypervisor PPI */ + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clockgen: clocking@1300000 { + compatible = "fsl,ls1088a-clockgen"; + reg = <0 0x1300000 0 0xa0000>; + #clock-cells = <2>; + clocks = <&sysclk>; + }; + + duart0: serial@21c0500 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x0 0x21c0500 0x0 0x100>; + clocks = <&clockgen 4 3>; + interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + duart1: serial@21c0600 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x0 0x21c0600 0x0 0x100>; + clocks = <&clockgen 4 3>; + interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + gpio0: gpio@2300000 { + compatible = "fsl,qoriq-gpio"; + reg = <0x0 0x2300000 0x0 0x10000>; + interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@2310000 { + compatible = "fsl,qoriq-gpio"; + reg = <0x0 0x2310000 0x0 0x10000>; + interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@2320000 { + compatible = "fsl,qoriq-gpio"; + reg = <0x0 0x2320000 0x0 0x10000>; + interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@2330000 { + compatible = "fsl,qoriq-gpio"; + reg = <0x0 0x2330000 0x0 0x10000>; + interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + ifc: ifc@2240000 { + compatible = "fsl,ifc", "simple-bus"; + reg = <0x0 0x2240000 0x0 0x20000>; + interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>; + little-endian; + #address-cells = <2>; + #size-cells = <1>; + + ranges = <0 0 0x5 0x80000000 0x08000000 + 2 0 0x5 0x30000000 0x00010000 + 3 0 0x5 0x20000000 0x00010000>; + status = "disabled"; + }; + + i2c0: i2c@2000000 { + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2000000 0x0 0x10000>; + interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clockgen 4 3>; + status = "disabled"; + }; + + i2c1: i2c@2010000 { + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2010000 0x0 0x10000>; + interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clockgen 4 3>; + status = "disabled"; + }; + + i2c2: i2c@2020000 { + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2020000 0x0 0x10000>; + interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clockgen 4 3>; + status = "disabled"; + }; + + i2c3: i2c@2030000 { + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2030000 0x0 0x10000>; + interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clockgen 4 3>; + status = "disabled"; + }; + + sata: sata@3200000 { + compatible = "fsl,ls1088a-ahci", "fsl,ls1043a-ahci"; + reg = <0x0 0x3200000 0x0 0x10000>; + interrupts = <0 133 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clockgen 4 3>; + status = "disabled"; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts index 8bc1f8f6fcfc..c1e76dfca48e 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts @@ -1,8 +1,9 @@ /* * Device Tree file for Freescale LS2080a QDS Board. * - * Copyright (C) 2015, Freescale Semiconductor + * Copyright (C) 2015-17, Freescale Semiconductor * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> * Bhupesh Sharma <bhupesh.sharma@freescale.com> * * This file is dual-licensed: you can use it either under the terms @@ -47,6 +48,7 @@ /dts-v1/; #include "fsl-ls2080a.dtsi" +#include "fsl-ls208xa-qds.dtsi" / { model = "Freescale Layerscape 2080a QDS Board"; @@ -61,154 +63,3 @@ stdout-path = "serial0:115200n8"; }; }; - -&esdhc { - status = "okay"; -}; - -&ifc { - status = "okay"; - #address-cells = <2>; - #size-cells = <1>; - ranges = <0x0 0x0 0x5 0x80000000 0x08000000 - 0x2 0x0 0x5 0x30000000 0x00010000 - 0x3 0x0 0x5 0x20000000 0x00010000>; - - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x8000000>; - bank-width = <2>; - device-width = <1>; - }; - - nand@2,0 { - compatible = "fsl,ifc-nand"; - reg = <0x2 0x0 0x10000>; - }; - - cpld@3,0 { - reg = <0x3 0x0 0x10000>; - compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; - }; -}; - -&i2c0 { - status = "okay"; - pca9547@77 { - compatible = "nxp,pca9547"; - reg = <0x77>; - #address-cells = <1>; - #size-cells = <0>; - i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x00>; - rtc@68 { - compatible = "dallas,ds3232"; - reg = <0x68>; - }; - }; - - i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x02>; - - ina220@40 { - compatible = "ti,ina220"; - reg = <0x40>; - shunt-resistor = <500>; - }; - - ina220@41 { - compatible = "ti,ina220"; - reg = <0x41>; - shunt-resistor = <1000>; - }; - }; - - i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x3>; - - adt7481@4c { - compatible = "adi,adt7461"; - reg = <0x4c>; - }; - }; - }; -}; - -&i2c1 { - status = "disabled"; -}; - -&i2c2 { - status = "disabled"; -}; - -&i2c3 { - status = "disabled"; -}; - -&dspi { - status = "okay"; - dflash0: n25q128a { - #address-cells = <1>; - #size-cells = <1>; - compatible = "st,m25p80"; - spi-max-frequency = <3000000>; - reg = <0>; - }; - dflash1: sst25wf040b { - #address-cells = <1>; - #size-cells = <1>; - compatible = "st,m25p80"; - spi-max-frequency = <3000000>; - reg = <1>; - }; - dflash2: en25s64 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "st,m25p80"; - spi-max-frequency = <3000000>; - reg = <2>; - }; -}; - -&qspi { - status = "okay"; - flash0: s25fl256s1@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "st,m25p80"; - spi-max-frequency = <20000000>; - reg = <0>; - }; - flash2: s25fl256s1@2 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "st,m25p80"; - spi-max-frequency = <20000000>; - reg = <0>; - }; -}; - -&sata0 { - status = "okay"; -}; - -&sata1 { - status = "okay"; -}; - -&usb0 { - status = "okay"; -}; - -&usb1 { - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts index 2ff46ca450b1..18ad19587311 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts @@ -1,8 +1,9 @@ /* * Device Tree file for Freescale LS2080a RDB Board. * - * Copyright (C) 2015, Freescale Semiconductor + * Copyright (C) 2016-17, Freescale Semiconductor * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> * Bhupesh Sharma <bhupesh.sharma@freescale.com> * * This file is dual-licensed: you can use it either under the terms @@ -47,6 +48,7 @@ /dts-v1/; #include "fsl-ls2080a.dtsi" +#include "fsl-ls208xa-rdb.dtsi" / { model = "Freescale Layerscape 2080a RDB Board"; @@ -61,109 +63,3 @@ stdout-path = "serial1:115200n8"; }; }; - -&esdhc { - status = "okay"; -}; - -&ifc { - status = "okay"; - #address-cells = <2>; - #size-cells = <1>; - ranges = <0x0 0x0 0x5 0x80000000 0x08000000 - 0x2 0x0 0x5 0x30000000 0x00010000 - 0x3 0x0 0x5 0x20000000 0x00010000>; - - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x8000000>; - bank-width = <2>; - device-width = <1>; - }; - - nand@2,0 { - compatible = "fsl,ifc-nand"; - reg = <0x2 0x0 0x10000>; - }; - - cpld@3,0 { - reg = <0x3 0x0 0x10000>; - compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; - }; - -}; - -&i2c0 { - status = "okay"; - pca9547@75 { - compatible = "nxp,pca9547"; - reg = <0x75>; - #address-cells = <1>; - #size-cells = <0>; - i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x01>; - rtc@68 { - compatible = "dallas,ds3232"; - reg = <0x68>; - }; - }; - - i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x3>; - - adt7481@4c { - compatible = "adi,adt7461"; - reg = <0x4c>; - }; - }; - }; -}; - -&i2c1 { - status = "disabled"; -}; - -&i2c2 { - status = "disabled"; -}; - -&i2c3 { - status = "disabled"; -}; - -&dspi { - status = "okay"; - dflash0: n25q512a { - #address-cells = <1>; - #size-cells = <1>; - compatible = "st,m25p80"; - spi-max-frequency = <3000000>; - reg = <0>; - }; -}; - -&qspi { - status = "disabled"; -}; - -&sata0 { - status = "okay"; -}; - -&sata1 { - status = "okay"; -}; - -&usb0 { - status = "okay"; -}; - -&usb1 { - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi index e5935f28848c..46a26c021421 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi @@ -1,8 +1,9 @@ /* * Device Tree Include file for Freescale Layerscape-2080A family SoC. * - * Copyright (C) 2014-2015, Freescale Semiconductor + * Copyright (C) 2014-2016, Freescale Semiconductor * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> * Bhupesh Sharma <bhupesh.sharma@freescale.com> * * This file is dual-licensed: you can use it either under the terms @@ -44,802 +45,122 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include <dt-bindings/thermal/thermal.h> +#include "fsl-ls208xa.dtsi" -/ { - compatible = "fsl,ls2080a"; - interrupt-parent = <&gic>; - #address-cells = <2>; - #size-cells = <2>; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - /* - * We expect the enable-method for cpu's to be "psci", but this - * is dependent on the SoC FW, which will fill this in. - * - * Currently supported enable-method is psci v0.2 - */ - - /* We have 4 clusters having 2 Cortex-A57 cores each */ - cpu0: cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x0>; - clocks = <&clockgen 1 0>; - next-level-cache = <&cluster0_l2>; - #cooling-cells = <2>; - }; - - cpu1: cpu@1 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x1>; - clocks = <&clockgen 1 0>; - next-level-cache = <&cluster0_l2>; - }; - - cpu2: cpu@100 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x100>; - clocks = <&clockgen 1 1>; - next-level-cache = <&cluster1_l2>; - #cooling-cells = <2>; - }; - - cpu3: cpu@101 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x101>; - clocks = <&clockgen 1 1>; - next-level-cache = <&cluster1_l2>; - }; - - cpu4: cpu@200 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x200>; - clocks = <&clockgen 1 2>; - next-level-cache = <&cluster2_l2>; - #cooling-cells = <2>; - }; - - cpu5: cpu@201 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x201>; - clocks = <&clockgen 1 2>; - next-level-cache = <&cluster2_l2>; - }; - - cpu6: cpu@300 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x300>; - clocks = <&clockgen 1 3>; - next-level-cache = <&cluster3_l2>; - #cooling-cells = <2>; - }; - - cpu7: cpu@301 { - device_type = "cpu"; - compatible = "arm,cortex-a57"; - reg = <0x301>; - clocks = <&clockgen 1 3>; - next-level-cache = <&cluster3_l2>; - }; - - cluster0_l2: l2-cache0 { - compatible = "cache"; - }; - - cluster1_l2: l2-cache1 { - compatible = "cache"; - }; - - cluster2_l2: l2-cache2 { - compatible = "cache"; - }; - - cluster3_l2: l2-cache3 { - compatible = "cache"; - }; +&cpu { + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0>; + clocks = <&clockgen 1 0>; + next-level-cache = <&cluster0_l2>; + #cooling-cells = <2>; }; - memory@80000000 { - device_type = "memory"; - reg = <0x00000000 0x80000000 0 0x80000000>; - /* DRAM space - 1, size : 2 GB DRAM */ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1>; + clocks = <&clockgen 1 0>; + next-level-cache = <&cluster0_l2>; }; - sysclk: sysclk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <100000000>; - clock-output-names = "sysclk"; + cpu2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x100>; + clocks = <&clockgen 1 1>; + next-level-cache = <&cluster1_l2>; + #cooling-cells = <2>; }; - gic: interrupt-controller@6000000 { - compatible = "arm,gic-v3"; - reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ - <0x0 0x06100000 0 0x100000>, /* GICR (RD_base + SGI_base) */ - <0x0 0x0c0c0000 0 0x2000>, /* GICC */ - <0x0 0x0c0d0000 0 0x1000>, /* GICH */ - <0x0 0x0c0e0000 0 0x20000>; /* GICV */ - #interrupt-cells = <3>; - #address-cells = <2>; - #size-cells = <2>; - ranges; - interrupt-controller; - interrupts = <1 9 0x4>; - - its: gic-its@6020000 { - compatible = "arm,gic-v3-its"; - msi-controller; - reg = <0x0 0x6020000 0 0x20000>; - }; + cpu3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x101>; + clocks = <&clockgen 1 1>; + next-level-cache = <&cluster1_l2>; }; - rstcr: syscon@1e60000 { - compatible = "fsl,ls2080a-rstcr", "syscon"; - reg = <0x0 0x1e60000 0x0 0x4>; + cpu4: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x200>; + clocks = <&clockgen 1 2>; + next-level-cache = <&cluster2_l2>; + #cooling-cells = <2>; }; - reboot { - compatible ="syscon-reboot"; - regmap = <&rstcr>; - offset = <0x0>; - mask = <0x2>; + cpu5: cpu@201 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x201>; + clocks = <&clockgen 1 2>; + next-level-cache = <&cluster2_l2>; }; - timer { - compatible = "arm,armv8-timer"; - interrupts = <1 13 4>, /* Physical Secure PPI, active-low */ - <1 14 4>, /* Physical Non-Secure PPI, active-low */ - <1 11 4>, /* Virtual PPI, active-low */ - <1 10 4>; /* Hypervisor PPI, active-low */ - fsl,erratum-a008585; + cpu6: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x300>; + clocks = <&clockgen 1 3>; + next-level-cache = <&cluster3_l2>; + #cooling-cells = <2>; }; - pmu { - compatible = "arm,armv8-pmuv3"; - interrupts = <1 7 0x8>; /* PMU PPI, Level low type */ + cpu7: cpu@301 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x301>; + clocks = <&clockgen 1 3>; + next-level-cache = <&cluster3_l2>; }; - soc { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - clockgen: clocking@1300000 { - compatible = "fsl,ls2080a-clockgen"; - reg = <0 0x1300000 0 0xa0000>; - #clock-cells = <2>; - clocks = <&sysclk>; - }; - - dcfg: dcfg@1e00000 { - compatible = "fsl,ls2080a-dcfg", "syscon"; - reg = <0x0 0x1e00000 0x0 0x10000>; - little-endian; - }; - - tmu: tmu@1f80000 { - compatible = "fsl,qoriq-tmu"; - reg = <0x0 0x1f80000 0x0 0x10000>; - interrupts = <0 23 0x4>; - fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; - fsl,tmu-calibration = <0x00000000 0x00000026 - 0x00000001 0x0000002d - 0x00000002 0x00000032 - 0x00000003 0x00000039 - 0x00000004 0x0000003f - 0x00000005 0x00000046 - 0x00000006 0x0000004d - 0x00000007 0x00000054 - 0x00000008 0x0000005a - 0x00000009 0x00000061 - 0x0000000a 0x0000006a - 0x0000000b 0x00000071 - - 0x00010000 0x00000025 - 0x00010001 0x0000002c - 0x00010002 0x00000035 - 0x00010003 0x0000003d - 0x00010004 0x00000045 - 0x00010005 0x0000004e - 0x00010006 0x00000057 - 0x00010007 0x00000061 - 0x00010008 0x0000006b - 0x00010009 0x00000076 - - 0x00020000 0x00000029 - 0x00020001 0x00000033 - 0x00020002 0x0000003d - 0x00020003 0x00000049 - 0x00020004 0x00000056 - 0x00020005 0x00000061 - 0x00020006 0x0000006d - - 0x00030000 0x00000021 - 0x00030001 0x0000002a - 0x00030002 0x0000003c - 0x00030003 0x0000004e>; - little-endian; - #thermal-sensor-cells = <1>; - }; - - thermal-zones { - cpu_thermal: cpu-thermal { - polling-delay-passive = <1000>; - polling-delay = <5000>; - - thermal-sensors = <&tmu 4>; - - trips { - cpu_alert: cpu-alert { - temperature = <75000>; - hysteresis = <2000>; - type = "passive"; - }; - cpu_crit: cpu-crit { - temperature = <85000>; - hysteresis = <2000>; - type = "critical"; - }; - }; - - cooling-maps { - map0 { - trip = <&cpu_alert>; - cooling-device = - <&cpu0 THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - map1 { - trip = <&cpu_alert>; - cooling-device = - <&cpu2 THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - map2 { - trip = <&cpu_alert>; - cooling-device = - <&cpu4 THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - map3 { - trip = <&cpu_alert>; - cooling-device = - <&cpu6 THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - }; - }; - }; - - serial0: serial@21c0500 { - compatible = "fsl,ns16550", "ns16550a"; - reg = <0x0 0x21c0500 0x0 0x100>; - clocks = <&clockgen 4 3>; - interrupts = <0 32 0x4>; /* Level high type */ - }; - - serial1: serial@21c0600 { - compatible = "fsl,ns16550", "ns16550a"; - reg = <0x0 0x21c0600 0x0 0x100>; - clocks = <&clockgen 4 3>; - interrupts = <0 32 0x4>; /* Level high type */ - }; - - cluster1_core0_watchdog: wdt@c000000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc000000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - cluster1_core1_watchdog: wdt@c010000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc010000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - cluster2_core0_watchdog: wdt@c100000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc100000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - cluster2_core1_watchdog: wdt@c110000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc110000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - cluster3_core0_watchdog: wdt@c200000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc200000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - cluster3_core1_watchdog: wdt@c210000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc210000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - cluster4_core0_watchdog: wdt@c300000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc300000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - cluster4_core1_watchdog: wdt@c310000 { - compatible = "arm,sp805-wdt", "arm,primecell"; - reg = <0x0 0xc310000 0x0 0x1000>; - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "apb_pclk", "wdog_clk"; - }; - - fsl_mc: fsl-mc@80c000000 { - compatible = "fsl,qoriq-mc"; - reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ - <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ - msi-parent = <&its>; - #address-cells = <3>; - #size-cells = <1>; - - /* - * Region type 0x0 - MC portals - * Region type 0x1 - QBMAN portals - */ - ranges = <0x0 0x0 0x0 0x8 0x0c000000 0x4000000 - 0x1 0x0 0x0 0x8 0x18000000 0x8000000>; - - /* - * Define the maximum number of MACs present on the SoC. - */ - dpmacs { - #address-cells = <1>; - #size-cells = <0>; - - dpmac1: dpmac@1 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x1>; - }; - - dpmac2: dpmac@2 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x2>; - }; - - dpmac3: dpmac@3 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x3>; - }; - - dpmac4: dpmac@4 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x4>; - }; - - dpmac5: dpmac@5 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x5>; - }; - - dpmac6: dpmac@6 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x6>; - }; - - dpmac7: dpmac@7 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x7>; - }; - - dpmac8: dpmac@8 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x8>; - }; - - dpmac9: dpmac@9 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x9>; - }; - - dpmac10: dpmac@a { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0xa>; - }; - - dpmac11: dpmac@b { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0xb>; - }; - - dpmac12: dpmac@c { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0xc>; - }; - - dpmac13: dpmac@d { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0xd>; - }; - - dpmac14: dpmac@e { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0xe>; - }; - - dpmac15: dpmac@f { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0xf>; - }; - - dpmac16: dpmac@10 { - compatible = "fsl,qoriq-mc-dpmac"; - reg = <0x10>; - }; - }; - }; - - smmu: iommu@5000000 { - compatible = "arm,mmu-500"; - reg = <0 0x5000000 0 0x800000>; - #global-interrupts = <12>; - interrupts = <0 13 4>, /* global secure fault */ - <0 14 4>, /* combined secure interrupt */ - <0 15 4>, /* global non-secure fault */ - <0 16 4>, /* combined non-secure interrupt */ - /* performance counter interrupts 0-7 */ - <0 211 4>, <0 212 4>, - <0 213 4>, <0 214 4>, - <0 215 4>, <0 216 4>, - <0 217 4>, <0 218 4>, - /* per context interrupt, 64 interrupts */ - <0 146 4>, <0 147 4>, - <0 148 4>, <0 149 4>, - <0 150 4>, <0 151 4>, - <0 152 4>, <0 153 4>, - <0 154 4>, <0 155 4>, - <0 156 4>, <0 157 4>, - <0 158 4>, <0 159 4>, - <0 160 4>, <0 161 4>, - <0 162 4>, <0 163 4>, - <0 164 4>, <0 165 4>, - <0 166 4>, <0 167 4>, - <0 168 4>, <0 169 4>, - <0 170 4>, <0 171 4>, - <0 172 4>, <0 173 4>, - <0 174 4>, <0 175 4>, - <0 176 4>, <0 177 4>, - <0 178 4>, <0 179 4>, - <0 180 4>, <0 181 4>, - <0 182 4>, <0 183 4>, - <0 184 4>, <0 185 4>, - <0 186 4>, <0 187 4>, - <0 188 4>, <0 189 4>, - <0 190 4>, <0 191 4>, - <0 192 4>, <0 193 4>, - <0 194 4>, <0 195 4>, - <0 196 4>, <0 197 4>, - <0 198 4>, <0 199 4>, - <0 200 4>, <0 201 4>, - <0 202 4>, <0 203 4>, - <0 204 4>, <0 205 4>, - <0 206 4>, <0 207 4>, - <0 208 4>, <0 209 4>; - mmu-masters = <&fsl_mc 0x300 0>; - }; - - dspi: dspi@2100000 { - status = "disabled"; - compatible = "fsl,ls2080a-dspi", "fsl,ls2085a-dspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0 0x2100000 0x0 0x10000>; - interrupts = <0 26 0x4>; /* Level high type */ - clocks = <&clockgen 4 3>; - clock-names = "dspi"; - spi-num-chipselects = <5>; - bus-num = <0>; - }; - - esdhc: esdhc@2140000 { - status = "disabled"; - compatible = "fsl,ls2080a-esdhc", "fsl,esdhc"; - reg = <0x0 0x2140000 0x0 0x10000>; - interrupts = <0 28 0x4>; /* Level high type */ - clock-frequency = <0>; /* Updated by bootloader */ - voltage-ranges = <1800 1800 3300 3300>; - sdhci,auto-cmd12; - little-endian; - bus-width = <4>; - }; - - gpio0: gpio@2300000 { - compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; - reg = <0x0 0x2300000 0x0 0x10000>; - interrupts = <0 36 0x4>; /* Level high type */ - gpio-controller; - little-endian; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio1: gpio@2310000 { - compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; - reg = <0x0 0x2310000 0x0 0x10000>; - interrupts = <0 36 0x4>; /* Level high type */ - gpio-controller; - little-endian; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio2: gpio@2320000 { - compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; - reg = <0x0 0x2320000 0x0 0x10000>; - interrupts = <0 37 0x4>; /* Level high type */ - gpio-controller; - little-endian; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio3: gpio@2330000 { - compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; - reg = <0x0 0x2330000 0x0 0x10000>; - interrupts = <0 37 0x4>; /* Level high type */ - gpio-controller; - little-endian; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - i2c0: i2c@2000000 { - status = "disabled"; - compatible = "fsl,vf610-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0 0x2000000 0x0 0x10000>; - interrupts = <0 34 0x4>; /* Level high type */ - clock-names = "i2c"; - clocks = <&clockgen 4 3>; - }; - - i2c1: i2c@2010000 { - status = "disabled"; - compatible = "fsl,vf610-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0 0x2010000 0x0 0x10000>; - interrupts = <0 34 0x4>; /* Level high type */ - clock-names = "i2c"; - clocks = <&clockgen 4 3>; - }; - - i2c2: i2c@2020000 { - status = "disabled"; - compatible = "fsl,vf610-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0 0x2020000 0x0 0x10000>; - interrupts = <0 35 0x4>; /* Level high type */ - clock-names = "i2c"; - clocks = <&clockgen 4 3>; - }; - - i2c3: i2c@2030000 { - status = "disabled"; - compatible = "fsl,vf610-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0 0x2030000 0x0 0x10000>; - interrupts = <0 35 0x4>; /* Level high type */ - clock-names = "i2c"; - clocks = <&clockgen 4 3>; - }; - - ifc: ifc@2240000 { - compatible = "fsl,ifc", "simple-bus"; - reg = <0x0 0x2240000 0x0 0x20000>; - interrupts = <0 21 0x4>; /* Level high type */ - little-endian; - #address-cells = <2>; - #size-cells = <1>; - - ranges = <0 0 0x5 0x80000000 0x08000000 - 2 0 0x5 0x30000000 0x00010000 - 3 0 0x5 0x20000000 0x00010000>; - }; - - qspi: quadspi@20c0000 { - status = "disabled"; - compatible = "fsl,ls2080a-qspi", "fsl,ls1021a-qspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0 0x20c0000 0x0 0x10000>, - <0x0 0x20000000 0x0 0x10000000>; - reg-names = "QuadSPI", "QuadSPI-memory"; - interrupts = <0 25 0x4>; /* Level high type */ - clocks = <&clockgen 4 3>, <&clockgen 4 3>; - clock-names = "qspi_en", "qspi"; - }; + cluster0_l2: l2-cache0 { + compatible = "cache"; + }; - pcie@3400000 { - compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", - "snps,dw-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x10 0x00000000 0x0 0x00002000>; /* configuration space */ - reg-names = "regs", "config"; - interrupts = <0 108 0x4>; /* Level high type */ - interrupt-names = "intr"; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - dma-coherent; - num-lanes = <4>; - bus-range = <0x0 0xff>; - ranges = <0x81000000 0x0 0x00000000 0x10 0x00010000 0x0 0x00010000 /* downstream I/O */ - 0x82000000 0x0 0x40000000 0x10 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ - msi-parent = <&its>; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0000 0 0 1 &gic 0 0 0 109 4>, - <0000 0 0 2 &gic 0 0 0 110 4>, - <0000 0 0 3 &gic 0 0 0 111 4>, - <0000 0 0 4 &gic 0 0 0 112 4>; - }; + cluster1_l2: l2-cache1 { + compatible = "cache"; + }; - pcie@3500000 { - compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", - "snps,dw-pcie"; - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x12 0x00000000 0x0 0x00002000>; /* configuration space */ - reg-names = "regs", "config"; - interrupts = <0 113 0x4>; /* Level high type */ - interrupt-names = "intr"; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - dma-coherent; - num-lanes = <4>; - bus-range = <0x0 0xff>; - ranges = <0x81000000 0x0 0x00000000 0x12 0x00010000 0x0 0x00010000 /* downstream I/O */ - 0x82000000 0x0 0x40000000 0x12 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ - msi-parent = <&its>; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0000 0 0 1 &gic 0 0 0 114 4>, - <0000 0 0 2 &gic 0 0 0 115 4>, - <0000 0 0 3 &gic 0 0 0 116 4>, - <0000 0 0 4 &gic 0 0 0 117 4>; - }; + cluster2_l2: l2-cache2 { + compatible = "cache"; + }; - pcie@3600000 { - compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", - "snps,dw-pcie"; - reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ - 0x14 0x00000000 0x0 0x00002000>; /* configuration space */ - reg-names = "regs", "config"; - interrupts = <0 118 0x4>; /* Level high type */ - interrupt-names = "intr"; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - dma-coherent; - num-lanes = <8>; - bus-range = <0x0 0xff>; - ranges = <0x81000000 0x0 0x00000000 0x14 0x00010000 0x0 0x00010000 /* downstream I/O */ - 0x82000000 0x0 0x40000000 0x14 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ - msi-parent = <&its>; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0000 0 0 1 &gic 0 0 0 119 4>, - <0000 0 0 2 &gic 0 0 0 120 4>, - <0000 0 0 3 &gic 0 0 0 121 4>, - <0000 0 0 4 &gic 0 0 0 122 4>; - }; + cluster3_l2: l2-cache3 { + compatible = "cache"; + }; +}; - pcie@3700000 { - compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", - "snps,dw-pcie"; - reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ - 0x16 0x00000000 0x0 0x00002000>; /* configuration space */ - reg-names = "regs", "config"; - interrupts = <0 123 0x4>; /* Level high type */ - interrupt-names = "intr"; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - dma-coherent; - num-lanes = <4>; - bus-range = <0x0 0xff>; - ranges = <0x81000000 0x0 0x00000000 0x16 0x00010000 0x0 0x00010000 /* downstream I/O */ - 0x82000000 0x0 0x40000000 0x16 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ - msi-parent = <&its>; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0000 0 0 1 &gic 0 0 0 124 4>, - <0000 0 0 2 &gic 0 0 0 125 4>, - <0000 0 0 3 &gic 0 0 0 126 4>, - <0000 0 0 4 &gic 0 0 0 127 4>; - }; +&pcie1 { + reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ + 0x10 0x00000000 0x0 0x00002000>; /* configuration space */ - sata0: sata@3200000 { - status = "disabled"; - compatible = "fsl,ls2080a-ahci"; - reg = <0x0 0x3200000 0x0 0x10000>; - interrupts = <0 133 0x4>; /* Level high type */ - clocks = <&clockgen 4 3>; - dma-coherent; - }; + ranges = <0x81000000 0x0 0x00000000 0x10 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x10 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +}; - sata1: sata@3210000 { - status = "disabled"; - compatible = "fsl,ls2080a-ahci"; - reg = <0x0 0x3210000 0x0 0x10000>; - interrupts = <0 136 0x4>; /* Level high type */ - clocks = <&clockgen 4 3>; - dma-coherent; - }; +&pcie2 { + reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ + 0x12 0x00000000 0x0 0x00002000>; /* configuration space */ - usb0: usb3@3100000 { - status = "disabled"; - compatible = "snps,dwc3"; - reg = <0x0 0x3100000 0x0 0x10000>; - interrupts = <0 80 0x4>; /* Level high type */ - dr_mode = "host"; - snps,quirk-frame-length-adjustment = <0x20>; - snps,dis_rxdet_inp3_quirk; - }; + ranges = <0x81000000 0x0 0x00000000 0x12 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x12 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +}; - usb1: usb3@3110000 { - status = "disabled"; - compatible = "snps,dwc3"; - reg = <0x0 0x3110000 0x0 0x10000>; - interrupts = <0 81 0x4>; /* Level high type */ - dr_mode = "host"; - snps,quirk-frame-length-adjustment = <0x20>; - snps,dis_rxdet_inp3_quirk; - }; +&pcie3 { + reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ + 0x14 0x00000000 0x0 0x00002000>; /* configuration space */ - ccn@4000000 { - compatible = "arm,ccn-504"; - reg = <0x0 0x04000000 0x0 0x01000000>; - interrupts = <0 12 4>; - }; - }; + ranges = <0x81000000 0x0 0x00000000 0x14 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x14 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +}; - ddr1: memory-controller@1080000 { - compatible = "fsl,qoriq-memory-controller"; - reg = <0x0 0x1080000 0x0 0x1000>; - interrupts = <0 17 0x4>; - little-endian; - }; +&pcie4 { + reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ + 0x16 0x00000000 0x0 0x00002000>; /* configuration space */ - ddr2: memory-controller@1090000 { - compatible = "fsl,qoriq-memory-controller"; - reg = <0x0 0x1090000 0x0 0x1000>; - interrupts = <0 18 0x4>; - little-endian; - }; + ranges = <0x81000000 0x0 0x00000000 0x16 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x16 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts new file mode 100644 index 000000000000..ebcd6ee4da0d --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts @@ -0,0 +1,64 @@ +/* + * Device Tree file for Freescale LS2088A QDS Board. + * + * Copyright (C) 2016-17, Freescale Semiconductor + * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "fsl-ls2088a.dtsi" +#include "fsl-ls208xa-qds.dtsi" + +/ { + model = "Freescale Layerscape 2088A QDS Board"; + compatible = "fsl,ls2088a-qds", "fsl,ls2088a"; + + aliases { + serial0 = &serial0; + serial1 = &serial1; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts new file mode 100644 index 000000000000..5992dc130faa --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts @@ -0,0 +1,64 @@ +/* + * Device Tree file for Freescale LS2088A RDB Board. + * + * Copyright (C) 2016-17, Freescale Semiconductor + * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +#include "fsl-ls2088a.dtsi" +#include "fsl-ls208xa-rdb.dtsi" + +/ { + model = "Freescale Layerscape 2088A RDB Board"; + compatible = "fsl,ls2088a-rdb", "fsl,ls2088a"; + + aliases { + serial0 = &serial0; + serial1 = &serial1; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi new file mode 100644 index 000000000000..33ce404cf7e4 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi @@ -0,0 +1,165 @@ +/* + * Device Tree Include file for Freescale Layerscape-2088A family SoC. + * + * Copyright (C) 2016-17, Freescale Semiconductor + * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "fsl-ls208xa.dtsi" + +&cpu { + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x0>; + clocks = <&clockgen 1 0>; + next-level-cache = <&cluster0_l2>; + #cooling-cells = <2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x1>; + clocks = <&clockgen 1 0>; + next-level-cache = <&cluster0_l2>; + }; + + cpu2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x100>; + clocks = <&clockgen 1 1>; + next-level-cache = <&cluster1_l2>; + #cooling-cells = <2>; + }; + + cpu3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x101>; + clocks = <&clockgen 1 1>; + next-level-cache = <&cluster1_l2>; + }; + + cpu4: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x200>; + clocks = <&clockgen 1 2>; + next-level-cache = <&cluster2_l2>; + #cooling-cells = <2>; + }; + + cpu5: cpu@201 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x201>; + clocks = <&clockgen 1 2>; + next-level-cache = <&cluster2_l2>; + }; + + cpu6: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x300>; + clocks = <&clockgen 1 3>; + next-level-cache = <&cluster3_l2>; + #cooling-cells = <2>; + }; + + cpu7: cpu@301 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x301>; + clocks = <&clockgen 1 3>; + next-level-cache = <&cluster3_l2>; + }; + + cluster0_l2: l2-cache0 { + compatible = "cache"; + }; + + cluster1_l2: l2-cache1 { + compatible = "cache"; + }; + + cluster2_l2: l2-cache2 { + compatible = "cache"; + }; + + cluster3_l2: l2-cache3 { + compatible = "cache"; + }; +}; + +&pcie1 { + reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ + 0x20 0x00000000 0x0 0x00002000>; /* configuration space */ + + ranges = <0x81000000 0x0 0x00000000 0x20 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x20 0x40000000 0x0 0x40000000>; +}; + +&pcie2 { + reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ + 0x28 0x00000000 0x0 0x00002000>; /* configuration space */ + + ranges = <0x81000000 0x0 0x00000000 0x28 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x28 0x40000000 0x0 0x40000000>; +}; + +&pcie3 { + reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ + 0x30 0x00000000 0x0 0x00002000>; /* configuration space */ + + ranges = <0x81000000 0x0 0x00000000 0x30 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x30 0x40000000 0x0 0x40000000>; +}; + +&pcie4 { + reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ + 0x38 0x00000000 0x0 0x00002000>; /* configuration space */ + + ranges = <0x81000000 0x0 0x00000000 0x38 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x38 0x40000000 0x0 0x40000000>; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi new file mode 100644 index 000000000000..8b6204845973 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi @@ -0,0 +1,196 @@ +/* + * Device Tree file for Freescale LS2080A QDS Board. + * + * Copyright (C) 2016-17, Freescale Semiconductor + * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +&esdhc { + status = "okay"; +}; + +&ifc { + status = "okay"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0x0 0x0 0x5 0x80000000 0x08000000 + 0x2 0x0 0x5 0x30000000 0x00010000 + 0x3 0x0 0x5 0x20000000 0x00010000>; + + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + }; + + nand@2,0 { + compatible = "fsl,ifc-nand"; + reg = <0x2 0x0 0x10000>; + }; + + cpld@3,0 { + reg = <0x3 0x0 0x10000>; + compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; + }; +}; + +&i2c0 { + status = "okay"; + pca9547@77 { + compatible = "nxp,pca9547"; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x00>; + rtc@68 { + compatible = "dallas,ds3232"; + reg = <0x68>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x02>; + + ina220@40 { + compatible = "ti,ina220"; + reg = <0x40>; + shunt-resistor = <500>; + }; + + ina220@41 { + compatible = "ti,ina220"; + reg = <0x41>; + shunt-resistor = <1000>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3>; + + adt7481@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; + }; + }; +}; + +&i2c1 { + status = "disabled"; +}; + +&i2c2 { + status = "disabled"; +}; + +&i2c3 { + status = "disabled"; +}; + +&dspi { + status = "okay"; + dflash0: n25q128a { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p80"; + spi-max-frequency = <3000000>; + reg = <0>; + }; + dflash1: sst25wf040b { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p80"; + spi-max-frequency = <3000000>; + reg = <1>; + }; + dflash2: en25s64 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p80"; + spi-max-frequency = <3000000>; + reg = <2>; + }; +}; + +&qspi { + status = "okay"; + flash0: s25fl256s1@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p80"; + spi-max-frequency = <20000000>; + reg = <0>; + }; + flash2: s25fl256s1@2 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p80"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&sata0 { + status = "okay"; +}; + +&sata1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi new file mode 100644 index 000000000000..3737587ffb33 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi @@ -0,0 +1,151 @@ +/* + * Device Tree file for Freescale LS2080A RDB Board. + * + * Copyright (C) 2016-17, Freescale Semiconductor + * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +&esdhc { + status = "okay"; +}; + +&ifc { + status = "okay"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0x0 0x0 0x5 0x80000000 0x08000000 + 0x2 0x0 0x5 0x30000000 0x00010000 + 0x3 0x0 0x5 0x20000000 0x00010000>; + + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + }; + + nand@2,0 { + compatible = "fsl,ifc-nand"; + reg = <0x2 0x0 0x10000>; + }; + + cpld@3,0 { + reg = <0x3 0x0 0x10000>; + compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; + }; + +}; + +&i2c0 { + status = "okay"; + pca9547@75 { + compatible = "nxp,pca9547"; + reg = <0x75>; + #address-cells = <1>; + #size-cells = <0>; + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x01>; + rtc@68 { + compatible = "dallas,ds3232"; + reg = <0x68>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3>; + + adt7481@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; + }; + }; +}; + +&i2c1 { + status = "disabled"; +}; + +&i2c2 { + status = "disabled"; +}; + +&i2c3 { + status = "disabled"; +}; + +&dspi { + status = "okay"; + dflash0: n25q512a { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p80"; + spi-max-frequency = <3000000>; + reg = <0>; + }; +}; + +&qspi { + status = "disabled"; +}; + +&sata0 { + status = "okay"; +}; + +&sata1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi new file mode 100644 index 000000000000..abb2fff7d162 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi @@ -0,0 +1,737 @@ +/* + * Device Tree Include file for Freescale Layerscape-2080A family SoC. + * + * Copyright (C) 2016-2017, Freescale Semiconductor + * + * Abhimanyu Saini <abhimanyu.saini@nxp.com> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPLv2 or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/thermal/thermal.h> + +/ { + compatible = "fsl,ls2080a"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpu: cpus { + #address-cells = <1>; + #size-cells = <0>; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00000000 0x80000000 0 0x80000000>; + /* DRAM space - 1, size : 2 GB DRAM */ + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + gic: interrupt-controller@6000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ + <0x0 0x06100000 0 0x100000>, /* GICR (RD_base + SGI_base) */ + <0x0 0x0c0c0000 0 0x2000>, /* GICC */ + <0x0 0x0c0d0000 0 0x1000>, /* GICH */ + <0x0 0x0c0e0000 0 0x20000>; /* GICV */ + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + interrupt-controller; + interrupts = <1 9 0x4>; + + its: gic-its@6020000 { + compatible = "arm,gic-v3-its"; + msi-controller; + reg = <0x0 0x6020000 0 0x20000>; + }; + }; + + rstcr: syscon@1e60000 { + compatible = "fsl,ls2080a-rstcr", "syscon"; + reg = <0x0 0x1e60000 0x0 0x4>; + }; + + reboot { + compatible ="syscon-reboot"; + regmap = <&rstcr>; + offset = <0x0>; + mask = <0x2>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 4>, /* Physical Secure PPI, active-low */ + <1 14 4>, /* Physical Non-Secure PPI, active-low */ + <1 11 4>, /* Virtual PPI, active-low */ + <1 10 4>; /* Hypervisor PPI, active-low */ + fsl,erratum-a008585; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <1 7 0x8>; /* PMU PPI, Level low type */ + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clockgen: clocking@1300000 { + compatible = "fsl,ls2080a-clockgen"; + reg = <0 0x1300000 0 0xa0000>; + #clock-cells = <2>; + clocks = <&sysclk>; + }; + + dcfg: dcfg@1e00000 { + compatible = "fsl,ls2080a-dcfg", "syscon"; + reg = <0x0 0x1e00000 0x0 0x10000>; + little-endian; + }; + + tmu: tmu@1f80000 { + compatible = "fsl,qoriq-tmu"; + reg = <0x0 0x1f80000 0x0 0x10000>; + interrupts = <0 23 0x4>; + fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; + fsl,tmu-calibration = <0x00000000 0x00000026 + 0x00000001 0x0000002d + 0x00000002 0x00000032 + 0x00000003 0x00000039 + 0x00000004 0x0000003f + 0x00000005 0x00000046 + 0x00000006 0x0000004d + 0x00000007 0x00000054 + 0x00000008 0x0000005a + 0x00000009 0x00000061 + 0x0000000a 0x0000006a + 0x0000000b 0x00000071 + + 0x00010000 0x00000025 + 0x00010001 0x0000002c + 0x00010002 0x00000035 + 0x00010003 0x0000003d + 0x00010004 0x00000045 + 0x00010005 0x0000004e + 0x00010006 0x00000057 + 0x00010007 0x00000061 + 0x00010008 0x0000006b + 0x00010009 0x00000076 + + 0x00020000 0x00000029 + 0x00020001 0x00000033 + 0x00020002 0x0000003d + 0x00020003 0x00000049 + 0x00020004 0x00000056 + 0x00020005 0x00000061 + 0x00020006 0x0000006d + + 0x00030000 0x00000021 + 0x00030001 0x0000002a + 0x00030002 0x0000003c + 0x00030003 0x0000004e>; + little-endian; + #thermal-sensor-cells = <1>; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <5000>; + + thermal-sensors = <&tmu 4>; + + trips { + cpu_alert: cpu-alert { + temperature = <75000>; + hysteresis = <2000>; + type = "passive"; + }; + cpu_crit: cpu-crit { + temperature = <85000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert>; + cooling-device = + <&cpu0 THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu_alert>; + cooling-device = + <&cpu2 THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + map2 { + trip = <&cpu_alert>; + cooling-device = + <&cpu4 THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + map3 { + trip = <&cpu_alert>; + cooling-device = + <&cpu6 THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + }; + + serial0: serial@21c0500 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x0 0x21c0500 0x0 0x100>; + clocks = <&clockgen 4 3>; + interrupts = <0 32 0x4>; /* Level high type */ + }; + + serial1: serial@21c0600 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x0 0x21c0600 0x0 0x100>; + clocks = <&clockgen 4 3>; + interrupts = <0 32 0x4>; /* Level high type */ + }; + + cluster1_core0_watchdog: wdt@c000000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc000000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + cluster1_core1_watchdog: wdt@c010000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc010000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + cluster2_core0_watchdog: wdt@c100000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc100000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + cluster2_core1_watchdog: wdt@c110000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc110000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + cluster3_core0_watchdog: wdt@c200000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc200000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + cluster3_core1_watchdog: wdt@c210000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc210000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + cluster4_core0_watchdog: wdt@c300000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc300000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + cluster4_core1_watchdog: wdt@c310000 { + compatible = "arm,sp805-wdt", "arm,primecell"; + reg = <0x0 0xc310000 0x0 0x1000>; + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "apb_pclk", "wdog_clk"; + }; + + fsl_mc: fsl-mc@80c000000 { + compatible = "fsl,qoriq-mc"; + reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ + <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ + msi-parent = <&its>; + #address-cells = <3>; + #size-cells = <1>; + + /* + * Region type 0x0 - MC portals + * Region type 0x1 - QBMAN portals + */ + ranges = <0x0 0x0 0x0 0x8 0x0c000000 0x4000000 + 0x1 0x0 0x0 0x8 0x18000000 0x8000000>; + + /* + * Define the maximum number of MACs present on the SoC. + */ + dpmacs { + #address-cells = <1>; + #size-cells = <0>; + + dpmac1: dpmac@1 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x1>; + }; + + dpmac2: dpmac@2 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x2>; + }; + + dpmac3: dpmac@3 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x3>; + }; + + dpmac4: dpmac@4 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x4>; + }; + + dpmac5: dpmac@5 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x5>; + }; + + dpmac6: dpmac@6 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x6>; + }; + + dpmac7: dpmac@7 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x7>; + }; + + dpmac8: dpmac@8 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x8>; + }; + + dpmac9: dpmac@9 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x9>; + }; + + dpmac10: dpmac@a { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0xa>; + }; + + dpmac11: dpmac@b { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0xb>; + }; + + dpmac12: dpmac@c { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0xc>; + }; + + dpmac13: dpmac@d { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0xd>; + }; + + dpmac14: dpmac@e { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0xe>; + }; + + dpmac15: dpmac@f { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0xf>; + }; + + dpmac16: dpmac@10 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <0x10>; + }; + }; + }; + + smmu: iommu@5000000 { + compatible = "arm,mmu-500"; + reg = <0 0x5000000 0 0x800000>; + #global-interrupts = <12>; + interrupts = <0 13 4>, /* global secure fault */ + <0 14 4>, /* combined secure interrupt */ + <0 15 4>, /* global non-secure fault */ + <0 16 4>, /* combined non-secure interrupt */ + /* performance counter interrupts 0-7 */ + <0 211 4>, <0 212 4>, + <0 213 4>, <0 214 4>, + <0 215 4>, <0 216 4>, + <0 217 4>, <0 218 4>, + /* per context interrupt, 64 interrupts */ + <0 146 4>, <0 147 4>, + <0 148 4>, <0 149 4>, + <0 150 4>, <0 151 4>, + <0 152 4>, <0 153 4>, + <0 154 4>, <0 155 4>, + <0 156 4>, <0 157 4>, + <0 158 4>, <0 159 4>, + <0 160 4>, <0 161 4>, + <0 162 4>, <0 163 4>, + <0 164 4>, <0 165 4>, + <0 166 4>, <0 167 4>, + <0 168 4>, <0 169 4>, + <0 170 4>, <0 171 4>, + <0 172 4>, <0 173 4>, + <0 174 4>, <0 175 4>, + <0 176 4>, <0 177 4>, + <0 178 4>, <0 179 4>, + <0 180 4>, <0 181 4>, + <0 182 4>, <0 183 4>, + <0 184 4>, <0 185 4>, + <0 186 4>, <0 187 4>, + <0 188 4>, <0 189 4>, + <0 190 4>, <0 191 4>, + <0 192 4>, <0 193 4>, + <0 194 4>, <0 195 4>, + <0 196 4>, <0 197 4>, + <0 198 4>, <0 199 4>, + <0 200 4>, <0 201 4>, + <0 202 4>, <0 203 4>, + <0 204 4>, <0 205 4>, + <0 206 4>, <0 207 4>, + <0 208 4>, <0 209 4>; + mmu-masters = <&fsl_mc 0x300 0>; + }; + + dspi: dspi@2100000 { + status = "disabled"; + compatible = "fsl,ls2080a-dspi", "fsl,ls2085a-dspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2100000 0x0 0x10000>; + interrupts = <0 26 0x4>; /* Level high type */ + clocks = <&clockgen 4 3>; + clock-names = "dspi"; + spi-num-chipselects = <5>; + bus-num = <0>; + }; + + esdhc: esdhc@2140000 { + status = "disabled"; + compatible = "fsl,ls2080a-esdhc", "fsl,esdhc"; + reg = <0x0 0x2140000 0x0 0x10000>; + interrupts = <0 28 0x4>; /* Level high type */ + clock-frequency = <0>; /* Updated by bootloader */ + voltage-ranges = <1800 1800 3300 3300>; + sdhci,auto-cmd12; + little-endian; + bus-width = <4>; + }; + + gpio0: gpio@2300000 { + compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; + reg = <0x0 0x2300000 0x0 0x10000>; + interrupts = <0 36 0x4>; /* Level high type */ + gpio-controller; + little-endian; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@2310000 { + compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; + reg = <0x0 0x2310000 0x0 0x10000>; + interrupts = <0 36 0x4>; /* Level high type */ + gpio-controller; + little-endian; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@2320000 { + compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; + reg = <0x0 0x2320000 0x0 0x10000>; + interrupts = <0 37 0x4>; /* Level high type */ + gpio-controller; + little-endian; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@2330000 { + compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; + reg = <0x0 0x2330000 0x0 0x10000>; + interrupts = <0 37 0x4>; /* Level high type */ + gpio-controller; + little-endian; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + i2c0: i2c@2000000 { + status = "disabled"; + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2000000 0x0 0x10000>; + interrupts = <0 34 0x4>; /* Level high type */ + clock-names = "i2c"; + clocks = <&clockgen 4 3>; + }; + + i2c1: i2c@2010000 { + status = "disabled"; + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2010000 0x0 0x10000>; + interrupts = <0 34 0x4>; /* Level high type */ + clock-names = "i2c"; + clocks = <&clockgen 4 3>; + }; + + i2c2: i2c@2020000 { + status = "disabled"; + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2020000 0x0 0x10000>; + interrupts = <0 35 0x4>; /* Level high type */ + clock-names = "i2c"; + clocks = <&clockgen 4 3>; + }; + + i2c3: i2c@2030000 { + status = "disabled"; + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2030000 0x0 0x10000>; + interrupts = <0 35 0x4>; /* Level high type */ + clock-names = "i2c"; + clocks = <&clockgen 4 3>; + }; + + ifc: ifc@2240000 { + compatible = "fsl,ifc", "simple-bus"; + reg = <0x0 0x2240000 0x0 0x20000>; + interrupts = <0 21 0x4>; /* Level high type */ + little-endian; + #address-cells = <2>; + #size-cells = <1>; + + ranges = <0 0 0x5 0x80000000 0x08000000 + 2 0 0x5 0x30000000 0x00010000 + 3 0 0x5 0x20000000 0x00010000>; + }; + + qspi: quadspi@20c0000 { + status = "disabled"; + compatible = "fsl,ls2080a-qspi", "fsl,ls1021a-qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x20c0000 0x0 0x10000>, + <0x0 0x20000000 0x0 0x10000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = <0 25 0x4>; /* Level high type */ + clocks = <&clockgen 4 3>, <&clockgen 4 3>; + clock-names = "qspi_en", "qspi"; + }; + + pcie1: pcie@3400000 { + compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", + "snps,dw-pcie"; + reg-names = "regs", "config"; + interrupts = <0 108 0x4>; /* Level high type */ + interrupt-names = "intr"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <4>; + bus-range = <0x0 0xff>; + msi-parent = <&its>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic 0 0 0 109 4>, + <0000 0 0 2 &gic 0 0 0 110 4>, + <0000 0 0 3 &gic 0 0 0 111 4>, + <0000 0 0 4 &gic 0 0 0 112 4>; + }; + + pcie2: pcie@3500000 { + compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", + "snps,dw-pcie"; + reg-names = "regs", "config"; + interrupts = <0 113 0x4>; /* Level high type */ + interrupt-names = "intr"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <4>; + bus-range = <0x0 0xff>; + msi-parent = <&its>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic 0 0 0 114 4>, + <0000 0 0 2 &gic 0 0 0 115 4>, + <0000 0 0 3 &gic 0 0 0 116 4>, + <0000 0 0 4 &gic 0 0 0 117 4>; + }; + + pcie3: pcie@3600000 { + compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", + "snps,dw-pcie"; + reg-names = "regs", "config"; + interrupts = <0 118 0x4>; /* Level high type */ + interrupt-names = "intr"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <8>; + bus-range = <0x0 0xff>; + msi-parent = <&its>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic 0 0 0 119 4>, + <0000 0 0 2 &gic 0 0 0 120 4>, + <0000 0 0 3 &gic 0 0 0 121 4>, + <0000 0 0 4 &gic 0 0 0 122 4>; + }; + + pcie4: pcie@3700000 { + compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", + "snps,dw-pcie"; + reg-names = "regs", "config"; + interrupts = <0 123 0x4>; /* Level high type */ + interrupt-names = "intr"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <4>; + bus-range = <0x0 0xff>; + msi-parent = <&its>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic 0 0 0 124 4>, + <0000 0 0 2 &gic 0 0 0 125 4>, + <0000 0 0 3 &gic 0 0 0 126 4>, + <0000 0 0 4 &gic 0 0 0 127 4>; + }; + + sata0: sata@3200000 { + status = "disabled"; + compatible = "fsl,ls2080a-ahci"; + reg = <0x0 0x3200000 0x0 0x10000>; + interrupts = <0 133 0x4>; /* Level high type */ + clocks = <&clockgen 4 3>; + dma-coherent; + }; + + sata1: sata@3210000 { + status = "disabled"; + compatible = "fsl,ls2080a-ahci"; + reg = <0x0 0x3210000 0x0 0x10000>; + interrupts = <0 136 0x4>; /* Level high type */ + clocks = <&clockgen 4 3>; + dma-coherent; + }; + + usb0: usb3@3100000 { + status = "disabled"; + compatible = "snps,dwc3"; + reg = <0x0 0x3100000 0x0 0x10000>; + interrupts = <0 80 0x4>; /* Level high type */ + dr_mode = "host"; + snps,quirk-frame-length-adjustment = <0x20>; + snps,dis_rxdet_inp3_quirk; + }; + + usb1: usb3@3110000 { + status = "disabled"; + compatible = "snps,dwc3"; + reg = <0x0 0x3110000 0x0 0x10000>; + interrupts = <0 81 0x4>; /* Level high type */ + dr_mode = "host"; + snps,quirk-frame-length-adjustment = <0x20>; + snps,dis_rxdet_inp3_quirk; + }; + + ccn@4000000 { + compatible = "arm,ccn-504"; + reg = <0x0 0x04000000 0x0 0x01000000>; + interrupts = <0 12 4>; + }; + }; + + ddr1: memory-controller@1080000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1080000 0x0 0x1000>; + interrupts = <0 17 0x4>; + little-endian; + }; + + ddr2: memory-controller@1090000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1090000 0x0 0x1000>; + interrupts = <0 18 0x4>; + little-endian; + }; +}; diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile index c3a6c1943038..8960ecafd37d 100644 --- a/arch/arm64/boot/dts/hisilicon/Makefile +++ b/arch/arm64/boot/dts/hisilicon/Makefile @@ -1,4 +1,5 @@ dtb-$(CONFIG_ARCH_HISI) += hi3660-hikey960.dtb +dtb-$(CONFIG_ARCH_HISI) += hi3798cv200-poplar.dtb dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb dtb-$(CONFIG_ARCH_HISI) += hip05-d02.dtb dtb-$(CONFIG_ARCH_HISI) += hip06-d03.dtb diff --git a/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts index ff37f0a0aa93..186251ffc6b2 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts +++ b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts @@ -8,6 +8,7 @@ /dts-v1/; #include "hi3660.dtsi" +#include "hikey960-pinctrl.dtsi" / { model = "HiKey960"; diff --git a/arch/arm64/boot/dts/hisilicon/hi3798cv200-poplar.dts b/arch/arm64/boot/dts/hisilicon/hi3798cv200-poplar.dts new file mode 100644 index 000000000000..b9142871d6fe --- /dev/null +++ b/arch/arm64/boot/dts/hisilicon/hi3798cv200-poplar.dts @@ -0,0 +1,162 @@ +/* + * DTS File for HiSilicon Poplar Development Board + * + * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. + * + * Released under the GPLv2 only. + * SPDX-License-Identifier: GPL-2.0 + */ + +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include "hi3798cv200.dtsi" + +/ { + model = "HiSilicon Poplar Development Board"; + compatible = "hisilicon,hi3798cv200-poplar", "hisilicon,hi3798cv200"; + + aliases { + serial0 = &uart0; + serial2 = &uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + leds { + compatible = "gpio-leds"; + + user-led0 { + label = "USER-LED0"; + gpios = <&gpio6 3 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + user-led1 { + label = "USER-LED1"; + gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + user-led2 { + label = "USER-LED2"; + gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; + linux,default-trigger = "none"; + default-state = "off"; + }; + + user-led3 { + label = "USER-LED3"; + gpios = <&gpio10 6 GPIO_ACTIVE_LOW>; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + }; +}; + +&gmac1 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + phy-handle = <ð_phy1>; + phy-mode = "rgmii"; + hisilicon,phy-reset-delays-us = <10000 10000 30000>; + + eth_phy1: phy@3 { + reg = <3>; + }; +}; + +&gpio1 { + status = "okay"; + gpio-line-names = "LS-GPIO-E", "", + "", "", + "", "LS-GPIO-F", + "", "LS-GPIO-J"; +}; + +&gpio2 { + status = "okay"; + gpio-line-names = "LS-GPIO-H", "LS-GPIO-I", + "LS-GPIO-L", "LS-GPIO-G", + "LS-GPIO-K", "", + "", ""; +}; + +&gpio3 { + status = "okay"; + gpio-line-names = "", "", + "", "", + "LS-GPIO-C", "", + "", "LS-GPIO-B"; +}; + +&gpio4 { + status = "okay"; + gpio-line-names = "", "", + "", "", + "", "LS-GPIO-D", + "", ""; +}; + +&gpio5 { + status = "okay"; + gpio-line-names = "", "USER-LED-1", + "USER-LED-2", "", + "", "LS-GPIO-A", + "", ""; +}; + +&gpio6 { + status = "okay"; + gpio-line-names = "", "", + "", "USER-LED-0", + "", "", + "", ""; +}; + +&gpio10 { + status = "okay"; + gpio-line-names = "", "", + "", "", + "", "", + "USER-LED-3", ""; +}; + +&i2c0 { + status = "okay"; + label = "LS-I2C0"; +}; + +&i2c2 { + status = "okay"; + label = "LS-I2C1"; +}; + +&ir { + status = "okay"; +}; + +&spi0 { + status = "okay"; + label = "LS-SPI0"; +}; + +&uart0 { + status = "okay"; +}; + +&uart2 { + status = "okay"; + label = "LS-UART0"; +}; +/* No optional LS-UART1 on Low Speed Expansion Connector. */ diff --git a/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi b/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi new file mode 100644 index 000000000000..75865f8a862a --- /dev/null +++ b/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi @@ -0,0 +1,411 @@ +/* + * DTS File for HiSilicon Hi3798cv200 SoC. + * + * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. + * + * Released under the GPLv2 only. + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <dt-bindings/clock/histb-clock.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/reset/ti-syscon.h> + +/ { + compatible = "hisilicon,hi3798cv200"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + cpu@1 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "psci"; + }; + + cpu@2 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "psci"; + }; + + cpu@3 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "psci"; + }; + }; + + gic: interrupt-controller@f1001000 { + compatible = "arm,gic-400"; + reg = <0x0 0xf1001000 0x0 0x1000>, /* GICD */ + <0x0 0xf1002000 0x0 0x100>; /* GICC */ + #address-cells = <0>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | + IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | + IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | + IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | + IRQ_TYPE_LEVEL_LOW)>; + }; + + soc: soc@f0000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0xf0000000 0x10000000>; + + crg: clock-reset-controller@8a22000 { + compatible = "hisilicon,hi3798cv200-crg", "syscon", "simple-mfd"; + reg = <0x8a22000 0x1000>; + #clock-cells = <1>; + #reset-cells = <2>; + + gmacphyrst: reset-controller { + compatible = "ti,syscon-reset"; + #reset-cells = <1>; + ti,reset-bits = + <0xcc 12 0xcc 12 0 0 (ASSERT_CLEAR | + DEASSERT_SET|STATUS_NONE)>, + <0xcc 13 0xcc 13 0 0 (ASSERT_CLEAR | + DEASSERT_SET|STATUS_NONE)>; + }; + }; + + sysctrl: system-controller@8000000 { + compatible = "hisilicon,hi3798cv200-sysctrl", "syscon"; + reg = <0x8000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <2>; + }; + + uart0: serial@8b00000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x8b00000 0x1000>; + interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sysctrl HISTB_UART0_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + uart2: serial@8b02000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x8b02000 0x1000>; + interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg HISTB_UART2_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + i2c0: i2c@8b10000 { + compatible = "hisilicon,hix5hd2-i2c"; + reg = <0x8b10000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <400000>; + clocks = <&crg HISTB_I2C0_CLK>; + status = "disabled"; + }; + + i2c1: i2c@8b11000 { + compatible = "hisilicon,hix5hd2-i2c"; + reg = <0x8b11000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <400000>; + clocks = <&crg HISTB_I2C1_CLK>; + status = "disabled"; + }; + + i2c2: i2c@8b12000 { + compatible = "hisilicon,hix5hd2-i2c"; + reg = <0x8b12000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <400000>; + clocks = <&crg HISTB_I2C2_CLK>; + status = "disabled"; + }; + + i2c3: i2c@8b13000 { + compatible = "hisilicon,hix5hd2-i2c"; + reg = <0x8b13000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <400000>; + clocks = <&crg HISTB_I2C3_CLK>; + status = "disabled"; + }; + + i2c4: i2c@8b14000 { + compatible = "hisilicon,hix5hd2-i2c"; + reg = <0x8b14000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <400000>; + clocks = <&crg HISTB_I2C4_CLK>; + status = "disabled"; + }; + + spi0: spi@8b1a000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x8b1a000 0x1000>; + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; + num-cs = <1>; + cs-gpios = <&gpio7 1 0>; + clocks = <&crg HISTB_SPI0_CLK>; + clock-names = "apb_pclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + emmc: mmc@9830000 { + compatible = "snps,dw-mshc"; + reg = <0x9830000 0x10000>; + interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg HISTB_MMC_CIU_CLK>, + <&crg HISTB_MMC_BIU_CLK>; + clock-names = "ciu", "biu"; + }; + + gpio0: gpio@8b20000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b20000 0x1000>; + interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio1: gpio@8b21000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b21000 0x1000>; + interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio2: gpio@8b22000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b22000 0x1000>; + interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio3: gpio@8b23000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b23000 0x1000>; + interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio4: gpio@8b24000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b24000 0x1000>; + interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio5: gpio@8004000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8004000 0x1000>; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio6: gpio@8b26000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b26000 0x1000>; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio7: gpio@8b27000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b27000 0x1000>; + interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio8: gpio@8b28000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b28000 0x1000>; + interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio9: gpio@8b29000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b29000 0x1000>; + interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio10: gpio@8b2a000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b2a000 0x1000>; + interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio11: gpio@8b2b000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b2b000 0x1000>; + interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio12: gpio@8b2c000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x8b2c000 0x1000>; + interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&crg HISTB_APB_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gmac0: ethernet@9840000 { + compatible = "hisilicon,hi3798cv200-gmac", "hisilicon,hisi-gmac-v2"; + reg = <0x9840000 0x1000>, + <0x984300c 0x4>; + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg HISTB_ETH0_MAC_CLK>, + <&crg HISTB_ETH0_MACIF_CLK>; + clock-names = "mac_core", "mac_ifc"; + resets = <&crg 0xcc 8>, + <&crg 0xcc 10>, + <&gmacphyrst 0>; + reset-names = "mac_core", "mac_ifc", "phy"; + status = "disabled"; + }; + + gmac1: ethernet@9841000 { + compatible = "hisilicon,hi3798cv200-gmac", "hisilicon,hisi-gmac-v2"; + reg = <0x9841000 0x1000>, + <0x9843010 0x4>; + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg HISTB_ETH1_MAC_CLK>, + <&crg HISTB_ETH1_MACIF_CLK>; + clock-names = "mac_core", "mac_ifc"; + resets = <&crg 0xcc 9>, + <&crg 0xcc 11>, + <&gmacphyrst 1>; + reset-names = "mac_core", "mac_ifc", "phy"; + status = "disabled"; + }; + + ir: ir@8001000 { + compatible = "hisilicon,hix5hd2-ir"; + reg = <0x8001000 0x1000>; + interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sysctrl HISTB_IR_CLK>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts index 9b4ba7169210..75bce2d0b1a8 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts +++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts @@ -411,6 +411,13 @@ }; }; }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; }; &uart2 { diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi index 470461ddd427..1e5129b19280 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi @@ -774,6 +774,7 @@ clocks = <&sys_ctrl 2>, <&sys_ctrl 1>; clock-names = "ciu", "biu"; resets = <&sys_ctrl PERIPH_RSTDIS0_MMC0>; + reset-names = "reset"; bus-width = <0x8>; vmmc-supply = <&ldo19>; pinctrl-names = "default"; @@ -797,6 +798,7 @@ clocks = <&sys_ctrl 4>, <&sys_ctrl 3>; clock-names = "ciu", "biu"; resets = <&sys_ctrl PERIPH_RSTDIS0_MMC1>; + reset-names = "reset"; vqmmc-supply = <&ldo7>; vmmc-supply = <&ldo10>; bus-width = <0x4>; @@ -815,6 +817,7 @@ clocks = <&sys_ctrl HI6220_MMC2_CIUCLK>, <&sys_ctrl HI6220_MMC2_CLK>; clock-names = "ciu", "biu"; resets = <&sys_ctrl PERIPH_RSTDIS0_MMC2>; + reset-names = "reset"; bus-width = <0x4>; broken-cd; pinctrl-names = "default", "idle"; diff --git a/arch/arm64/boot/dts/hisilicon/hikey960-pinctrl.dtsi b/arch/arm64/boot/dts/hisilicon/hikey960-pinctrl.dtsi new file mode 100644 index 000000000000..719c4bc937a4 --- /dev/null +++ b/arch/arm64/boot/dts/hisilicon/hikey960-pinctrl.dtsi @@ -0,0 +1,407 @@ +/* + * pinctrl dts fils for Hislicon HiKey960 development board + * + */ + +#include <dt-bindings/pinctrl/hisi.h> + +/ { + soc { + /* [IOMG_000, IOMG_123] */ + range: gpio-range { + #pinctrl-single,gpio-range-cells = <3>; + }; + + pmx0: pinmux@e896c000 { + compatible = "pinctrl-single"; + reg = <0x0 0xe896c000 0x0 0x1f0>; + #pinctrl-cells = <1>; + #gpio-range-cells = <0x3>; + pinctrl-single,register-width = <0x20>; + pinctrl-single,function-mask = <0x7>; + /* pin base, nr pins & gpio function */ + pinctrl-single,gpio-range = < + &range 0 7 0 + &range 8 116 0>; + + isp0_pmx_func: isp0_pmx_func { + pinctrl-single,pins = < + 0x058 MUX_M1 /* ISP_CLK0 */ + 0x064 MUX_M1 /* ISP_SCL0 */ + 0x068 MUX_M1 /* ISP_SDA0 */ + >; + }; + + isp1_pmx_func: isp1_pmx_func { + pinctrl-single,pins = < + 0x05c MUX_M1 /* ISP_CLK1 */ + 0x06c MUX_M1 /* ISP_SCL1 */ + 0x070 MUX_M1 /* ISP_SDA1 */ + >; + }; + + i2c3_pmx_func: i2c3_pmx_func { + pinctrl-single,pins = < + 0x02c MUX_M1 /* I2C3_SCL */ + 0x030 MUX_M1 /* I2C3_SDA */ + >; + }; + + i2c4_pmx_func: i2c4_pmx_func { + pinctrl-single,pins = < + 0x090 MUX_M1 /* I2C4_SCL */ + 0x094 MUX_M1 /* I2C4_SDA */ + >; + }; + + pcie_perstn_pmx_func: pcie_perstn_pmx_func { + pinctrl-single,pins = < + 0x15c MUX_M1 /* PCIE_PERST_N */ + >; + }; + + usbhub5734_pmx_func: usbhub5734_pmx_func { + pinctrl-single,pins = < + 0x11c MUX_M0 /* GPIO_073 */ + 0x120 MUX_M0 /* GPIO_074 */ + >; + }; + + spi1_pmx_func: spi1_pmx_func { + pinctrl-single,pins = < + 0x034 MUX_M1 /* SPI1_CLK */ + 0x038 MUX_M1 /* SPI1_DI */ + 0x03c MUX_M1 /* SPI1_DO */ + 0x040 MUX_M1 /* SPI1_CS_N */ + >; + }; + + uart0_pmx_func: uart0_pmx_func { + pinctrl-single,pins = < + 0x0cc MUX_M2 /* UART0_RXD */ + 0x0d0 MUX_M2 /* UART0_TXD */ + 0x0d4 MUX_M2 /* UART0_RXD_M */ + 0x0d8 MUX_M2 /* UART0_TXD_M */ + >; + }; + + uart1_pmx_func: uart1_pmx_func { + pinctrl-single,pins = < + 0x0b0 MUX_M2 /* UART1_CTS_N */ + 0x0b4 MUX_M2 /* UART1_RTS_N */ + 0x0a8 MUX_M2 /* UART1_RXD */ + 0x0ac MUX_M2 /* UART1_TXD */ + >; + }; + + uart2_pmx_func: uart2_pmx_func { + pinctrl-single,pins = < + 0x0bc MUX_M2 /* UART2_CTS_N */ + 0x0c0 MUX_M2 /* UART2_RTS_N */ + 0x0c8 MUX_M2 /* UART2_RXD */ + 0x0c4 MUX_M2 /* UART2_TXD */ + >; + }; + + uart3_pmx_func: uart3_pmx_func { + pinctrl-single,pins = < + 0x0dc MUX_M1 /* UART3_CTS_N */ + 0x0e0 MUX_M1 /* UART3_RTS_N */ + 0x0e4 MUX_M1 /* UART3_RXD */ + 0x0e8 MUX_M1 /* UART3_TXD */ + >; + }; + + uart4_pmx_func: uart4_pmx_func { + pinctrl-single,pins = < + 0x0ec MUX_M1 /* UART4_CTS_N */ + 0x0f0 MUX_M1 /* UART4_RTS_N */ + 0x0f4 MUX_M1 /* UART4_RXD */ + 0x0f8 MUX_M1 /* UART4_TXD */ + >; + }; + + uart5_pmx_func: uart5_pmx_func { + pinctrl-single,pins = < + 0x0c4 MUX_M3 /* UART5_CTS_N */ + 0x0c8 MUX_M3 /* UART5_RTS_N */ + 0x0bc MUX_M3 /* UART5_RXD */ + 0x0c0 MUX_M3 /* UART5_TXD */ + >; + }; + + uart6_pmx_func: uart6_pmx_func { + pinctrl-single,pins = < + 0x0cc MUX_M1 /* UART6_CTS_N */ + 0x0d0 MUX_M1 /* UART6_RTS_N */ + 0x0d4 MUX_M1 /* UART6_RXD */ + 0x0d8 MUX_M1 /* UART6_TXD */ + >; + }; + }; + + /* [IOMG_MMC0_000, IOMG_MMC0_005] */ + pmx1: pinmux@ff37e000 { + compatible = "pinctrl-single"; + reg = <0x0 0xff37e000 0x0 0x18>; + #gpio-range-cells = <0x3>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <0x20>; + pinctrl-single,function-mask = <0x7>; + /* pin base, nr pins & gpio function */ + pinctrl-single,gpio-range = <&range 0 6 0>; + + sd_pmx_func: sd_pmx_func { + pinctrl-single,pins = < + 0x000 MUX_M1 /* SD_CLK */ + 0x004 MUX_M1 /* SD_CMD */ + 0x008 MUX_M1 /* SD_DATA0 */ + 0x00c MUX_M1 /* SD_DATA1 */ + 0x010 MUX_M1 /* SD_DATA2 */ + 0x014 MUX_M1 /* SD_DATA3 */ + >; + }; + }; + + /* [IOMG_FIX_000, IOMG_FIX_011] */ + pmx2: pinmux@ff3b6000 { + compatible = "pinctrl-single"; + reg = <0x0 0xff3b6000 0x0 0x30>; + #pinctrl-cells = <1>; + #gpio-range-cells = <0x3>; + pinctrl-single,register-width = <0x20>; + pinctrl-single,function-mask = <0x7>; + /* pin base, nr pins & gpio function */ + pinctrl-single,gpio-range = <&range 0 12 0>; + + spi3_pmx_func: spi3_pmx_func { + pinctrl-single,pins = < + 0x008 MUX_M1 /* SPI3_CLK */ + 0x00c MUX_M1 /* SPI3_DI */ + 0x010 MUX_M1 /* SPI3_DO */ + 0x014 MUX_M1 /* SPI3_CS0_N */ + >; + }; + }; + + /* [IOMG_MMC1_000, IOMG_MMC1_005] */ + pmx3: pinmux@ff3fd000 { + compatible = "pinctrl-single"; + reg = <0x0 0xff3fd000 0x0 0x18>; + #pinctrl-cells = <1>; + #gpio-range-cells = <0x3>; + pinctrl-single,register-width = <0x20>; + pinctrl-single,function-mask = <0x7>; + /* pin base, nr pins & gpio function */ + pinctrl-single,gpio-range = <&range 0 6 0>; + + sdio_pmx_func: sdio_pmx_func { + pinctrl-single,pins = < + 0x000 MUX_M1 /* SDIO_CLK */ + 0x004 MUX_M1 /* SDIO_CMD */ + 0x008 MUX_M1 /* SDIO_DATA0 */ + 0x00c MUX_M1 /* SDIO_DATA1 */ + 0x010 MUX_M1 /* SDIO_DATA2 */ + 0x014 MUX_M1 /* SDIO_DATA3 */ + >; + }; + }; + + /* [IOMG_AO_000, IOMG_AO_041] */ + pmx4: pinmux@fff11000 { + compatible = "pinctrl-single"; + reg = <0x0 0xfff11000 0x0 0xa8>; + #pinctrl-cells = <1>; + #gpio-range-cells = <0x3>; + pinctrl-single,register-width = <0x20>; + pinctrl-single,function-mask = <0x7>; + /* pin base in node, nr pins & gpio function */ + pinctrl-single,gpio-range = <&range 0 42 0>; + + i2s2_pmx_func: i2s2_pmx_func { + pinctrl-single,pins = < + 0x044 MUX_M1 /* I2S2_DI */ + 0x048 MUX_M1 /* I2S2_DO */ + 0x04c MUX_M1 /* I2S2_XCLK */ + 0x050 MUX_M1 /* I2S2_XFS */ + >; + }; + + slimbus_pmx_func: slimbus_pmx_func { + pinctrl-single,pins = < + 0x02c MUX_M1 /* SLIMBUS_CLK */ + 0x030 MUX_M1 /* SLIMBUS_DATA */ + >; + }; + + i2c0_pmx_func: i2c0_pmx_func { + pinctrl-single,pins = < + 0x014 MUX_M1 /* I2C0_SCL */ + 0x018 MUX_M1 /* I2C0_SDA */ + >; + }; + + i2c1_pmx_func: i2c1_pmx_func { + pinctrl-single,pins = < + 0x01c MUX_M1 /* I2C1_SCL */ + 0x020 MUX_M1 /* I2C1_SDA */ + >; + }; + + i2c2_pmx_func: i2c2_pmx_func { + pinctrl-single,pins = < + 0x024 MUX_M1 /* I2C2_SCL */ + 0x028 MUX_M1 /* I2C2_SDA */ + >; + }; + + i2c7_pmx_func: i2c7_pmx_func { + pinctrl-single,pins = < + 0x024 MUX_M3 /* I2C7_SCL */ + 0x028 MUX_M3 /* I2C7_SDA */ + >; + }; + + spi2_pmx_func: spi2_pmx_func { + pinctrl-single,pins = < + 0x08c MUX_M1 /* SPI2_CLK */ + 0x090 MUX_M1 /* SPI2_DI */ + 0x094 MUX_M1 /* SPI2_DO */ + 0x098 MUX_M1 /* SPI2_CS0_N */ + >; + }; + + spi4_pmx_func: spi4_pmx_func { + pinctrl-single,pins = < + 0x08c MUX_M4 /* SPI4_CLK */ + 0x090 MUX_M4 /* SPI4_DI */ + 0x094 MUX_M4 /* SPI4_DO */ + 0x098 MUX_M4 /* SPI4_CS0_N */ + >; + }; + + i2s0_pmx_func: i2s0_pmx_func { + pinctrl-single,pins = < + 0x034 MUX_M1 /* I2S0_DI */ + 0x038 MUX_M1 /* I2S0_DO */ + 0x03c MUX_M1 /* I2S0_XCLK */ + 0x040 MUX_M1 /* I2S0_XFS */ + >; + }; + }; + + pmx5: pinmux@ff3fd800 { + compatible = "pinconf-single"; + reg = <0x0 0xff3fd800 0x0 0x18>; + #pinctrl-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + pinctrl-single,register-width = <32>; + + sdio_clk_cfg_func: sdio_clk_cfg_func { + pinctrl-single,pins = < + 0x000 0x0 /* SDIO_CLK */ + >; + pinctrl-single,bias-pulldown = < + PULL_DIS + PULL_DOWN + PULL_DIS + PULL_DOWN + >; + pinctrl-single,bias-pullup = < + PULL_DIS + PULL_UP + PULL_DIS + PULL_UP + >; + pinctrl-single,drive-strength = < + DRIVE6_32MA + DRIVE6_MASK + >; + }; + + sdio_cfg_func: sdio_cfg_func { + pinctrl-single,pins = < + 0x004 0x0 /* SDIO_CMD */ + 0x008 0x0 /* SDIO_DATA0 */ + 0x00c 0x0 /* SDIO_DATA1 */ + 0x010 0x0 /* SDIO_DATA2 */ + 0x014 0x0 /* SDIO_DATA3 */ + >; + pinctrl-single,bias-pulldown = < + PULL_DIS + PULL_DOWN + PULL_DIS + PULL_DOWN + >; + pinctrl-single,bias-pullup = < + PULL_UP + PULL_UP + PULL_DIS + PULL_UP + >; + pinctrl-single,drive-strength = < + DRIVE6_19MA + DRIVE6_MASK + >; + }; + }; + + pmx6: pinmux@ff37e800 { + compatible = "pinconf-single"; + reg = <0x0 0xff37e800 0x0 0x18>; + #pinctrl-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + pinctrl-single,register-width = <32>; + + sd_clk_cfg_func: sd_clk_cfg_func { + pinctrl-single,pins = < + 0x000 0x0 /* SD_CLK */ + >; + pinctrl-single,bias-pulldown = < + PULL_DIS + PULL_DOWN + PULL_DIS + PULL_DOWN + >; + pinctrl-single,bias-pullup = < + PULL_DIS + PULL_UP + PULL_DIS + PULL_UP + >; + pinctrl-single,drive-strength = < + DRIVE6_32MA + DRIVE6_MASK + >; + }; + + sd_cfg_func: sd_cfg_func { + pinctrl-single,pins = < + 0x004 0x0 /* SD_CMD */ + 0x008 0x0 /* SD_DATA0 */ + 0x00c 0x0 /* SD_DATA1 */ + 0x010 0x0 /* SD_DATA2 */ + 0x014 0x0 /* SD_DATA3 */ + >; + pinctrl-single,bias-pulldown = < + PULL_DIS + PULL_DOWN + PULL_DIS + PULL_DOWN + >; + pinctrl-single,bias-pullup = < + PULL_UP + PULL_UP + PULL_DIS + PULL_UP + >; + pinctrl-single,drive-strength = < + DRIVE6_19MA + DRIVE6_MASK + >; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/hisilicon/hip07-d05.dts b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts index e05844230583..f5d7f0889b41 100644 --- a/arch/arm64/boot/dts/hisilicon/hip07-d05.dts +++ b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts @@ -64,3 +64,23 @@ &usb_ehci { status = "ok"; }; + +ð0 { + status = "ok"; +}; + +ð1 { + status = "ok"; +}; + +ð2 { + status = "ok"; +}; + +ð3 { + status = "ok"; +}; + +&sas1 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/hisilicon/hip07.dtsi b/arch/arm64/boot/dts/hisilicon/hip07.dtsi index 5144eb1c179d..283d7b532e16 100644 --- a/arch/arm64/boot/dts/hisilicon/hip07.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hip07.dtsi @@ -1014,6 +1014,34 @@ compatible = "hisilicon,mbigen-v2"; reg = <0x0 0xa0080000 0x0 0x10000>; + mbigen_pcie2_a: intc_pcie2_a { + msi-parent = <&p0_its_dsa_a 0x40087>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <10>; + }; + + mbigen_sas1: intc_sas1 { + msi-parent = <&p0_its_dsa_a 0x40000>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <128>; + }; + + mbigen_sas2: intc_sas2 { + msi-parent = <&p0_its_dsa_a 0x40040>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <128>; + }; + + mbigen_smmu_pcie: intc_smmu_pcie { + msi-parent = <&p0_its_dsa_a 0x40b0c>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <3>; + }; + mbigen_usb: intc_usb { msi-parent = <&p0_its_dsa_a 0x40080>; interrupt-controller; @@ -1022,6 +1050,39 @@ }; }; + p0_mbigen_dsa_a: interrupt-controller@c0080000 { + compatible = "hisilicon,mbigen-v2"; + reg = <0x0 0xc0080000 0x0 0x10000>; + + mbigen_dsaf0: intc_dsaf0 { + msi-parent = <&p0_its_dsa_a 0x40800>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <409>; + }; + + mbigen_dsa_roce: intc-roce { + msi-parent = <&p0_its_dsa_a 0x40B1E>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <34>; + }; + + mbigen_sas0: intc-sas0 { + msi-parent = <&p0_its_dsa_a 0x40900>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <128>; + }; + + mbigen_smmu_dsa: intc_smmu_dsa { + msi-parent = <&p0_its_dsa_a 0x40b20>; + interrupt-controller; + #interrupt-cells = <2>; + num-pins = <3>; + }; + }; + soc { compatible = "simple-bus"; #address-cells = <2>; @@ -1055,5 +1116,423 @@ dma-coherent; status = "disabled"; }; + + peri_c_subctrl: sub_ctrl_c@60000000 { + compatible = "hisilicon,peri-subctrl","syscon"; + reg = <0 0x60000000 0x0 0x10000>; + }; + + dsa_subctrl: dsa_subctrl@c0000000 { + compatible = "hisilicon,dsa-subctrl", "syscon"; + reg = <0x0 0xc0000000 0x0 0x10000>; + }; + + pcie_subctl: pcie_subctl@a0000000 { + compatible = "hisilicon,pcie-sas-subctrl", "syscon"; + reg = <0x0 0xa0000000 0x0 0x10000>; + }; + + serdes_ctrl: sds_ctrl@c2200000 { + compatible = "syscon"; + reg = <0 0xc2200000 0x0 0x80000>; + }; + + mdio@603c0000 { + compatible = "hisilicon,hns-mdio"; + reg = <0x0 0x603c0000 0x0 0x1000>; + subctrl-vbase = <&peri_c_subctrl 0x338 0xa38 + 0x531c 0x5a1c>; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; + + dsaf0: dsa@c7000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "hisilicon,hns-dsaf-v2"; + mode = "6port-16rss"; + reg = <0x0 0xc5000000 0x0 0x890000 + 0x0 0xc7000000 0x0 0x600000>; + reg-names = "ppe-base", "dsaf-base"; + interrupt-parent = <&mbigen_dsaf0>; + subctrl-syscon = <&dsa_subctrl>; + reset-field-offset = <0>; + interrupts = + <576 1>, <577 1>, <578 1>, <579 1>, <580 1>, + <581 1>, <582 1>, <583 1>, <584 1>, <585 1>, + <586 1>, <587 1>, <588 1>, <589 1>, <590 1>, + <591 1>, <592 1>, <593 1>, <594 1>, <595 1>, + <596 1>, <597 1>, <598 1>, <599 1>, <600 1>, + <960 1>, <961 1>, <962 1>, <963 1>, <964 1>, + <965 1>, <966 1>, <967 1>, <968 1>, <969 1>, + <970 1>, <971 1>, <972 1>, <973 1>, <974 1>, + <975 1>, <976 1>, <977 1>, <978 1>, <979 1>, + <980 1>, <981 1>, <982 1>, <983 1>, <984 1>, + <985 1>, <986 1>, <987 1>, <988 1>, <989 1>, + <990 1>, <991 1>, <992 1>, <993 1>, <994 1>, + <995 1>, <996 1>, <997 1>, <998 1>, <999 1>, + <1000 1>, <1001 1>, <1002 1>, <1003 1>, <1004 1>, + <1005 1>, <1006 1>, <1007 1>, <1008 1>, <1009 1>, + <1010 1>, <1011 1>, <1012 1>, <1013 1>, <1014 1>, + <1015 1>, <1016 1>, <1017 1>, <1018 1>, <1019 1>, + <1020 1>, <1021 1>, <1022 1>, <1023 1>, <1024 1>, + <1025 1>, <1026 1>, <1027 1>, <1028 1>, <1029 1>, + <1030 1>, <1031 1>, <1032 1>, <1033 1>, <1034 1>, + <1035 1>, <1036 1>, <1037 1>, <1038 1>, <1039 1>, + <1040 1>, <1041 1>, <1042 1>, <1043 1>, <1044 1>, + <1045 1>, <1046 1>, <1047 1>, <1048 1>, <1049 1>, + <1050 1>, <1051 1>, <1052 1>, <1053 1>, <1054 1>, + <1055 1>, <1056 1>, <1057 1>, <1058 1>, <1059 1>, + <1060 1>, <1061 1>, <1062 1>, <1063 1>, <1064 1>, + <1065 1>, <1066 1>, <1067 1>, <1068 1>, <1069 1>, + <1070 1>, <1071 1>, <1072 1>, <1073 1>, <1074 1>, + <1075 1>, <1076 1>, <1077 1>, <1078 1>, <1079 1>, + <1080 1>, <1081 1>, <1082 1>, <1083 1>, <1084 1>, + <1085 1>, <1086 1>, <1087 1>, <1088 1>, <1089 1>, + <1090 1>, <1091 1>, <1092 1>, <1093 1>, <1094 1>, + <1095 1>, <1096 1>, <1097 1>, <1098 1>, <1099 1>, + <1100 1>, <1101 1>, <1102 1>, <1103 1>, <1104 1>, + <1105 1>, <1106 1>, <1107 1>, <1108 1>, <1109 1>, + <1110 1>, <1111 1>, <1112 1>, <1113 1>, <1114 1>, + <1115 1>, <1116 1>, <1117 1>, <1118 1>, <1119 1>, + <1120 1>, <1121 1>, <1122 1>, <1123 1>, <1124 1>, + <1125 1>, <1126 1>, <1127 1>, <1128 1>, <1129 1>, + <1130 1>, <1131 1>, <1132 1>, <1133 1>, <1134 1>, + <1135 1>, <1136 1>, <1137 1>, <1138 1>, <1139 1>, + <1140 1>, <1141 1>, <1142 1>, <1143 1>, <1144 1>, + <1145 1>, <1146 1>, <1147 1>, <1148 1>, <1149 1>, + <1150 1>, <1151 1>, <1152 1>, <1153 1>, <1154 1>, + <1155 1>, <1156 1>, <1157 1>, <1158 1>, <1159 1>, + <1160 1>, <1161 1>, <1162 1>, <1163 1>, <1164 1>, + <1165 1>, <1166 1>, <1167 1>, <1168 1>, <1169 1>, + <1170 1>, <1171 1>, <1172 1>, <1173 1>, <1174 1>, + <1175 1>, <1176 1>, <1177 1>, <1178 1>, <1179 1>, + <1180 1>, <1181 1>, <1182 1>, <1183 1>, <1184 1>, + <1185 1>, <1186 1>, <1187 1>, <1188 1>, <1189 1>, + <1190 1>, <1191 1>, <1192 1>, <1193 1>, <1194 1>, + <1195 1>, <1196 1>, <1197 1>, <1198 1>, <1199 1>, + <1200 1>, <1201 1>, <1202 1>, <1203 1>, <1204 1>, + <1205 1>, <1206 1>, <1207 1>, <1208 1>, <1209 1>, + <1210 1>, <1211 1>, <1212 1>, <1213 1>, <1214 1>, + <1215 1>, <1216 1>, <1217 1>, <1218 1>, <1219 1>, + <1220 1>, <1221 1>, <1222 1>, <1223 1>, <1224 1>, + <1225 1>, <1226 1>, <1227 1>, <1228 1>, <1229 1>, + <1230 1>, <1231 1>, <1232 1>, <1233 1>, <1234 1>, + <1235 1>, <1236 1>, <1237 1>, <1238 1>, <1239 1>, + <1240 1>, <1241 1>, <1242 1>, <1243 1>, <1244 1>, + <1245 1>, <1246 1>, <1247 1>, <1248 1>, <1249 1>, + <1250 1>, <1251 1>, <1252 1>, <1253 1>, <1254 1>, + <1255 1>, <1256 1>, <1257 1>, <1258 1>, <1259 1>, + <1260 1>, <1261 1>, <1262 1>, <1263 1>, <1264 1>, + <1265 1>, <1266 1>, <1267 1>, <1268 1>, <1269 1>, + <1270 1>, <1271 1>, <1272 1>, <1273 1>, <1274 1>, + <1275 1>, <1276 1>, <1277 1>, <1278 1>, <1279 1>, + <1280 1>, <1281 1>, <1282 1>, <1283 1>, <1284 1>, + <1285 1>, <1286 1>, <1287 1>, <1288 1>, <1289 1>, + <1290 1>, <1291 1>, <1292 1>, <1293 1>, <1294 1>, + <1295 1>, <1296 1>, <1297 1>, <1298 1>, <1299 1>, + <1300 1>, <1301 1>, <1302 1>, <1303 1>, <1304 1>, + <1305 1>, <1306 1>, <1307 1>, <1308 1>, <1309 1>, + <1310 1>, <1311 1>, <1312 1>, <1313 1>, <1314 1>, + <1315 1>, <1316 1>, <1317 1>, <1318 1>, <1319 1>, + <1320 1>, <1321 1>, <1322 1>, <1323 1>, <1324 1>, + <1325 1>, <1326 1>, <1327 1>, <1328 1>, <1329 1>, + <1330 1>, <1331 1>, <1332 1>, <1333 1>, <1334 1>, + <1335 1>, <1336 1>, <1337 1>, <1338 1>, <1339 1>, + <1340 1>, <1341 1>, <1342 1>, <1343 1>; + + desc-num = <0x400>; + buf-size = <0x1000>; + dma-coherent; + + port@0 { + reg = <0>; + serdes-syscon = <&serdes_ctrl>; + port-rst-offset = <0>; + port-mode-offset = <0>; + mc-mac-mask = [ff f0 00 00 00 00]; + media-type = "fiber"; + }; + + port@1 { + reg = <1>; + serdes-syscon= <&serdes_ctrl>; + port-rst-offset = <1>; + port-mode-offset = <1>; + mc-mac-mask = [ff f0 00 00 00 00]; + media-type = "fiber"; + }; + + port@4 { + reg = <4>; + phy-handle = <&phy0>; + serdes-syscon= <&serdes_ctrl>; + port-rst-offset = <4>; + port-mode-offset = <2>; + mc-mac-mask = [ff f0 00 00 00 00]; + media-type = "copper"; + }; + + port@5 { + reg = <5>; + phy-handle = <&phy1>; + serdes-syscon= <&serdes_ctrl>; + port-rst-offset = <5>; + port-mode-offset = <3>; + mc-mac-mask = [ff f0 00 00 00 00]; + media-type = "copper"; + }; + }; + + eth0: ethernet@4{ + compatible = "hisilicon,hns-nic-v2"; + ae-handle = <&dsaf0>; + port-idx-in-ae = <4>; + local-mac-address = [00 00 00 00 00 00]; + status = "disabled"; + dma-coherent; + }; + + eth1: ethernet@5{ + compatible = "hisilicon,hns-nic-v2"; + ae-handle = <&dsaf0>; + port-idx-in-ae = <5>; + local-mac-address = [00 00 00 00 00 00]; + status = "disabled"; + dma-coherent; + }; + + eth2: ethernet@0{ + compatible = "hisilicon,hns-nic-v2"; + ae-handle = <&dsaf0>; + port-idx-in-ae = <0>; + local-mac-address = [00 00 00 00 00 00]; + status = "disabled"; + dma-coherent; + }; + + eth3: ethernet@1{ + compatible = "hisilicon,hns-nic-v2"; + ae-handle = <&dsaf0>; + port-idx-in-ae = <1>; + local-mac-address = [00 00 00 00 00 00]; + status = "disabled"; + dma-coherent; + }; + + infiniband@c4000000 { + compatible = "hisilicon,hns-roce-v1"; + reg = <0x0 0xc4000000 0x0 0x100000>; + dma-coherent; + eth-handle = <ð2 ð3 0 0 ð0 ð1>; + dsaf-handle = <&dsaf0>; + node-guid = [00 9A CD 00 00 01 02 03]; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&mbigen_dsa_roce>; + interrupts = <722 1>, + <723 1>, + <724 1>, + <725 1>, + <726 1>, + <727 1>, + <728 1>, + <729 1>, + <730 1>, + <731 1>, + <732 1>, + <733 1>, + <734 1>, + <735 1>, + <736 1>, + <737 1>, + <738 1>, + <739 1>, + <740 1>, + <741 1>, + <742 1>, + <743 1>, + <744 1>, + <745 1>, + <746 1>, + <747 1>, + <748 1>, + <749 1>, + <750 1>, + <751 1>, + <752 1>, + <753 1>, + <785 1>, + <754 4>; + + interrupt-names = "hns-roce-comp-0", + "hns-roce-comp-1", + "hns-roce-comp-2", + "hns-roce-comp-3", + "hns-roce-comp-4", + "hns-roce-comp-5", + "hns-roce-comp-6", + "hns-roce-comp-7", + "hns-roce-comp-8", + "hns-roce-comp-9", + "hns-roce-comp-10", + "hns-roce-comp-11", + "hns-roce-comp-12", + "hns-roce-comp-13", + "hns-roce-comp-14", + "hns-roce-comp-15", + "hns-roce-comp-16", + "hns-roce-comp-17", + "hns-roce-comp-18", + "hns-roce-comp-19", + "hns-roce-comp-20", + "hns-roce-comp-21", + "hns-roce-comp-22", + "hns-roce-comp-23", + "hns-roce-comp-24", + "hns-roce-comp-25", + "hns-roce-comp-26", + "hns-roce-comp-27", + "hns-roce-comp-28", + "hns-roce-comp-29", + "hns-roce-comp-30", + "hns-roce-comp-31", + "hns-roce-async", + "hns-roce-common"; + }; + + sas0: sas@c3000000 { + compatible = "hisilicon,hip07-sas-v2"; + reg = <0 0xc3000000 0 0x10000>; + sas-addr = [50 01 88 20 16 00 00 00]; + hisilicon,sas-syscon = <&dsa_subctrl>; + ctrl-reset-reg = <0xa60>; + ctrl-reset-sts-reg = <0x5a30>; + ctrl-clock-ena-reg = <0x338>; + queue-count = <16>; + phy-count = <8>; + dma-coherent; + interrupt-parent = <&mbigen_sas0>; + interrupts = <64 4>,<65 4>,<66 4>,<67 4>,<68 4>, + <69 4>,<70 4>,<71 4>,<72 4>,<73 4>, + <74 4>,<75 4>,<76 4>,<77 4>,<78 4>, + <79 4>,<80 4>,<81 4>,<82 4>,<83 4>, + <84 4>,<85 4>,<86 4>,<87 4>,<88 4>, + <89 4>,<90 4>,<91 4>,<92 4>,<93 4>, + <94 4>,<95 4>,<96 4>,<97 4>,<98 4>, + <99 4>,<100 4>,<101 4>,<102 4>,<103 4>, + <104 4>,<105 4>,<106 4>,<107 4>,<108 4>, + <109 4>,<110 4>,<111 4>,<112 4>,<113 4>, + <114 4>,<115 4>,<116 4>,<117 4>,<118 4>, + <119 4>,<120 4>,<121 4>,<122 4>,<123 4>, + <124 4>,<125 4>,<126 4>,<127 4>,<128 4>, + <129 4>,<130 4>,<131 4>,<132 4>,<133 4>, + <134 4>,<135 4>,<136 4>,<137 4>,<138 4>, + <139 4>,<140 4>,<141 4>,<142 4>,<143 4>, + <144 4>,<145 4>,<146 4>,<147 4>,<148 4>, + <149 4>,<150 4>,<151 4>,<152 4>,<153 4>, + <154 4>,<155 4>,<156 4>,<157 4>,<158 4>, + <159 4>,<601 1>,<602 1>,<603 1>,<604 1>, + <605 1>,<606 1>,<607 1>,<608 1>,<609 1>, + <610 1>,<611 1>,<612 1>,<613 1>,<614 1>, + <615 1>,<616 1>,<617 1>,<618 1>,<619 1>, + <620 1>,<621 1>,<622 1>,<623 1>,<624 1>, + <625 1>,<626 1>,<627 1>,<628 1>,<629 1>, + <630 1>,<631 1>,<632 1>; + status = "disabled"; + }; + + sas1: sas@a2000000 { + compatible = "hisilicon,hip07-sas-v2"; + reg = <0 0xa2000000 0 0x10000>; + sas-addr = [50 01 88 20 16 00 00 00]; + hisilicon,sas-syscon = <&pcie_subctl>; + hip06-sas-v2-quirk-amt; + ctrl-reset-reg = <0xa18>; + ctrl-reset-sts-reg = <0x5a0c>; + ctrl-clock-ena-reg = <0x318>; + queue-count = <16>; + phy-count = <8>; + dma-coherent; + interrupt-parent = <&mbigen_sas1>; + interrupts = <64 4>,<65 4>,<66 4>,<67 4>,<68 4>, + <69 4>,<70 4>,<71 4>,<72 4>,<73 4>, + <74 4>,<75 4>,<76 4>,<77 4>,<78 4>, + <79 4>,<80 4>,<81 4>,<82 4>,<83 4>, + <84 4>,<85 4>,<86 4>,<87 4>,<88 4>, + <89 4>,<90 4>,<91 4>,<92 4>,<93 4>, + <94 4>,<95 4>,<96 4>,<97 4>,<98 4>, + <99 4>,<100 4>,<101 4>,<102 4>,<103 4>, + <104 4>,<105 4>,<106 4>,<107 4>,<108 4>, + <109 4>,<110 4>,<111 4>,<112 4>,<113 4>, + <114 4>,<115 4>,<116 4>,<117 4>,<118 4>, + <119 4>,<120 4>,<121 4>,<122 4>,<123 4>, + <124 4>,<125 4>,<126 4>,<127 4>,<128 4>, + <129 4>,<130 4>,<131 4>,<132 4>,<133 4>, + <134 4>,<135 4>,<136 4>,<137 4>,<138 4>, + <139 4>,<140 4>,<141 4>,<142 4>,<143 4>, + <144 4>,<145 4>,<146 4>,<147 4>,<148 4>, + <149 4>,<150 4>,<151 4>,<152 4>,<153 4>, + <154 4>,<155 4>,<156 4>,<157 4>,<158 4>, + <159 4>,<576 1>,<577 1>,<578 1>,<579 1>, + <580 1>,<581 1>,<582 1>,<583 1>,<584 1>, + <585 1>,<586 1>,<587 1>,<588 1>,<589 1>, + <590 1>,<591 1>,<592 1>,<593 1>,<594 1>, + <595 1>,<596 1>,<597 1>,<598 1>,<599 1>, + <600 1>,<601 1>,<602 1>,<603 1>,<604 1>, + <605 1>,<606 1>,<607 1>; + status = "disabled"; + }; + + sas2: sas@a3000000 { + compatible = "hisilicon,hip07-sas-v2"; + reg = <0 0xa3000000 0 0x10000>; + sas-addr = [50 01 88 20 16 00 00 00]; + hisilicon,sas-syscon = <&pcie_subctl>; + ctrl-reset-reg = <0xae0>; + ctrl-reset-sts-reg = <0x5a70>; + ctrl-clock-ena-reg = <0x3a8>; + queue-count = <16>; + phy-count = <9>; + dma-coherent; + interrupt-parent = <&mbigen_sas2>; + interrupts = <192 4>,<193 4>,<194 4>,<195 4>,<196 4>, + <197 4>,<198 4>,<199 4>,<200 4>,<201 4>, + <202 4>,<203 4>,<204 4>,<205 4>,<206 4>, + <207 4>,<208 4>,<209 4>,<210 4>,<211 4>, + <212 4>,<213 4>,<214 4>,<215 4>,<216 4>, + <217 4>,<218 4>,<219 4>,<220 4>,<221 4>, + <222 4>,<223 4>,<224 4>,<225 4>,<226 4>, + <227 4>,<228 4>,<229 4>,<230 4>,<231 4>, + <232 4>,<233 4>,<234 4>,<235 4>,<236 4>, + <237 4>,<238 4>,<239 4>,<240 4>,<241 4>, + <242 4>,<243 4>,<244 4>,<245 4>,<246 4>, + <247 4>,<248 4>,<249 4>,<250 4>,<251 4>, + <252 4>,<253 4>,<254 4>,<255 4>,<256 4>, + <257 4>,<258 4>,<259 4>,<260 4>,<261 4>, + <262 4>,<263 4>,<264 4>,<265 4>,<266 4>, + <267 4>,<268 4>,<269 4>,<270 4>,<271 4>, + <272 4>,<273 4>,<274 4>,<275 4>,<276 4>, + <277 4>,<278 4>,<279 4>,<280 4>,<281 4>, + <282 4>,<283 4>,<284 4>,<285 4>,<286 4>, + <287 4>,<608 1>,<609 1>,<610 1>,<611 1>, + <612 1>,<613 1>,<614 1>,<615 1>,<616 1>, + <617 1>,<618 1>,<619 1>,<620 1>,<621 1>, + <622 1>,<623 1>,<624 1>,<625 1>,<626 1>, + <627 1>,<628 1>,<629 1>,<630 1>,<631 1>, + <632 1>,<633 1>,<634 1>,<635 1>,<636 1>, + <637 1>,<638 1>,<639 1>; + status = "disabled"; + }; }; }; diff --git a/arch/arm64/boot/dts/include/arm b/arch/arm64/boot/dts/include/arm new file mode 120000 index 000000000000..cf63d80e2b93 --- /dev/null +++ b/arch/arm64/boot/dts/include/arm @@ -0,0 +1 @@ +../../../../arm/boot/dts
\ No newline at end of file diff --git a/arch/arm64/boot/dts/include/arm64 b/arch/arm64/boot/dts/include/arm64 new file mode 120000 index 000000000000..a96aa0ea9d8c --- /dev/null +++ b/arch/arm64/boot/dts/include/arm64 @@ -0,0 +1 @@ +..
\ No newline at end of file diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts index a07a0c1cd4e6..cef5f976bc0f 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts @@ -46,6 +46,7 @@ /dts-v1/; +#include <dt-bindings/gpio/gpio.h> #include "armada-372x.dtsi" / { @@ -60,10 +61,49 @@ device_type = "memory"; reg = <0x00000000 0x00000000 0x00000000 0x20000000>; }; + + exp_usb3_vbus: usb3-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb3-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + gpio = <&gpio_exp 1 GPIO_ACTIVE_HIGH>; + }; + + usb3_phy: usb3-phy { + compatible = "usb-nop-xceiv"; + vcc-supply = <&exp_usb3_vbus>; + }; }; &i2c0 { status = "okay"; + + gpio_exp: pca9555@22 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + + reg = <0x22>; + /* + * IO0_0: PWR_EN_USB2 IO1_0: PWR_EN_VTT + * IO0_1: PWR_EN_USB23 IO1_1: MPCIE_WDISABLE + * IO0_2: PWR_EN_SATA IO1_2: RGMII_DEV_RSTN + * IO0_3: PWR_EN_PCIE IO1_3: SGMII_DEV_RSTN + * IO0_4: PWR_EN_SD + * IO0_5: PWR_EN_EMMC + * IO0_6: PWR_EN_RGMII IO1_6: SATA_USB3.0_SEL + * IO0_7: PWR_EN_SGMII IO1_7: PWR_MCI_PS + */ + }; + + rtc@68 { + /* PT7C4337A from pericom fully compatible with the ds1337 */ + compatible = "dallas,ds1337"; + reg = <0x68>; + }; }; /* CON3 */ @@ -106,9 +146,19 @@ status = "okay"; }; +&sdhci0 { + non-removable; + bus-width = <8>; + mmc-ddr-1_8v; + mmc-hs400-1_8v; + marvell,pad-type = "fixed-1-8v"; + status = "okay"; +}; + /* CON31 */ &usb3 { status = "okay"; + usb-phy = <&usb3_phy>; }; /* CON17 (PCIe) / CON12 (mini-PCIe) */ diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi index 42747b7db683..58ae9e095af2 100644 --- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi @@ -112,6 +112,8 @@ i2c0: i2c@11000 { compatible = "marvell,armada-3700-i2c"; reg = <0x11000 0x24>; + #address-cells = <1>; + #size-cells = <0>; clocks = <&nb_periph_clk 10>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; mrvl,i2c-fast-mode; @@ -121,6 +123,8 @@ i2c1: i2c@11080 { compatible = "marvell,armada-3700-i2c"; reg = <0x11080 0x24>; + #address-cells = <1>; + #size-cells = <0>; clocks = <&nb_periph_clk 9>; interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; mrvl,i2c-fast-mode; @@ -196,7 +200,8 @@ compatible = "marvell,armada3700-xhci", "generic-xhci"; reg = <0x58000 0x4000>; - interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sb_periph_clk 12>; status = "disabled"; }; @@ -220,6 +225,17 @@ }; }; + sdhci0: sdhci@d8000 { + compatible = "marvell,armada-3700-sdhci", + "marvell,sdhci-xenon"; + reg = <0xd8000 0x300 + 0x17808 0x4>; + interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&nb_periph_clk 0>; + clock-names = "core"; + status = "disabled"; + }; + sata: sata@e0000 { compatible = "marvell,armada-3700-ahci"; reg = <0xe0000 0x2000>; diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts index 070b589680c5..12442329b80f 100644 --- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts @@ -146,3 +146,46 @@ &cpm_usb3_1 { status = "okay"; }; + +&ap_sdhci0 { + status = "okay"; + bus-width = <4>; + no-1-8-v; + non-removable; +}; + +&cpm_sdhci0 { + status = "okay"; + bus-width = <4>; + no-1-8-v; + non-removable; +}; + +&cpm_mdio { + phy0: ethernet-phy@0 { + reg = <0>; + }; + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + +&cpm_ethernet { + status = "okay"; +}; + +&cpm_eth1 { + status = "okay"; + phy = <&phy0>; + phy-mode = "sgmii"; +}; + +&cpm_eth2 { + status = "okay"; + phy = <&phy1>; + phy-mode = "rgmii-id"; +}; + +&cpm_crypto { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/marvell/armada-8020.dtsi b/arch/arm64/boot/dts/marvell/armada-8020.dtsi index 048e5cf5160e..7c08f1f28d9e 100644 --- a/arch/arm64/boot/dts/marvell/armada-8020.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-8020.dtsi @@ -54,3 +54,13 @@ compatible = "marvell,armada8020", "marvell,armada-ap806-dual", "marvell,armada-ap806"; }; + +/* The RTC requires external oscillator. But on Aramda 80x0, the RTC clock + * in CP master is not connected (by package) to the oscillator. So + * disable it. However, the RTC clock in CP slave is connected to the + * oscillator so this one is let enabled. + */ + +&cpm_rtc { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts index 6e6f182fb297..dc0d084005b2 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts @@ -124,6 +124,26 @@ status = "okay"; }; +&cpm_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + +&cpm_ethernet { + status = "okay"; +}; + +&cpm_eth2 { + status = "okay"; + phy = <&phy1>; + phy-mode = "rgmii-id"; +}; + +&cpm_crypto { + status = "okay"; +}; + /* CON5 on CP1 expansion */ &cps_pcie2 { status = "okay"; @@ -148,3 +168,15 @@ &cps_usb3_1 { status = "okay"; }; + +&ap_sdhci0 { + status = "okay"; + bus-width = <4>; + non-removable; +}; + +&cpm_sdhci0 { + status = "okay"; + bus-width = <8>; + non-removable; +}; diff --git a/arch/arm64/boot/dts/marvell/armada-8040.dtsi b/arch/arm64/boot/dts/marvell/armada-8040.dtsi index 9c1b28c47683..33813a75bc30 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-8040.dtsi @@ -54,3 +54,12 @@ compatible = "marvell,armada8040", "marvell,armada-ap806-quad", "marvell,armada-ap806"; }; + +/* The RTC requires external oscillator. But on Aramda 80x0, the RTC clock + * in CP master is not connected (by package) to the oscillator. So + * disable it. However, the RTC clock in CP slave is connected to the + * oscillator so this one is let enabled. + */ +&cpm_rtc { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi index 5019c8f4acd0..fe41bf9c301e 100644 --- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi @@ -229,6 +229,17 @@ }; + ap_sdhci0: sdhci@6e0000 { + compatible = "marvell,armada-ap806-sdhci"; + reg = <0x6e0000 0x300>; + interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "core"; + clocks = <&ap_syscon 4>; + dma-coherent; + marvell,xenon-phy-slow-mode; + status = "disabled"; + }; + ap_syscon: system-controller@6f4000 { compatible = "marvell,ap806-system-controller", "syscon"; diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi index 3a99c36433d6..ac8df5201cd6 100644 --- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi @@ -59,6 +59,43 @@ interrupt-parent = <&gic>; ranges = <0x0 0x0 0xf2000000 0x2000000>; + cpm_ethernet: ethernet@0 { + compatible = "marvell,armada-7k-pp22"; + reg = <0x0 0x100000>, <0x129000 0xb000>; + clocks = <&cpm_syscon0 1 3>, <&cpm_syscon0 1 9>, <&cpm_syscon0 1 5>; + clock-names = "pp_clk", "gop_clk", "mg_clk"; + status = "disabled"; + dma-coherent; + + cpm_eth0: eth0 { + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; + port-id = <0>; + gop-port-id = <0>; + status = "disabled"; + }; + + cpm_eth1: eth1 { + interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; + port-id = <1>; + gop-port-id = <2>; + status = "disabled"; + }; + + cpm_eth2: eth2 { + interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; + port-id = <2>; + gop-port-id = <3>; + status = "disabled"; + }; + }; + + cpm_mdio: mdio@12a200 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,orion-mdio"; + reg = <0x12a200 0x10>; + }; + cpm_syscon0: system-controller@440000 { compatible = "marvell,cp110-system-controller0", "syscon"; @@ -79,6 +116,13 @@ "cpm-usb3dev", "cpm-eip150", "cpm-eip197"; }; + cpm_rtc: rtc@284000 { + compatible = "marvell,armada-8k-rtc"; + reg = <0x284000 0x20>, <0x284080 0x24>; + reg-names = "rtc", "rtc-soc"; + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + }; + cpm_sata0: sata@540000 { compatible = "marvell,armada-8k-ahci", "generic-ahci"; @@ -173,6 +217,32 @@ clocks = <&cpm_syscon0 1 25>; status = "okay"; }; + + cpm_sdhci0: sdhci@780000 { + compatible = "marvell,armada-cp110-sdhci"; + reg = <0x780000 0x300>; + interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "core"; + clocks = <&cpm_syscon0 1 4>; + dma-coherent; + status = "disabled"; + }; + + cpm_crypto: crypto@800000 { + compatible = "inside-secure,safexcel-eip197"; + reg = <0x800000 0x200000>; + interrupts = <GIC_SPI 34 (IRQ_TYPE_EDGE_RISING + | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "mem", "ring0", "ring1", + "ring2", "ring3", "eip"; + clocks = <&cpm_syscon0 1 26>; + status = "disabled"; + }; }; cpm_pcie0: pcie@f2600000 { diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi index 9e09c4d3b6bd..7740a75a8230 100644 --- a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi @@ -59,6 +59,50 @@ interrupt-parent = <&gic>; ranges = <0x0 0x0 0xf4000000 0x2000000>; + cps_rtc: rtc@284000 { + compatible = "marvell,armada-8k-rtc"; + reg = <0x284000 0x20>, <0x284080 0x24>; + reg-names = "rtc", "rtc-soc"; + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + }; + + cps_ethernet: ethernet@0 { + compatible = "marvell,armada-7k-pp22"; + reg = <0x0 0x100000>, <0x129000 0xb000>; + clocks = <&cps_syscon0 1 3>, <&cps_syscon0 1 9>, <&cps_syscon0 1 5>; + clock-names = "pp_clk", "gop_clk", "mg_clk"; + status = "disabled"; + dma-coherent; + + cps_eth0: eth0 { + interrupts = <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>; + port-id = <0>; + gop-port-id = <0>; + status = "disabled"; + }; + + cps_eth1: eth1 { + interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>; + port-id = <1>; + gop-port-id = <2>; + status = "disabled"; + }; + + cps_eth2: eth2 { + interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>; + port-id = <2>; + gop-port-id = <3>; + status = "disabled"; + }; + }; + + cps_mdio: mdio@12a200 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,orion-mdio"; + reg = <0x12a200 0x10>; + }; + cps_syscon0: system-controller@440000 { compatible = "marvell,cp110-system-controller0", "syscon"; @@ -173,6 +217,22 @@ clocks = <&cps_syscon0 1 25>; status = "okay"; }; + + cps_crypto: crypto@800000 { + compatible = "inside-secure,safexcel-eip197"; + reg = <0x800000 0x200000>; + interrupts = <GIC_SPI 34 (IRQ_TYPE_EDGE_RISING + | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "mem", "ring0", "ring1", + "ring2", "ring3", "eip"; + clocks = <&cps_syscon0 1 26>; + status = "disabled"; + }; }; cps_pcie0: pcie@f4600000 { diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi index 3f3a46a4bd01..2b17936ac5be 100644 --- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi @@ -224,7 +224,7 @@ }; flow-controller@60007000 { - compatible = "nvidia,tegra124-flowctrl"; + compatible = "nvidia,tegra132-flowctrl", "nvidia,tegra124-flowctrl"; reg = <0x0 0x60007000 0x0 0x1000>; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts index 0d3c0996d832..8daadadec63a 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts @@ -1,8 +1,99 @@ /dts-v1/; +#include <dt-bindings/input/linux-event-codes.h> + #include "tegra186-p3310.dtsi" / { model = "NVIDIA Tegra186 P2771-0000 Development Board"; compatible = "nvidia,p2771-0000", "nvidia,tegra186"; + + i2c@3160000 { + power-monitor@42 { + compatible = "ti,ina3221"; + reg = <0x42>; + }; + + power-monitor@43 { + compatible = "ti,ina3221"; + reg = <0x43>; + }; + + exp1: gpio@74 { + compatible = "ti,tca9539"; + reg = <0x74>; + + interrupt-parent = <&gpio>; + interrupts = <TEGRA_MAIN_GPIO(Y, 0) GPIO_ACTIVE_LOW>; + + #gpio-cells = <2>; + gpio-controller; + }; + + exp2: gpio@77 { + compatible = "ti,tca9539"; + reg = <0x77>; + + interrupt-parent = <&gpio>; + interrupts = <TEGRA_MAIN_GPIO(Y, 6) GPIO_ACTIVE_LOW>; + + #gpio-cells = <2>; + gpio-controller; + }; + }; + + /* SDMMC1 (SD/MMC) */ + sdhci@3400000 { + status = "okay"; + + vmmc-supply = <&vdd_sd>; + }; + + gpio-keys { + compatible = "gpio-keys"; + + power { + label = "Power"; + gpios = <&gpio_aon TEGRA_AON_GPIO(FF, 0) + GPIO_ACTIVE_LOW>; + linux,input-type = <EV_KEY>; + linux,code = <KEY_POWER>; + debounce-interval = <10>; + wakeup-source; + }; + + volume-up { + label = "Volume Up"; + gpios = <&gpio_aon TEGRA_AON_GPIO(FF, 1) + GPIO_ACTIVE_LOW>; + linux,input-type = <EV_KEY>; + linux,code = <KEY_VOLUMEUP>; + debounce-interval = <10>; + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio_aon TEGRA_AON_GPIO(FF, 2) + GPIO_ACTIVE_LOW>; + linux,input-type = <EV_KEY>; + linux,code = <KEY_VOLUMEDOWN>; + debounce-interval = <10>; + }; + }; + + regulators { + vdd_sd: regulator@100 { + compatible = "regulator-fixed"; + reg = <100>; + + regulator-name = "SD_CARD_SW_PWR"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&gpio TEGRA_MAIN_GPIO(P, 6) GPIO_ACTIVE_HIGH>; + enable-active-high; + + vin-supply = <&vdd_3v3_sys>; + }; + }; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi b/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi index 1abe2eceb3d1..cf84d7046ad5 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi @@ -1,11 +1,23 @@ #include "tegra186.dtsi" +#include <dt-bindings/mfd/max77620.h> + / { model = "NVIDIA Tegra186 P3310 Processor Module"; compatible = "nvidia,p3310", "nvidia,tegra186"; aliases { + sdhci0 = "/sdhci@3460000"; + sdhci1 = "/sdhci@3400000"; serial0 = &uarta; + i2c0 = "/bpmp/i2c"; + i2c1 = "/i2c@3160000"; + i2c2 = "/i2c@c240000"; + i2c3 = "/i2c@3180000"; + i2c4 = "/i2c@3190000"; + i2c5 = "/i2c@31c0000"; + i2c6 = "/i2c@c250000"; + i2c7 = "/i2c@31e0000"; }; chosen { @@ -18,14 +30,99 @@ reg = <0x0 0x80000000 0x2 0x00000000>; }; + ethernet@2490000 { + status = "okay"; + + phy-reset-gpios = <&gpio TEGRA_MAIN_GPIO(M, 4) GPIO_ACTIVE_LOW>; + phy-handle = <&phy>; + phy-mode = "rgmii"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy: phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x0>; + interrupt-parent = <&gpio>; + interrupts = <TEGRA_MAIN_GPIO(M, 5) IRQ_TYPE_LEVEL_HIGH>; + }; + }; + }; + serial@3100000 { status = "okay"; }; + i2c@3160000 { + status = "okay"; + + power-monitor@40 { + compatible = "ti,ina3221"; + reg = <0x40>; + }; + + power-monitor@41 { + compatible = "ti,ina3221"; + reg = <0x41>; + }; + }; + + i2c@3180000 { + status = "okay"; + }; + + i2c@3190000 { + status = "okay"; + }; + + i2c@31c0000 { + status = "okay"; + }; + + i2c@31e0000 { + status = "okay"; + }; + + /* SDMMC1 (SD/MMC) */ + sdhci@3400000 { + cd-gpios = <&gpio TEGRA_MAIN_GPIO(P, 5) GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio TEGRA_MAIN_GPIO(P, 4) GPIO_ACTIVE_LOW>; + + vqmmc-supply = <&vddio_sdmmc1>; + }; + + /* SDMMC3 (SDIO) */ + sdhci@3440000 { + status = "okay"; + }; + + /* SDMMC4 (eMMC) */ + sdhci@3460000 { + status = "okay"; + bus-width = <8>; + non-removable; + + vqmmc-supply = <&vdd_1v8_ap>; + vmmc-supply = <&vdd_3v3_sys>; + }; + hsp@3c00000 { status = "okay"; }; + i2c@c240000 { + status = "okay"; + }; + + i2c@c250000 { + status = "okay"; + }; + + pmc@c360000 { + nvidia,invert-interrupt; + }; + cpus { cpu@0 { enable-method = "psci"; @@ -53,7 +150,192 @@ }; bpmp { - status = "okay"; + i2c { + status = "okay"; + + pmic: pmic@3c { + compatible = "maxim,max77620"; + reg = <0x3c>; + + interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <2>; + interrupt-controller; + + #gpio-cells = <2>; + gpio-controller; + + pinctrl-names = "default"; + pinctrl-0 = <&max77620_default>; + + max77620_default: pinmux { + gpio0 { + pins = "gpio0"; + function = "gpio"; + }; + + gpio1 { + pins = "gpio1"; + function = "fps-out"; + maxim,active-fps-source = <MAX77620_FPS_SRC_0>; + }; + + gpio2 { + pins = "gpio2"; + function = "fps-out"; + maxim,active-fps-source = <MAX77620_FPS_SRC_1>; + }; + + gpio3 { + pins = "gpio3"; + function = "fps-out"; + maxim,active-fps-source = <MAX77620_FPS_SRC_1>; + }; + + gpio4 { + pins = "gpio4"; + function = "32k-out1"; + drive-push-pull = <1>; + }; + + gpio5 { + pins = "gpio5"; + function = "gpio"; + drive-push-pull = <0>; + }; + + gpio6 { + pins = "gpio6"; + function = "gpio"; + drive-push-pull = <1>; + }; + + gpio7 { + pins = "gpio7"; + function = "gpio"; + drive-push-pull = <0>; + }; + }; + + fps { + fps0 { + maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>; + maxim,shutdown-fps-time-period-us = <640>; + }; + + fps1 { + maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN1>; + maxim,shutdown-fps-time-period-us = <640>; + }; + + fps2 { + maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>; + maxim,shutdown-fps-time-period-us = <640>; + }; + }; + + regulators { + in-sd0-supply = <&vdd_5v0_sys>; + in-sd1-supply = <&vdd_5v0_sys>; + in-sd2-supply = <&vdd_5v0_sys>; + in-sd3-supply = <&vdd_5v0_sys>; + + in-ldo0-1-supply = <&vdd_5v0_sys>; + in-ldo2-supply = <&vdd_5v0_sys>; + in-ldo3-5-supply = <&vdd_5v0_sys>; + in-ldo4-6-supply = <&vdd_1v8>; + in-ldo7-8-supply = <&avdd_dsi_csi>; + + sd0 { + regulator-name = "VDD_DDR_1V1_PMIC"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + }; + + avdd_dsi_csi: sd1 { + regulator-name = "AVDD_DSI_CSI_1V2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + /* XXX */ + regulator-always-on; + regulator-boot-on; + }; + + vdd_1v8: sd2 { + regulator-name = "VDD_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + /* XXX */ + regulator-always-on; + regulator-boot-on; + }; + + vdd_3v3_sys: sd3 { + regulator-name = "VDD_3V3_SYS"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + /* XXX */ + regulator-always-on; + regulator-boot-on; + }; + + ldo0 { + regulator-name = "VDD_1V8_AP_PLL"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + /* XXX */ + regulator-always-on; + regulator-boot-on; + }; + + ldo2 { + regulator-name = "VDDIO_3V3_AOHV"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + /* XXX */ + regulator-always-on; + regulator-boot-on; + }; + + vddio_sdmmc1: ldo3 { + regulator-name = "VDDIO_SDMMC1_AP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + ldo4 { + regulator-name = "VDD_RTC"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + vddio_sdmmc3: ldo5 { + regulator-name = "VDDIO_SDMMC3_AP"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + avdd_1v05: ldo7 { + regulator-name = "VDD_HDMI_1V05"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + /* XXX */ + regulator-always-on; + regulator-boot-on; + }; + + vdd_pex: ldo8 { + regulator-name = "VDD_PEX_1V05"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + /* XXX */ + regulator-always-on; + regulator-boot-on; + }; + }; + }; + }; }; psci { @@ -61,4 +343,39 @@ status = "okay"; method = "smc"; }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + vdd_5v0_sys: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + + regulator-name = "VDD_5V0_SYS"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_1v8_ap: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + + regulator-name = "VDD_1V8_AP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + /* XXX */ + regulator-always-on; + regulator-boot-on; + + gpio = <&pmic 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + + vin-supply = <&vdd_1v8>; + }; + }; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi index 62fa85ae0271..5e62e68ac053 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi @@ -2,6 +2,7 @@ #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/mailbox/tegra186-hsp.h> +#include <dt-bindings/power/tegra186-powergate.h> #include <dt-bindings/reset/tegra186-reset.h> / { @@ -27,6 +28,37 @@ gpio-controller; }; + ethernet@2490000 { + compatible = "nvidia,tegra186-eqos", + "snps,dwc-qos-ethernet-4.10"; + reg = <0x0 0x02490000 0x0 0x10000>; + interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>, /* common */ + <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>, /* power */ + <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, /* rx0 */ + <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>, /* tx0 */ + <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>, /* rx1 */ + <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>, /* tx1 */ + <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>, /* rx2 */ + <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, /* tx2 */ + <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>, /* rx3 */ + <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>; /* tx3 */ + clocks = <&bpmp TEGRA186_CLK_AXI_CBB>, + <&bpmp TEGRA186_CLK_EQOS_AXI>, + <&bpmp TEGRA186_CLK_EQOS_RX>, + <&bpmp TEGRA186_CLK_EQOS_TX>, + <&bpmp TEGRA186_CLK_EQOS_PTP_REF>; + clock-names = "master_bus", "slave_bus", "rx", "tx", "ptp_ref"; + resets = <&bpmp TEGRA186_RESET_EQOS>; + reset-names = "eqos"; + status = "disabled"; + + snps,write-requests = <1>; + snps,read-requests = <3>; + snps,burst-map = <0x7>; + snps,txpbl = <32>; + snps,rxpbl = <8>; + }; + uarta: serial@3100000 { compatible = "nvidia,tegra186-uart", "nvidia,tegra20-uart"; reg = <0x0 0x03100000 0x0 0x40>; @@ -307,6 +339,33 @@ #interrupt-cells = <2>; }; + pmc@c360000 { + compatible = "nvidia,tegra186-pmc"; + reg = <0 0x0c360000 0 0x10000>, + <0 0x0c370000 0 0x10000>, + <0 0x0c380000 0 0x10000>, + <0 0x0c390000 0 0x10000>; + reg-names = "pmc", "wake", "aotag", "scratch"; + }; + + gpu@17000000 { + compatible = "nvidia,gp10b"; + reg = <0x0 0x17000000 0x0 0x1000000>, + <0x0 0x18000000 0x0 0x1000000>; + interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH + GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "stall", "nonstall"; + + clocks = <&bpmp TEGRA186_CLK_GPCCLK>, + <&bpmp TEGRA186_CLK_GPU>; + clock-names = "gpu", "pwr"; + resets = <&bpmp TEGRA186_RESET_GPU>; + reset-names = "gpu"; + status = "disabled"; + + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_GPU>; + }; + sysram@30000000 { compatible = "nvidia,tegra186-sysram", "mmio-sram"; reg = <0x0 0x30000000 0x0 0x50000>; diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index 2f832df29da8..8f26c4d4409a 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -89,6 +89,8 @@ ranges = <0x0 0x54000000 0x0 0x54000000 0x0 0x01000000>; + iommus = <&mc TEGRA_SWGROUP_HC>; + dpaux1: dpaux@54040000 { compatible = "nvidia,tegra210-dpaux"; reg = <0x0 0x54040000 0x0 0x00040000>; @@ -185,7 +187,14 @@ vic@54340000 { compatible = "nvidia,tegra210-vic"; reg = <0x0 0x54340000 0x0 0x00040000>; - status = "disabled"; + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&tegra_car TEGRA210_CLK_VIC03>; + clock-names = "vic"; + resets = <&tegra_car 178>; + reset-names = "vic"; + + iommus = <&mc TEGRA_SWGROUP_VIC>; + power-domains = <&pd_vic>; }; nvjpg@54380000 { @@ -755,6 +764,14 @@ resets = <&tegra_car TEGRA210_CLK_XUSB_HOST>; #power-domain-cells = <0>; }; + + pd_vic: vic { + clocks = <&tegra_car TEGRA210_CLK_VIC03>; + clock-names = "vic"; + resets = <&tegra_car 178>; + reset-names = "vic"; + #power-domain-cells = <0>; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi index eac5389f2f38..a17f5b9a5de6 100644 --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi @@ -35,6 +35,17 @@ stdout-path = "serial0"; }; + reserved-memory { + ramoops@bff00000{ + compatible = "ramoops"; + reg = <0x0 0xbff00000 0x0 0x100000>; + + record-size = <0x20000>; + console-size = <0x20000>; + ftrace-size = <0x20000>; + }; + }; + soc { dma@7884000 { status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 68a8e67cba29..ab3093995ded 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -157,7 +157,7 @@ }; pmu { - compatible = "arm,armv8-pmuv3"; + compatible = "arm,cortex-a53-pmu"; interrupts = <GIC_PPI 7 GIC_CPU_MASK_SIMPLE(4)>; }; @@ -833,8 +833,9 @@ clocks = <&gcc GCC_MSS_CFG_AHB_CLK>, <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, - <&gcc GCC_BOOT_ROM_AHB_CLK>; - clock-names = "iface", "bus", "mem"; + <&gcc GCC_BOOT_ROM_AHB_CLK>, + <&xo_board>; + clock-names = "iface", "bus", "mem", "xo"; qcom,smem-states = <&hexagon_smp2p_out 0>; qcom,smem-state-names = "stop"; @@ -842,6 +843,7 @@ resets = <&scm 0>; reset-names = "mss_restart"; + cx-supply = <&pm8916_s1>; mx-supply = <&pm8916_l3>; pll-supply = <&pm8916_l7>; @@ -856,6 +858,16 @@ mpss { memory-region = <&mpss_mem>; }; + + smd-edge { + interrupts = <0 25 IRQ_TYPE_EDGE_RISING>; + + qcom,smd-edge = <0>; + qcom,ipc = <&apcs 8 12>; + qcom,remote-pid = <1>; + + label = "hexagon"; + }; }; pronto: wcnss@a21b000 { @@ -1214,14 +1226,6 @@ }; }; }; - - hexagon { - interrupts = <0 25 IRQ_TYPE_EDGE_RISING>; - - qcom,smd-edge = <0>; - qcom,ipc = <&apcs 8 12>; - qcom,remote-pid = <1>; - }; }; hexagon-smp2p { diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index ed7223d3c8cb..9bc9c857a000 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -534,6 +534,26 @@ }; }; + adsp-pil { + compatible = "qcom,msm8996-adsp-pil"; + + interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack"; + + clocks = <&xo_board>; + clock-names = "xo"; + + memory-region = <&adsp_region>; + + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + }; + adsp-smp2p { compatible = "qcom,smp2p"; qcom,smem = <443>, <429>; @@ -547,7 +567,7 @@ adsp_smp2p_out: master-kernel { qcom,entry-name = "master-kernel"; - #qcom,state-cells = <1>; + #qcom,smem-state-cells = <1>; }; adsp_smp2p_in: slave-kernel { @@ -557,5 +577,29 @@ #interrupt-cells = <2>; }; }; + + smp2p-slpi { + compatible = "qcom,smp2p"; + qcom,smem = <481>, <430>; + + interrupts = <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>; + + qcom,ipc = <&apcs 16 26>; + + qcom,local-pid = <0>; + qcom,remote-pid = <3>; + + slpi_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + slpi_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + }; + }; #include "msm8996-pins.dtsi" diff --git a/arch/arm64/boot/dts/qcom/pm8994.dtsi b/arch/arm64/boot/dts/qcom/pm8994.dtsi index 0f1866024ae3..b413e44fd09e 100644 --- a/arch/arm64/boot/dts/qcom/pm8994.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8994.dtsi @@ -9,6 +9,13 @@ #address-cells = <1>; #size-cells = <0>; + rtc@6000 { + compatible = "qcom,pm8941-rtc"; + reg = <0x6000>, <0x6100>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; + }; + pm8994_gpios: gpios@c000 { compatible = "qcom,pm8994-gpio"; reg = <0xc000>; diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts index c5f8f69a4f5f..ab352159de65 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts +++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts @@ -33,6 +33,21 @@ reg = <0x0 0x48000000 0x0 0x38000000>; }; + memory@500000000 { + device_type = "memory"; + reg = <0x5 0x00000000 0x0 0x40000000>; + }; + + memory@600000000 { + device_type = "memory"; + reg = <0x6 0x00000000 0x0 0x40000000>; + }; + + memory@700000000 { + device_type = "memory"; + reg = <0x7 0x00000000 0x0 0x40000000>; + }; + leds { compatible = "gpio-leds"; @@ -213,7 +228,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &i2c2 { @@ -339,18 +353,7 @@ status = "okay"; phy0: ethernet-phy@0 { - rxc-skew-ps = <900>; - rxdv-skew-ps = <0>; - rxd0-skew-ps = <0>; - rxd1-skew-ps = <0>; - rxd2-skew-ps = <0>; - rxd3-skew-ps = <0>; - txc-skew-ps = <900>; - txen-skew-ps = <0>; - txd0-skew-ps = <0>; - txd1-skew-ps = <0>; - txd2-skew-ps = <0>; - txd3-skew-ps = <0>; + rxc-skew-ps = <1500>; reg = <0>; interrupt-parent = <&gpio2>; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts index 7a8986edcdc0..639aa085d996 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts @@ -56,7 +56,7 @@ reg = <0x0 0x48000000 0x0 0x38000000>; }; - x12_clk: x12_clk { + x12_clk: x12 { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24576000>; @@ -247,8 +247,22 @@ }; avb_pins: avb { - groups = "avb_mdc"; - function = "avb"; + mux { + groups = "avb_link", "avb_phy_int", "avb_mdc", + "avb_mii"; + function = "avb"; + }; + + pins_mdc { + groups = "avb_mdc"; + drive-strength = <24>; + }; + + pins_mii_tx { + pins = "PIN_AVB_TX_CTL", "PIN_AVB_TXC", "PIN_AVB_TD0", + "PIN_AVB_TD1", "PIN_AVB_TD2", "PIN_AVB_TD3"; + drive-strength = <12>; + }; }; du_pins: du { @@ -348,7 +362,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &i2c2 { @@ -485,6 +498,10 @@ clock-frequency = <22579200>; }; +&i2c_dvfs { + status = "okay"; +}; + &avb { pinctrl-0 = <&avb_pins>; pinctrl-names = "default"; @@ -493,18 +510,7 @@ status = "okay"; phy0: ethernet-phy@0 { - rxc-skew-ps = <900>; - rxdv-skew-ps = <0>; - rxd0-skew-ps = <0>; - rxd1-skew-ps = <0>; - rxd2-skew-ps = <0>; - rxd3-skew-ps = <0>; - txc-skew-ps = <900>; - txen-skew-ps = <0>; - txd0-skew-ps = <0>; - txd1-skew-ps = <0>; - txd2-skew-ps = <0>; - txd3-skew-ps = <0>; + rxc-skew-ps = <1500>; reg = <0>; interrupt-parent = <&gpio2>; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; @@ -567,7 +573,6 @@ &pcie_bus_clk { clock-frequency = <100000000>; - status = "okay"; }; &pciec0 { diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi index eac4f29aa5cd..e99d6443b3e4 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi @@ -25,10 +25,11 @@ i2c4 = &i2c4; i2c5 = &i2c5; i2c6 = &i2c6; + i2c7 = &i2c_dvfs; }; psci { - compatible = "arm,psci-0.2"; + compatible = "arm,psci-1.0", "arm,psci-0.2"; method = "smc"; }; @@ -72,17 +73,51 @@ enable-method = "psci"; }; - L2_CA57: cache-controller@0 { + a53_0: cpu@100 { + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x100>; + device_type = "cpu"; + power-domains = <&sysc R8A7795_PD_CA53_CPU0>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + a53_1: cpu@101 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x101>; + device_type = "cpu"; + power-domains = <&sysc R8A7795_PD_CA53_CPU1>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + a53_2: cpu@102 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x102>; + device_type = "cpu"; + power-domains = <&sysc R8A7795_PD_CA53_CPU2>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + a53_3: cpu@103 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x103>; + device_type = "cpu"; + power-domains = <&sysc R8A7795_PD_CA53_CPU3>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + L2_CA57: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7795_PD_CA57_SCU>; cache-unified; cache-level = <2>; }; - L2_CA53: cache-controller@100 { + L2_CA53: cache-controller-1 { compatible = "cache"; - reg = <0x100>; power-domains = <&sysc R8A7795_PD_CA53_SCU>; cache-unified; cache-level = <2>; @@ -165,10 +200,11 @@ <0x0 0xf1040000 0 0x20000>, <0x0 0xf1060000 0 0x20000>; interrupts = <GIC_PPI 9 - (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>; clocks = <&cpg CPG_MOD 408>; clock-names = "clk"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 408>; }; wdt0: watchdog@e6020000 { @@ -176,6 +212,7 @@ reg = <0 0xe6020000 0 0x0c>; clocks = <&cpg CPG_MOD 402>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 402>; status = "disabled"; }; @@ -191,6 +228,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 912>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 912>; }; gpio1: gpio@e6051000 { @@ -205,6 +243,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 911>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 911>; }; gpio2: gpio@e6052000 { @@ -219,6 +258,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 910>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 910>; }; gpio3: gpio@e6053000 { @@ -233,6 +273,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 909>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 909>; }; gpio4: gpio@e6054000 { @@ -247,6 +288,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 908>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 908>; }; gpio5: gpio@e6055000 { @@ -261,6 +303,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 907>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 907>; }; gpio6: gpio@e6055400 { @@ -275,6 +318,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 906>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 906>; }; gpio7: gpio@e6055800 { @@ -289,6 +333,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 905>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 905>; }; pmu_a57 { @@ -303,16 +348,28 @@ <&a57_3>; }; + pmu_a53 { + compatible = "arm,cortex-a53-pmu"; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; + interrupt-affinity = <&a53_0>, + <&a53_1>, + <&a53_2>, + <&a53_3>; + }; + timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 - (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 14 - (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 - (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 10 - (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>; }; cpg: clock-controller@e6150000 { @@ -322,6 +379,7 @@ clock-names = "extal", "extalr"; #clock-cells = <2>; #power-domain-cells = <0>; + #reset-cells = <1>; }; rst: reset-controller@e6160000 { @@ -358,6 +416,7 @@ GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 407>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 407>; }; dmac0: dma-controller@e6700000 { @@ -389,6 +448,7 @@ clocks = <&cpg CPG_MOD 219>; clock-names = "fck"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 219>; #dma-cells = <1>; dma-channels = <16>; }; @@ -422,6 +482,7 @@ clocks = <&cpg CPG_MOD 218>; clock-names = "fck"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 218>; #dma-cells = <1>; dma-channels = <16>; }; @@ -455,6 +516,7 @@ clocks = <&cpg CPG_MOD 217>; clock-names = "fck"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 217>; #dma-cells = <1>; dma-channels = <16>; }; @@ -488,6 +550,7 @@ clocks = <&cpg CPG_MOD 502>; clock-names = "fck"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 502>; #dma-cells = <1>; dma-channels = <16>; }; @@ -521,6 +584,7 @@ clocks = <&cpg CPG_MOD 501>; clock-names = "fck"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 501>; #dma-cells = <1>; dma-channels = <16>; }; @@ -563,7 +627,8 @@ "ch24"; clocks = <&cpg CPG_MOD 812>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - phy-mode = "rgmii-id"; + resets = <&cpg 812>; + phy-mode = "rgmii-txid"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -581,6 +646,7 @@ assigned-clocks = <&cpg CPG_CORE R8A7795_CLK_CANFD>; assigned-clock-rates = <40000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 916>; status = "disabled"; }; @@ -596,6 +662,7 @@ assigned-clocks = <&cpg CPG_CORE R8A7795_CLK_CANFD>; assigned-clock-rates = <40000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 915>; status = "disabled"; }; @@ -612,6 +679,7 @@ assigned-clocks = <&cpg CPG_CORE R8A7795_CLK_CANFD>; assigned-clock-rates = <40000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 914>; status = "disabled"; channel0 { @@ -636,6 +704,7 @@ dmas = <&dmac1 0x31>, <&dmac1 0x30>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 520>; status = "disabled"; }; @@ -652,6 +721,7 @@ dmas = <&dmac1 0x33>, <&dmac1 0x32>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 519>; status = "disabled"; }; @@ -668,6 +738,7 @@ dmas = <&dmac1 0x35>, <&dmac1 0x34>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 518>; status = "disabled"; }; @@ -684,6 +755,7 @@ dmas = <&dmac0 0x37>, <&dmac0 0x36>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 517>; status = "disabled"; }; @@ -700,6 +772,7 @@ dmas = <&dmac0 0x39>, <&dmac0 0x38>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 516>; status = "disabled"; }; @@ -715,6 +788,7 @@ dmas = <&dmac1 0x51>, <&dmac1 0x50>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 207>; status = "disabled"; }; @@ -730,6 +804,7 @@ dmas = <&dmac1 0x53>, <&dmac1 0x52>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 206>; status = "disabled"; }; @@ -745,6 +820,7 @@ dmas = <&dmac1 0x13>, <&dmac1 0x12>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 310>; status = "disabled"; }; @@ -760,6 +836,7 @@ dmas = <&dmac0 0x57>, <&dmac0 0x56>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 204>; status = "disabled"; }; @@ -775,6 +852,7 @@ dmas = <&dmac0 0x59>, <&dmac0 0x58>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 203>; status = "disabled"; }; @@ -790,6 +868,21 @@ dmas = <&dmac1 0x5b>, <&dmac1 0x5a>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 202>; + status = "disabled"; + }; + + i2c_dvfs: i2c@e60b0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7795", + "renesas,rcar-gen3-iic", + "renesas,rmobile-iic"; + reg = <0 0xe60b0000 0 0x425>; + interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 926>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 926>; status = "disabled"; }; @@ -802,6 +895,7 @@ interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 931>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 931>; dmas = <&dmac1 0x91>, <&dmac1 0x90>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <110>; @@ -817,6 +911,7 @@ interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 930>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 930>; dmas = <&dmac1 0x93>, <&dmac1 0x92>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <6>; @@ -832,6 +927,7 @@ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 929>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 929>; dmas = <&dmac1 0x95>, <&dmac1 0x94>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <6>; @@ -847,6 +943,7 @@ interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 928>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 928>; dmas = <&dmac0 0x97>, <&dmac0 0x96>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <110>; @@ -862,6 +959,7 @@ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 927>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 927>; dmas = <&dmac0 0x99>, <&dmac0 0x98>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <110>; @@ -877,6 +975,7 @@ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 919>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 919>; dmas = <&dmac0 0x9b>, <&dmac0 0x9a>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <110>; @@ -892,6 +991,7 @@ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 918>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 918>; dmas = <&dmac0 0x9d>, <&dmac0 0x9c>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <6>; @@ -903,6 +1003,7 @@ reg = <0 0xe6e30000 0 0x8>; clocks = <&cpg CPG_MOD 523>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 523>; #pwm-cells = <2>; status = "disabled"; }; @@ -912,6 +1013,7 @@ reg = <0 0xe6e31000 0 0x8>; clocks = <&cpg CPG_MOD 523>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 523>; #pwm-cells = <2>; status = "disabled"; }; @@ -921,6 +1023,7 @@ reg = <0 0xe6e32000 0 0x8>; clocks = <&cpg CPG_MOD 523>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 523>; #pwm-cells = <2>; status = "disabled"; }; @@ -930,6 +1033,7 @@ reg = <0 0xe6e33000 0 0x8>; clocks = <&cpg CPG_MOD 523>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 523>; #pwm-cells = <2>; status = "disabled"; }; @@ -939,6 +1043,7 @@ reg = <0 0xe6e34000 0 0x8>; clocks = <&cpg CPG_MOD 523>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 523>; #pwm-cells = <2>; status = "disabled"; }; @@ -948,6 +1053,7 @@ reg = <0 0xe6e35000 0 0x8>; clocks = <&cpg CPG_MOD 523>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 523>; #pwm-cells = <2>; status = "disabled"; }; @@ -957,6 +1063,7 @@ reg = <0 0xe6e36000 0 0x8>; clocks = <&cpg CPG_MOD 523>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 523>; #pwm-cells = <2>; status = "disabled"; }; @@ -1015,11 +1122,11 @@ rcar_sound,dvc { dvc0: dvc-0 { - dmas = <&audma0 0xbc>; + dmas = <&audma1 0xbc>; dma-names = "tx"; }; dvc1: dvc-1 { - dmas = <&audma0 0xbe>; + dmas = <&audma1 0xbe>; dma-names = "tx"; }; }; @@ -1149,10 +1256,11 @@ sata: sata@ee300000 { compatible = "renesas,sata-r8a7795"; - reg = <0 0xee300000 0 0x1fff>; + reg = <0 0xee300000 0 0x200000>; interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 815>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 815>; status = "disabled"; }; @@ -1162,6 +1270,7 @@ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 328>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 328>; status = "disabled"; }; @@ -1171,6 +1280,7 @@ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 327>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 327>; status = "disabled"; }; @@ -1183,6 +1293,7 @@ interrupt-names = "ch0", "ch1"; clocks = <&cpg CPG_MOD 330>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 330>; #dma-cells = <1>; dma-channels = <2>; }; @@ -1196,6 +1307,7 @@ interrupt-names = "ch0", "ch1"; clocks = <&cpg CPG_MOD 331>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 331>; #dma-cells = <1>; dma-channels = <2>; }; @@ -1207,6 +1319,7 @@ clocks = <&cpg CPG_MOD 314>; max-frequency = <200000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 314>; status = "disabled"; }; @@ -1217,6 +1330,7 @@ clocks = <&cpg CPG_MOD 313>; max-frequency = <200000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 313>; status = "disabled"; }; @@ -1227,6 +1341,7 @@ clocks = <&cpg CPG_MOD 312>; max-frequency = <200000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 312>; status = "disabled"; }; @@ -1237,6 +1352,7 @@ clocks = <&cpg CPG_MOD 311>; max-frequency = <200000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 311>; status = "disabled"; }; @@ -1247,6 +1363,7 @@ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 703>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 703>; #phy-cells = <0>; status = "disabled"; }; @@ -1257,6 +1374,7 @@ reg = <0 0xee0a0200 0 0x700>; clocks = <&cpg CPG_MOD 702>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 702>; #phy-cells = <0>; status = "disabled"; }; @@ -1267,6 +1385,7 @@ reg = <0 0xee0c0200 0 0x700>; clocks = <&cpg CPG_MOD 701>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 701>; #phy-cells = <0>; status = "disabled"; }; @@ -1279,6 +1398,7 @@ phys = <&usb2_phy0>; phy-names = "usb"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 703>; status = "disabled"; }; @@ -1290,6 +1410,7 @@ phys = <&usb2_phy1>; phy-names = "usb"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 702>; status = "disabled"; }; @@ -1301,6 +1422,7 @@ phys = <&usb2_phy2>; phy-names = "usb"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 701>; status = "disabled"; }; @@ -1312,6 +1434,7 @@ phys = <&usb2_phy0>; phy-names = "usb"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 703>; status = "disabled"; }; @@ -1323,6 +1446,7 @@ phys = <&usb2_phy1>; phy-names = "usb"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 702>; status = "disabled"; }; @@ -1334,6 +1458,7 @@ phys = <&usb2_phy2>; phy-names = "usb"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 701>; status = "disabled"; }; @@ -1350,6 +1475,7 @@ phys = <&usb2_phy0>; phy-names = "usb"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 704>; status = "disabled"; }; @@ -1376,6 +1502,7 @@ clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>; clock-names = "pcie", "pcie_bus"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 319>; status = "disabled"; }; @@ -1402,6 +1529,7 @@ clocks = <&cpg CPG_MOD 318>, <&pcie_bus_clk>; clock-names = "pcie", "pcie_bus"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 318>; status = "disabled"; }; @@ -1411,6 +1539,7 @@ interrupts = <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 624>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 624>; renesas,fcp = <&fcpvb1>; }; @@ -1420,6 +1549,7 @@ reg = <0 0xfe92f000 0 0x200>; clocks = <&cpg CPG_MOD 606>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 606>; }; fcpf0: fcp@fe950000 { @@ -1427,6 +1557,7 @@ reg = <0 0xfe950000 0 0x200>; clocks = <&cpg CPG_MOD 615>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 615>; }; fcpf1: fcp@fe951000 { @@ -1434,6 +1565,7 @@ reg = <0 0xfe951000 0 0x200>; clocks = <&cpg CPG_MOD 614>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 614>; }; fcpf2: fcp@fe952000 { @@ -1441,6 +1573,7 @@ reg = <0 0xfe952000 0 0x200>; clocks = <&cpg CPG_MOD 613>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 613>; }; vspbd: vsp@fe960000 { @@ -1449,6 +1582,7 @@ interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 626>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 626>; renesas,fcp = <&fcpvb0>; }; @@ -1458,6 +1592,7 @@ reg = <0 0xfe96f000 0 0x200>; clocks = <&cpg CPG_MOD 607>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 607>; }; vspi0: vsp@fe9a0000 { @@ -1466,6 +1601,7 @@ interrupts = <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 631>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 631>; renesas,fcp = <&fcpvi0>; }; @@ -1475,6 +1611,7 @@ reg = <0 0xfe9af000 0 0x200>; clocks = <&cpg CPG_MOD 611>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 611>; }; vspi1: vsp@fe9b0000 { @@ -1483,6 +1620,7 @@ interrupts = <GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 630>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 630>; renesas,fcp = <&fcpvi1>; }; @@ -1492,6 +1630,7 @@ reg = <0 0xfe9bf000 0 0x200>; clocks = <&cpg CPG_MOD 610>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 610>; }; vspi2: vsp@fe9c0000 { @@ -1500,6 +1639,7 @@ interrupts = <GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 629>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 629>; renesas,fcp = <&fcpvi2>; }; @@ -1509,6 +1649,7 @@ reg = <0 0xfe9cf000 0 0x200>; clocks = <&cpg CPG_MOD 609>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 609>; }; vspd0: vsp@fea20000 { @@ -1517,6 +1658,7 @@ interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 623>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 623>; renesas,fcp = <&fcpvd0>; }; @@ -1526,6 +1668,7 @@ reg = <0 0xfea27000 0 0x200>; clocks = <&cpg CPG_MOD 603>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 603>; }; vspd1: vsp@fea28000 { @@ -1534,6 +1677,7 @@ interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 622>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 622>; renesas,fcp = <&fcpvd1>; }; @@ -1543,6 +1687,7 @@ reg = <0 0xfea2f000 0 0x200>; clocks = <&cpg CPG_MOD 602>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 602>; }; vspd2: vsp@fea30000 { @@ -1551,6 +1696,7 @@ interrupts = <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 621>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 621>; renesas,fcp = <&fcpvd2>; }; @@ -1560,6 +1706,7 @@ reg = <0 0xfea37000 0 0x200>; clocks = <&cpg CPG_MOD 601>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 601>; }; vspd3: vsp@fea38000 { @@ -1568,6 +1715,7 @@ interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 620>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 620>; renesas,fcp = <&fcpvd3>; }; @@ -1577,6 +1725,7 @@ reg = <0 0xfea3f000 0 0x200>; clocks = <&cpg CPG_MOD 600>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 600>; }; fdp1@fe940000 { @@ -1585,6 +1734,7 @@ interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 119>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 119>; renesas,fcp = <&fcpf0>; }; @@ -1594,6 +1744,7 @@ interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 118>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 118>; renesas,fcp = <&fcpf1>; }; @@ -1603,6 +1754,7 @@ interrupts = <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 117>; power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 117>; renesas,fcp = <&fcpf2>; }; @@ -1662,6 +1814,7 @@ <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 522>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 522>; #thermal-sensor-cells = <1>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts index c3f064ac2cb4..372b2a944716 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts +++ b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts @@ -180,7 +180,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &wdt0 { diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts index c7f40f8f3169..c9f59b6ce33f 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts @@ -18,6 +18,7 @@ aliases { serial0 = &scif2; + serial1 = &scif1; ethernet0 = &avb; }; @@ -113,6 +114,11 @@ function = "avb"; }; + scif1_pins: scif1 { + groups = "scif1_data_a", "scif1_ctrl"; + function = "scif1"; + }; + scif2_pins: scif2 { groups = "scif2_data_a"; function = "scif2"; @@ -172,18 +178,7 @@ status = "okay"; phy0: ethernet-phy@0 { - rxc-skew-ps = <900>; - rxdv-skew-ps = <0>; - rxd0-skew-ps = <0>; - rxd1-skew-ps = <0>; - rxd2-skew-ps = <0>; - rxd3-skew-ps = <0>; - txc-skew-ps = <900>; - txen-skew-ps = <0>; - txd0-skew-ps = <0>; - txd1-skew-ps = <0>; - txd2-skew-ps = <0>; - txd3-skew-ps = <0>; + rxc-skew-ps = <1500>; reg = <0>; interrupt-parent = <&gpio2>; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; @@ -239,6 +234,14 @@ status = "okay"; }; +&scif1 { + pinctrl-0 = <&scif1_pins>; + pinctrl-names = "default"; + + uart-has-rtscts; + status = "okay"; +}; + &scif2 { pinctrl-0 = <&scif2_pins>; pinctrl-names = "default"; @@ -247,7 +250,6 @@ &scif_clk { clock-frequency = <14745600>; - status = "okay"; }; &i2c2 { @@ -261,3 +263,7 @@ timeout-sec = <60>; status = "okay"; }; + +&i2c_dvfs { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index f7120cdedd0d..2ec1ed5f4991 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -25,10 +25,11 @@ i2c4 = &i2c4; i2c5 = &i2c5; i2c6 = &i2c6; + i2c7 = &i2c_dvfs; }; psci { - compatible = "arm,psci-0.2"; + compatible = "arm,psci-1.0", "arm,psci-0.2"; method = "smc"; }; @@ -36,7 +37,6 @@ #address-cells = <1>; #size-cells = <0>; - /* 1 core only at this point */ a57_0: cpu@0 { compatible = "arm,cortex-a57", "arm,armv8"; reg = <0x0>; @@ -46,13 +46,64 @@ enable-method = "psci"; }; - L2_CA57: cache-controller@0 { + a57_1: cpu@1 { + compatible = "arm,cortex-a57","arm,armv8"; + reg = <0x1>; + device_type = "cpu"; + power-domains = <&sysc R8A7796_PD_CA57_CPU1>; + next-level-cache = <&L2_CA57>; + enable-method = "psci"; + }; + + a53_0: cpu@100 { + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x100>; + device_type = "cpu"; + power-domains = <&sysc R8A7796_PD_CA53_CPU0>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + a53_1: cpu@101 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x101>; + device_type = "cpu"; + power-domains = <&sysc R8A7796_PD_CA53_CPU1>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + a53_2: cpu@102 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x102>; + device_type = "cpu"; + power-domains = <&sysc R8A7796_PD_CA53_CPU2>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + a53_3: cpu@103 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x103>; + device_type = "cpu"; + power-domains = <&sysc R8A7796_PD_CA53_CPU3>; + next-level-cache = <&L2_CA53>; + enable-method = "psci"; + }; + + L2_CA57: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7796_PD_CA57_SCU>; cache-unified; cache-level = <2>; }; + + L2_CA53: cache-controller-1 { + compatible = "cache"; + power-domains = <&sysc R8A7796_PD_CA53_SCU>; + cache-unified; + cache-level = <2>; + }; }; extal_clk: extal { @@ -100,22 +151,23 @@ <0x0 0xf1040000 0 0x20000>, <0x0 0xf1060000 0 0x20000>; interrupts = <GIC_PPI 9 - (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>; + (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>; clocks = <&cpg CPG_MOD 408>; clock-names = "clk"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 408>; }; timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 - (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, + (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 14 - (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, + (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 - (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, + (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 10 - (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>; + (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>; }; wdt0: watchdog@e6020000 { @@ -124,6 +176,7 @@ reg = <0 0xe6020000 0 0x0c>; clocks = <&cpg CPG_MOD 402>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 402>; status = "disabled"; }; @@ -139,6 +192,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 912>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 912>; }; gpio1: gpio@e6051000 { @@ -153,6 +207,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 911>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 911>; }; gpio2: gpio@e6052000 { @@ -167,6 +222,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 910>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 910>; }; gpio3: gpio@e6053000 { @@ -181,6 +237,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 909>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 909>; }; gpio4: gpio@e6054000 { @@ -195,6 +252,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 908>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 908>; }; gpio5: gpio@e6055000 { @@ -209,6 +267,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 907>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 907>; }; gpio6: gpio@e6055400 { @@ -223,6 +282,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 906>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 906>; }; gpio7: gpio@e6055800 { @@ -237,6 +297,7 @@ interrupt-controller; clocks = <&cpg CPG_MOD 905>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 905>; }; pfc: pin-controller@e6060000 { @@ -244,6 +305,26 @@ reg = <0 0xe6060000 0 0x50c>; }; + pmu_a57 { + compatible = "arm,cortex-a57-pmu"; + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; + interrupt-affinity = <&a57_0>, + <&a57_1>; + }; + + pmu_a53 { + compatible = "arm,cortex-a53-pmu"; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; + interrupt-affinity = <&a53_0>, + <&a53_1>, + <&a53_2>, + <&a53_3>; + }; + cpg: clock-controller@e6150000 { compatible = "renesas,r8a7796-cpg-mssr"; reg = <0 0xe6150000 0 0x1000>; @@ -251,6 +332,7 @@ clock-names = "extal", "extalr"; #clock-cells = <2>; #power-domain-cells = <0>; + #reset-cells = <1>; }; rst: reset-controller@e6160000 { @@ -269,6 +351,20 @@ #power-domain-cells = <1>; }; + i2c_dvfs: i2c@e60b0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7796", + "renesas,rcar-gen3-iic", + "renesas,rmobile-iic"; + reg = <0 0xe60b0000 0 0x425>; + interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 926>; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 926>; + status = "disabled"; + }; + i2c0: i2c@e6500000 { #address-cells = <1>; #size-cells = <0>; @@ -278,6 +374,7 @@ interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 931>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 931>; dmas = <&dmac1 0x91>, <&dmac1 0x90>, <&dmac2 0x91>, <&dmac2 0x90>; dma-names = "tx", "rx", "tx", "rx"; @@ -294,6 +391,7 @@ interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 930>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 930>; dmas = <&dmac1 0x93>, <&dmac1 0x92>, <&dmac2 0x93>, <&dmac2 0x92>; dma-names = "tx", "rx", "tx", "rx"; @@ -310,6 +408,7 @@ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 929>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 929>; dmas = <&dmac1 0x95>, <&dmac1 0x94>, <&dmac2 0x95>, <&dmac2 0x94>; dma-names = "tx", "rx", "tx", "rx"; @@ -326,6 +425,7 @@ interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 928>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 928>; dmas = <&dmac0 0x97>, <&dmac0 0x96>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <110>; @@ -341,6 +441,7 @@ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 927>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 927>; dmas = <&dmac0 0x99>, <&dmac0 0x98>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <110>; @@ -356,6 +457,7 @@ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 919>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 919>; dmas = <&dmac0 0x9b>, <&dmac0 0x9a>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <110>; @@ -371,6 +473,7 @@ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 918>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 918>; dmas = <&dmac0 0x9d>, <&dmac0 0x9c>; dma-names = "tx", "rx"; i2c-scl-internal-delay-ns = <6>; @@ -389,6 +492,7 @@ assigned-clocks = <&cpg CPG_CORE R8A7796_CLK_CANFD>; assigned-clock-rates = <40000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 916>; status = "disabled"; }; @@ -404,6 +508,7 @@ assigned-clocks = <&cpg CPG_CORE R8A7796_CLK_CANFD>; assigned-clock-rates = <40000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 915>; status = "disabled"; }; @@ -420,6 +525,7 @@ assigned-clocks = <&cpg CPG_CORE R8A7796_CLK_CANFD>; assigned-clock-rates = <40000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 914>; status = "disabled"; channel0 { @@ -469,12 +575,135 @@ "ch24"; clocks = <&cpg CPG_MOD 812>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; - phy-mode = "rgmii-id"; + resets = <&cpg 812>; + phy-mode = "rgmii-txid"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; + hscif0: serial@e6540000 { + compatible = "renesas,hscif-r8a7796", + "renesas,rcar-gen3-hscif", + "renesas,hscif"; + reg = <0 0xe6540000 0 0x60>; + interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 520>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac1 0x31>, <&dmac1 0x30>, + <&dmac2 0x31>, <&dmac2 0x30>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 520>; + status = "disabled"; + }; + + hscif1: serial@e6550000 { + compatible = "renesas,hscif-r8a7796", + "renesas,rcar-gen3-hscif", + "renesas,hscif"; + reg = <0 0xe6550000 0 0x60>; + interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 519>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac1 0x33>, <&dmac1 0x32>, + <&dmac2 0x33>, <&dmac2 0x32>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 519>; + status = "disabled"; + }; + + hscif2: serial@e6560000 { + compatible = "renesas,hscif-r8a7796", + "renesas,rcar-gen3-hscif", + "renesas,hscif"; + reg = <0 0xe6560000 0 0x60>; + interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 518>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac1 0x35>, <&dmac1 0x34>, + <&dmac2 0x35>, <&dmac2 0x34>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 518>; + status = "disabled"; + }; + + hscif3: serial@e66a0000 { + compatible = "renesas,hscif-r8a7796", + "renesas,rcar-gen3-hscif", + "renesas,hscif"; + reg = <0 0xe66a0000 0 0x60>; + interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 517>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x37>, <&dmac0 0x36>; + dma-names = "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 517>; + status = "disabled"; + }; + + hscif4: serial@e66b0000 { + compatible = "renesas,hscif-r8a7796", + "renesas,rcar-gen3-hscif", + "renesas,hscif"; + reg = <0 0xe66b0000 0 0x60>; + interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 516>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x39>, <&dmac0 0x38>; + dma-names = "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 516>; + status = "disabled"; + }; + + scif0: serial@e6e60000 { + compatible = "renesas,scif-r8a7796", + "renesas,rcar-gen3-scif", "renesas,scif"; + reg = <0 0xe6e60000 0 64>; + interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 207>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac1 0x51>, <&dmac1 0x50>, + <&dmac2 0x51>, <&dmac2 0x50>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 207>; + status = "disabled"; + }; + + scif1: serial@e6e68000 { + compatible = "renesas,scif-r8a7796", + "renesas,rcar-gen3-scif", "renesas,scif"; + reg = <0 0xe6e68000 0 64>; + interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 206>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac1 0x53>, <&dmac1 0x52>, + <&dmac2 0x53>, <&dmac2 0x52>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 206>; + status = "disabled"; + }; + scif2: serial@e6e88000 { compatible = "renesas,scif-r8a7796", "renesas,rcar-gen3-scif", "renesas,scif"; @@ -485,6 +714,56 @@ <&scif_clk>; clock-names = "fck", "brg_int", "scif_clk"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 310>; + status = "disabled"; + }; + + scif3: serial@e6c50000 { + compatible = "renesas,scif-r8a7796", + "renesas,rcar-gen3-scif", "renesas,scif"; + reg = <0 0xe6c50000 0 64>; + interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 204>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x57>, <&dmac0 0x56>; + dma-names = "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 204>; + status = "disabled"; + }; + + scif4: serial@e6c40000 { + compatible = "renesas,scif-r8a7796", + "renesas,rcar-gen3-scif", "renesas,scif"; + reg = <0 0xe6c40000 0 64>; + interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 203>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x59>, <&dmac0 0x58>; + dma-names = "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 203>; + status = "disabled"; + }; + + scif5: serial@e6f30000 { + compatible = "renesas,scif-r8a7796", + "renesas,rcar-gen3-scif", "renesas,scif"; + reg = <0 0xe6f30000 0 64>; + interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 202>, + <&cpg CPG_CORE R8A7796_CLK_S3D1>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac1 0x5b>, <&dmac1 0x5a>, + <&dmac2 0x5b>, <&dmac2 0x5a>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 202>; status = "disabled"; }; @@ -498,6 +777,7 @@ <&dmac2 0x41>, <&dmac2 0x40>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 211>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -513,6 +793,7 @@ <&dmac2 0x43>, <&dmac2 0x42>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 210>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -527,6 +808,7 @@ dmas = <&dmac0 0x45>, <&dmac0 0x44>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 209>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -541,6 +823,7 @@ dmas = <&dmac0 0x47>, <&dmac0 0x46>; dma-names = "tx", "rx"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 208>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -575,6 +858,7 @@ clocks = <&cpg CPG_MOD 219>; clock-names = "fck"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 219>; #dma-cells = <1>; dma-channels = <16>; }; @@ -608,6 +892,7 @@ clocks = <&cpg CPG_MOD 218>; clock-names = "fck"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 218>; #dma-cells = <1>; dma-channels = <16>; }; @@ -641,6 +926,7 @@ clocks = <&cpg CPG_MOD 217>; clock-names = "fck"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 217>; #dma-cells = <1>; dma-channels = <16>; }; @@ -652,6 +938,7 @@ clocks = <&cpg CPG_MOD 314>; max-frequency = <200000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 314>; status = "disabled"; }; @@ -662,6 +949,7 @@ clocks = <&cpg CPG_MOD 313>; max-frequency = <200000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 313>; status = "disabled"; }; @@ -672,6 +960,7 @@ clocks = <&cpg CPG_MOD 312>; max-frequency = <200000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 312>; status = "disabled"; }; @@ -682,6 +971,7 @@ clocks = <&cpg CPG_MOD 311>; max-frequency = <200000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 311>; status = "disabled"; }; @@ -695,6 +985,7 @@ <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cpg CPG_MOD 522>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 522>; #thermal-sensor-cells = <1>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 3a862894ea44..b5636bba6b1c 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -1,9 +1,11 @@ +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-evb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-evb-act8846.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-geekbox.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-orion-r68-meta.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-evb.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-kevin.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts new file mode 100644 index 000000000000..cf272392cebf --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "rk3328.dtsi" + +/ { + model = "Rockchip RK3328 EVB"; + compatible = "rockchip,rk3328-evb", "rockchip,rk3328"; + + chosen { + stdout-path = "serial2:1500000n8"; + }; +}; + +&uart2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi new file mode 100644 index 000000000000..7e69f1fe78d6 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -0,0 +1,1264 @@ +/* + * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/clock/rk3328-cru.h> +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/pinctrl/rockchip.h> +#include <dt-bindings/power/rk3328-power.h> +#include <dt-bindings/soc/rockchip,boot-mode.h> + +/ { + compatible = "rockchip,rk3328"; + + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x0>; + clocks = <&cru ARMCLK>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x1>; + clocks = <&cru ARMCLK>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x2>; + clocks = <&cru ARMCLK>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x3>; + clocks = <&cru ARMCLK>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + l2: l2-cache0 { + compatible = "cache"; + }; + }; + + amba { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dmac: dmac@ff1f0000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0xff1f0000 0x0 0x4000>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + #dma-cells = <1>; + }; + }; + + arm-pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + }; + + xin24m: xin24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "xin24m"; + }; + + grf: syscon@ff100000 { + compatible = "rockchip,rk3328-grf", "syscon", "simple-mfd"; + reg = <0x0 0xff100000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + power: power-controller { + compatible = "rockchip,rk3328-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + pd_hevc@RK3328_PD_HEVC { + reg = <RK3328_PD_HEVC>; + }; + pd_video@RK3328_PD_VIDEO { + reg = <RK3328_PD_VIDEO>; + }; + pd_vpu@RK3328_PD_VPU { + reg = <RK3328_PD_VPU>; + }; + }; + + reboot-mode { + compatible = "syscon-reboot-mode"; + offset = <0x5c8>; + mode-normal = <BOOT_NORMAL>; + mode-recovery = <BOOT_RECOVERY>; + mode-bootloader = <BOOT_FASTBOOT>; + mode-loader = <BOOT_BL_DOWNLOAD>; + }; + + }; + + uart0: serial@ff110000 { + compatible = "rockchip,rk3328-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff110000 0x0 0x100>; + interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac 2>, <&dmac 3>; + #dma-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart1: serial@ff120000 { + compatible = "rockchip,rk3328-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff120000 0x0 0x100>; + interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; + clock-names = "sclk_uart", "pclk_uart"; + dmas = <&dmac 4>, <&dmac 5>; + #dma-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_xfer &uart1_cts &uart1_rts>; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart2: serial@ff130000 { + compatible = "rockchip,rk3328-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff130000 0x0 0x100>; + interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac 6>, <&dmac 7>; + #dma-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&uart2m1_xfer>; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + i2c0: i2c@ff150000 { + compatible = "rockchip,rk3328-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xff150000 0x0 0x1000>; + interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cru SCLK_I2C0>, <&cru PCLK_I2C0>; + clock-names = "i2c", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_xfer>; + status = "disabled"; + }; + + i2c1: i2c@ff160000 { + compatible = "rockchip,rk3328-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xff160000 0x0 0x1000>; + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>; + clock-names = "i2c", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_xfer>; + status = "disabled"; + }; + + i2c2: i2c@ff170000 { + compatible = "rockchip,rk3328-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xff170000 0x0 0x1000>; + interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>; + clock-names = "i2c", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_xfer>; + status = "disabled"; + }; + + i2c3: i2c@ff180000 { + compatible = "rockchip,rk3328-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xff180000 0x0 0x1000>; + interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>; + clock-names = "i2c", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_xfer>; + status = "disabled"; + }; + + spi0: spi@ff190000 { + compatible = "rockchip,rk3328-spi", "rockchip,rk3066-spi"; + reg = <0x0 0xff190000 0x0 0x1000>; + interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cru SCLK_SPI>, <&cru PCLK_SPI>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac 8>, <&dmac 9>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0m2_clk &spi0m2_tx &spi0m2_rx &spi0m2_cs0>; + status = "disabled"; + }; + + wdt: watchdog@ff1a0000 { + compatible = "snps,dw-wdt"; + reg = <0x0 0xff1a0000 0x0 0x100>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + }; + + saradc: adc@ff280000 { + compatible = "rockchip,rk3328-saradc", "rockchip,rk3399-saradc"; + reg = <0x0 0xff280000 0x0 0x100>; + interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>; + #io-channel-cells = <1>; + clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>; + clock-names = "saradc", "apb_pclk"; + resets = <&cru SRST_SARADC_P>; + reset-names = "saradc-apb"; + status = "disabled"; + }; + + cru: clock-controller@ff440000 { + compatible = "rockchip,rk3328-cru", "rockchip,cru", "syscon"; + reg = <0x0 0xff440000 0x0 0x1000>; + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; + assigned-clocks = + /* + * CPLL should run at 1200, but that is to high for + * the initial dividers of most of its children. + * We need set cpll child clk div first, + * and then set the cpll frequency. + */ + <&cru DCLK_LCDC>, <&cru SCLK_PDM>, + <&cru SCLK_RTC32K>, <&cru SCLK_UART0>, + <&cru SCLK_UART1>, <&cru SCLK_UART2>, + <&cru ACLK_BUS_PRE>, <&cru ACLK_PERI_PRE>, + <&cru ACLK_VIO_PRE>, <&cru ACLK_RGA_PRE>, + <&cru ACLK_VOP_PRE>, <&cru ACLK_RKVDEC_PRE>, + <&cru ACLK_RKVENC>, <&cru ACLK_VPU_PRE>, + <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>, + <&cru SCLK_VENC_CORE>, <&cru SCLK_VENC_DSP>, + <&cru SCLK_SDIO>, <&cru SCLK_TSP>, + <&cru SCLK_WIFI>, <&cru ARMCLK>, + <&cru PLL_GPLL>, <&cru PLL_CPLL>, + <&cru ACLK_BUS_PRE>, <&cru HCLK_BUS_PRE>, + <&cru PCLK_BUS_PRE>, <&cru ACLK_PERI_PRE>, + <&cru HCLK_PERI>, <&cru PCLK_PERI>, + <&cru SCLK_RTC32K>; + assigned-clock-parents = + <&cru HDMIPHY>, <&cru PLL_APLL>, + <&cru PLL_GPLL>, <&xin24m>, + <&xin24m>, <&xin24m>; + assigned-clock-rates = + <0>, <61440000>, + <0>, <24000000>, + <24000000>, <24000000>, + <15000000>, <15000000>, + <100000000>, <100000000>, + <100000000>, <100000000>, + <50000000>, <100000000>, + <100000000>, <100000000>, + <50000000>, <50000000>, + <50000000>, <50000000>, + <24000000>, <600000000>, + <491520000>, <1200000000>, + <150000000>, <75000000>, + <75000000>, <150000000>, + <75000000>, <75000000>, + <32768>; + }; + + gmac2io: ethernet@ff540000 { + compatible = "rockchip,rk3328-gmac"; + reg = <0x0 0xff540000 0x0 0x10000>; + interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_RX>, + <&cru SCLK_MAC2IO_TX>, <&cru SCLK_MAC2IO_REF>, + <&cru SCLK_MAC2IO_REFOUT>, <&cru ACLK_MAC2IO>, + <&cru PCLK_MAC2IO>; + clock-names = "stmmaceth", "mac_clk_rx", + "mac_clk_tx", "clk_mac_ref", + "clk_mac_refout", "aclk_mac", + "pclk_mac"; + resets = <&cru SRST_GMAC2IO_A>; + reset-names = "stmmaceth"; + rockchip,grf = <&grf>; + status = "disabled"; + }; + + gic: interrupt-controller@ff811000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x0 0xff811000 0 0x1000>, + <0x0 0xff812000 0 0x2000>, + <0x0 0xff814000 0 0x2000>, + <0x0 0xff816000 0 0x2000>; + interrupts = <GIC_PPI 9 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + + pinctrl: pinctrl { + compatible = "rockchip,rk3328-pinctrl"; + rockchip,grf = <&grf>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gpio0: gpio0@ff210000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xff210000 0x0 0x100>; + interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO0>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio1@ff220000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xff220000 0x0 0x100>; + interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO1>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio2@ff230000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xff230000 0x0 0x100>; + interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO2>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio3@ff240000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xff240000 0x0 0x100>; + interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO3>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + pcfg_pull_up: pcfg-pull-up { + bias-pull-up; + }; + + pcfg_pull_down: pcfg-pull-down { + bias-pull-down; + }; + + pcfg_pull_none: pcfg-pull-none { + bias-disable; + }; + + pcfg_pull_none_2ma: pcfg-pull-none-2ma { + bias-disable; + drive-strength = <2>; + }; + + pcfg_pull_up_2ma: pcfg-pull-up-2ma { + bias-pull-up; + drive-strength = <2>; + }; + + pcfg_pull_up_4ma: pcfg-pull-up-4ma { + bias-pull-up; + drive-strength = <4>; + }; + + pcfg_pull_none_4ma: pcfg-pull-none-4ma { + bias-disable; + drive-strength = <4>; + }; + + pcfg_pull_down_4ma: pcfg-pull-down-4ma { + bias-pull-down; + drive-strength = <4>; + }; + + pcfg_pull_none_8ma: pcfg-pull-none-8ma { + bias-disable; + drive-strength = <8>; + }; + + pcfg_pull_up_8ma: pcfg-pull-up-8ma { + bias-pull-up; + drive-strength = <8>; + }; + + pcfg_pull_none_12ma: pcfg-pull-none-12ma { + bias-disable; + drive-strength = <12>; + }; + + pcfg_pull_up_12ma: pcfg-pull-up-12ma { + bias-pull-up; + drive-strength = <12>; + }; + + pcfg_output_high: pcfg-output-high { + output-high; + }; + + pcfg_output_low: pcfg-output-low { + output-low; + }; + + pcfg_input_high: pcfg-input-high { + bias-pull-up; + input-enable; + }; + + pcfg_input: pcfg-input { + input-enable; + }; + + i2c0 { + i2c0_xfer: i2c0-xfer { + rockchip,pins = <2 RK_PD0 1 &pcfg_pull_none>, + <2 RK_PD1 1 &pcfg_pull_none>; + }; + }; + + i2c1 { + i2c1_xfer: i2c1-xfer { + rockchip,pins = <2 RK_PA4 2 &pcfg_pull_none>, + <2 RK_PA5 2 &pcfg_pull_none>; + }; + }; + + i2c2 { + i2c2_xfer: i2c2-xfer { + rockchip,pins = <2 RK_PB5 1 &pcfg_pull_none>, + <2 RK_PB6 1 &pcfg_pull_none>; + }; + }; + + i2c3 { + i2c3_xfer: i2c3-xfer { + rockchip,pins = <0 RK_PA5 2 &pcfg_pull_none>, + <0 RK_PA6 2 &pcfg_pull_none>; + }; + i2c3_gpio: i2c3-gpio { + rockchip,pins = + <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, + <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + hdmi_i2c { + hdmii2c_xfer: hdmii2c-xfer { + rockchip,pins = <0 RK_PA5 1 &pcfg_pull_none>, + <0 RK_PA6 1 &pcfg_pull_none>; + }; + }; + + tsadc { + otp_gpio: otp-gpio { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + otp_out: otp-out { + rockchip,pins = <2 RK_PB5 1 &pcfg_pull_none>; + }; + }; + + uart0 { + uart0_xfer: uart0-xfer { + rockchip,pins = <1 RK_PB1 1 &pcfg_pull_up>, + <1 RK_PB0 1 &pcfg_pull_none>; + }; + + uart0_cts: uart0-cts { + rockchip,pins = <1 RK_PB3 1 &pcfg_pull_none>; + }; + + uart0_rts: uart0-rts { + rockchip,pins = <1 RK_PB2 1 &pcfg_pull_none>; + }; + + uart0_rts_gpio: uart0-rts-gpio { + rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + uart1 { + uart1_xfer: uart1-xfer { + rockchip,pins = <3 RK_PA4 4 &pcfg_pull_up>, + <3 RK_PA6 4 &pcfg_pull_none>; + }; + + uart1_cts: uart1-cts { + rockchip,pins = <3 RK_PA7 4 &pcfg_pull_none>; + }; + + uart1_rts: uart1-rts { + rockchip,pins = <3 RK_PA5 4 &pcfg_pull_none>; + }; + + uart1_rts_gpio: uart1-rts-gpio { + rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + uart2-0 { + uart2m0_xfer: uart2m0-xfer { + rockchip,pins = <1 RK_PA0 2 &pcfg_pull_up>, + <1 RK_PA1 2 &pcfg_pull_none>; + }; + }; + + uart2-1 { + uart2m1_xfer: uart2m1-xfer { + rockchip,pins = <2 RK_PA0 1 &pcfg_pull_up>, + <2 RK_PA1 1 &pcfg_pull_none>; + }; + }; + + spi0-0 { + spi0m0_clk: spi0m0-clk { + rockchip,pins = <2 RK_PB0 1 &pcfg_pull_up>; + }; + + spi0m0_cs0: spi0m0-cs0 { + rockchip,pins = <2 RK_PB3 1 &pcfg_pull_up>; + }; + + spi0m0_tx: spi0m0-tx { + rockchip,pins = <2 RK_PB1 1 &pcfg_pull_up>; + }; + + spi0m0_rx: spi0m0-rx { + rockchip,pins = <2 RK_PB2 1 &pcfg_pull_up>; + }; + + spi0m0_cs1: spi0m0-cs1 { + rockchip,pins = <2 RK_PB4 1 &pcfg_pull_up>; + }; + }; + + spi0-1 { + spi0m1_clk: spi0m1-clk { + rockchip,pins = <3 RK_PC7 2 &pcfg_pull_up>; + }; + + spi0m1_cs0: spi0m1-cs0 { + rockchip,pins = <3 RK_PD2 2 &pcfg_pull_up>; + }; + + spi0m1_tx: spi0m1-tx { + rockchip,pins = <3 RK_PD1 2 &pcfg_pull_up>; + }; + + spi0m1_rx: spi0m1-rx { + rockchip,pins = <3 RK_PD0 2 &pcfg_pull_up>; + }; + + spi0m1_cs1: spi0m1-cs1 { + rockchip,pins = <3 RK_PD3 2 &pcfg_pull_up>; + }; + }; + + spi0-2 { + spi0m2_clk: spi0m2-clk { + rockchip,pins = <3 RK_PA0 4 &pcfg_pull_up>; + }; + + spi0m2_cs0: spi0m2-cs0 { + rockchip,pins = <3 RK_PB0 3 &pcfg_pull_up>; + }; + + spi0m2_tx: spi0m2-tx { + rockchip,pins = <3 RK_PA1 4 &pcfg_pull_up>; + }; + + spi0m2_rx: spi0m2-rx { + rockchip,pins = <3 RK_PA2 4 &pcfg_pull_up>; + }; + }; + + i2s1 { + i2s1_mclk: i2s1-mclk { + rockchip,pins = <2 RK_PB7 1 &pcfg_pull_none>; + }; + + i2s1_sclk: i2s1-sclk { + rockchip,pins = <2 RK_PC2 1 &pcfg_pull_none>; + }; + + i2s1_lrckrx: i2s1-lrckrx { + rockchip,pins = <2 RK_PC0 1 &pcfg_pull_none>; + }; + + i2s1_lrcktx: i2s1-lrcktx { + rockchip,pins = <2 RK_PC1 1 &pcfg_pull_none>; + }; + + i2s1_sdi: i2s1-sdi { + rockchip,pins = <2 RK_PC3 1 &pcfg_pull_none>; + }; + + i2s1_sdo: i2s1-sdo { + rockchip,pins = <2 RK_PC7 1 &pcfg_pull_none>; + }; + + i2s1_sdio1: i2s1-sdio1 { + rockchip,pins = <2 RK_PC4 1 &pcfg_pull_none>; + }; + + i2s1_sdio2: i2s1-sdio2 { + rockchip,pins = <2 RK_PC5 1 &pcfg_pull_none>; + }; + + i2s1_sdio3: i2s1-sdio3 { + rockchip,pins = <2 RK_PC6 1 &pcfg_pull_none>; + }; + + i2s1_sleep: i2s1-sleep { + rockchip,pins = + <2 RK_PB7 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC0 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC1 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC2 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC3 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC4 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC5 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>, + <2 RK_PC7 RK_FUNC_GPIO &pcfg_input_high>; + }; + }; + + i2s2-0 { + i2s2m0_mclk: i2s2m0-mclk { + rockchip,pins = <1 RK_PC5 1 &pcfg_pull_none>; + }; + + i2s2m0_sclk: i2s2m0-sclk { + rockchip,pins = <1 RK_PC6 1 &pcfg_pull_none>; + }; + + i2s2m0_lrckrx: i2s2m0-lrckrx { + rockchip,pins = <1 RK_PD2 1 &pcfg_pull_none>; + }; + + i2s2m0_lrcktx: i2s2m0-lrcktx { + rockchip,pins = <1 RK_PC7 1 &pcfg_pull_none>; + }; + + i2s2m0_sdi: i2s2m0-sdi { + rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>; + }; + + i2s2m0_sdo: i2s2m0-sdo { + rockchip,pins = <1 RK_PD1 1 &pcfg_pull_none>; + }; + + i2s2m0_sleep: i2s2m0-sleep { + rockchip,pins = + <1 RK_PC5 RK_FUNC_GPIO &pcfg_input_high>, + <1 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>, + <1 RK_PD2 RK_FUNC_GPIO &pcfg_input_high>, + <1 RK_PC7 RK_FUNC_GPIO &pcfg_input_high>, + <1 RK_PD0 RK_FUNC_GPIO &pcfg_input_high>, + <1 RK_PD1 RK_FUNC_GPIO &pcfg_input_high>; + }; + }; + + i2s2-1 { + i2s2m1_mclk: i2s2m1-mclk { + rockchip,pins = <1 RK_PC5 1 &pcfg_pull_none>; + }; + + i2s2m1_sclk: i2s2m1-sclk { + rockchip,pins = <3 RK_PA0 6 &pcfg_pull_none>; + }; + + i2s2m1_lrckrx: i2sm1-lrckrx { + rockchip,pins = <3 RK_PB0 6 &pcfg_pull_none>; + }; + + i2s2m1_lrcktx: i2s2m1-lrcktx { + rockchip,pins = <3 RK_PB0 4 &pcfg_pull_none>; + }; + + i2s2m1_sdi: i2s2m1-sdi { + rockchip,pins = <3 RK_PA2 6 &pcfg_pull_none>; + }; + + i2s2m1_sdo: i2s2m1-sdo { + rockchip,pins = <3 RK_PA1 6 &pcfg_pull_none>; + }; + + i2s2m1_sleep: i2s2m1-sleep { + rockchip,pins = + <1 RK_PC5 RK_FUNC_GPIO &pcfg_input_high>, + <3 RK_PA0 RK_FUNC_GPIO &pcfg_input_high>, + <3 RK_PB0 RK_FUNC_GPIO &pcfg_input_high>, + <3 RK_PA2 RK_FUNC_GPIO &pcfg_input_high>, + <3 RK_PA1 RK_FUNC_GPIO &pcfg_input_high>; + }; + }; + + spdif-0 { + spdifm0_tx: spdifm0-tx { + rockchip,pins = <0 RK_PD3 1 &pcfg_pull_none>; + }; + }; + + spdif-1 { + spdifm1_tx: spdifm1-tx { + rockchip,pins = <2 RK_PC1 2 &pcfg_pull_none>; + }; + }; + + spdif-2 { + spdifm2_tx: spdifm2-tx { + rockchip,pins = <0 RK_PA2 2 &pcfg_pull_none>; + }; + }; + + sdmmc0-0 { + sdmmc0m0_pwren: sdmmc0m0-pwren { + rockchip,pins = <2 RK_PA7 1 &pcfg_pull_up_4ma>; + }; + + sdmmc0m0_gpio: sdmmc0m0-gpio { + rockchip,pins = <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; + + sdmmc0-1 { + sdmmc0m1_pwren: sdmmc0m1-pwren { + rockchip,pins = <0 RK_PD6 3 &pcfg_pull_up_4ma>; + }; + + sdmmc0m1_gpio: sdmmc0m1-gpio { + rockchip,pins = <0 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; + + sdmmc0 { + sdmmc0_clk: sdmmc0-clk { + rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none_4ma>; + }; + + sdmmc0_cmd: sdmmc0-cmd { + rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up_4ma>; + }; + + sdmmc0_dectn: sdmmc0-dectn { + rockchip,pins = <1 RK_PA5 1 &pcfg_pull_up_4ma>; + }; + + sdmmc0_wrprt: sdmmc0-wrprt { + rockchip,pins = <1 RK_PA7 1 &pcfg_pull_up_4ma>; + }; + + sdmmc0_bus1: sdmmc0-bus1 { + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>; + }; + + sdmmc0_bus4: sdmmc0-bus4 { + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>, + <1 RK_PA1 1 &pcfg_pull_up_4ma>, + <1 RK_PA2 1 &pcfg_pull_up_4ma>, + <1 RK_PA3 1 &pcfg_pull_up_4ma>; + }; + + sdmmc0_gpio: sdmmc0-gpio { + rockchip,pins = + <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; + + sdmmc0ext { + sdmmc0ext_clk: sdmmc0ext-clk { + rockchip,pins = <3 RK_PA2 3 &pcfg_pull_none_4ma>; + }; + + sdmmc0ext_cmd: sdmmc0ext-cmd { + rockchip,pins = <3 RK_PA0 3 &pcfg_pull_up_4ma>; + }; + + sdmmc0ext_wrprt: sdmmc0ext-wrprt { + rockchip,pins = <3 RK_PA3 3 &pcfg_pull_up_4ma>; + }; + + sdmmc0ext_dectn: sdmmc0ext-dectn { + rockchip,pins = <3 RK_PA1 3 &pcfg_pull_up_4ma>; + }; + + sdmmc0ext_bus1: sdmmc0ext-bus1 { + rockchip,pins = <3 RK_PA4 3 &pcfg_pull_up_4ma>; + }; + + sdmmc0ext_bus4: sdmmc0ext-bus4 { + rockchip,pins = + <3 RK_PA4 3 &pcfg_pull_up_4ma>, + <3 RK_PA5 3 &pcfg_pull_up_4ma>, + <3 RK_PA6 3 &pcfg_pull_up_4ma>, + <3 RK_PA7 3 &pcfg_pull_up_4ma>; + }; + + sdmmc0ext_gpio: sdmmc0ext-gpio { + rockchip,pins = + <3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; + + sdmmc1 { + sdmmc1_clk: sdmmc1-clk { + rockchip,pins = <1 RK_PB4 1 &pcfg_pull_none_8ma>; + }; + + sdmmc1_cmd: sdmmc1-cmd { + rockchip,pins = <1 RK_PB5 1 &pcfg_pull_up_8ma>; + }; + + sdmmc1_pwren: sdmmc1-pwren { + rockchip,pins = <1 RK_PC2 1 &pcfg_pull_up_8ma>; + }; + + sdmmc1_wrprt: sdmmc1-wrprt { + rockchip,pins = <1 RK_PC4 1 &pcfg_pull_up_8ma>; + }; + + sdmmc1_dectn: sdmmc1-dectn { + rockchip,pins = <1 RK_PC3 1 &pcfg_pull_up_8ma>; + }; + + sdmmc1_bus1: sdmmc1-bus1 { + rockchip,pins = <1 RK_PB6 1 &pcfg_pull_up_8ma>; + }; + + sdmmc1_bus4: sdmmc1-bus4 { + rockchip,pins = <1 RK_PB6 1 &pcfg_pull_up_8ma>, + <1 RK_PB7 1 &pcfg_pull_up_8ma>, + <1 RK_PC0 1 &pcfg_pull_up_8ma>, + <1 RK_PC1 1 &pcfg_pull_up_8ma>; + }; + + sdmmc1_gpio: sdmmc1-gpio { + rockchip,pins = + <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; + + emmc { + emmc_clk: emmc-clk { + rockchip,pins = <3 RK_PC5 2 &pcfg_pull_none_12ma>; + }; + + emmc_cmd: emmc-cmd { + rockchip,pins = <3 RK_PC3 2 &pcfg_pull_up_12ma>; + }; + + emmc_pwren: emmc-pwren { + rockchip,pins = <3 RK_PC6 2 &pcfg_pull_none>; + }; + + emmc_rstnout: emmc-rstnout { + rockchip,pins = <3 RK_PC4 2 &pcfg_pull_none>; + }; + + emmc_bus1: emmc-bus1 { + rockchip,pins = <0 RK_PA7 2 &pcfg_pull_up_12ma>; + }; + + emmc_bus4: emmc-bus4 { + rockchip,pins = + <0 RK_PA7 2 &pcfg_pull_up_12ma>, + <2 RK_PD4 2 &pcfg_pull_up_12ma>, + <2 RK_PD5 2 &pcfg_pull_up_12ma>, + <2 RK_PD6 2 &pcfg_pull_up_12ma>; + }; + + emmc_bus8: emmc-bus8 { + rockchip,pins = + <0 RK_PA7 2 &pcfg_pull_up_12ma>, + <2 RK_PD4 2 &pcfg_pull_up_12ma>, + <2 RK_PD5 2 &pcfg_pull_up_12ma>, + <2 RK_PD6 2 &pcfg_pull_up_12ma>, + <2 RK_PD7 2 &pcfg_pull_up_12ma>, + <3 RK_PC0 2 &pcfg_pull_up_12ma>, + <3 RK_PC1 2 &pcfg_pull_up_12ma>, + <3 RK_PC2 2 &pcfg_pull_up_12ma>; + }; + }; + + pwm0 { + pwm0_pin: pwm0-pin { + rockchip,pins = <2 RK_PA4 1 &pcfg_pull_none>; + }; + }; + + pwm1 { + pwm1_pin: pwm1-pin { + rockchip,pins = <2 RK_PA5 1 &pcfg_pull_none>; + }; + }; + + pwm2 { + pwm2_pin: pwm2-pin { + rockchip,pins = <2 RK_PA6 1 &pcfg_pull_none>; + }; + }; + + pwmir { + pwmir_pin: pwmir-pin { + rockchip,pins = <2 RK_PA2 1 &pcfg_pull_none>; + }; + }; + + gmac-1 { + rgmiim1_pins: rgmiim1-pins { + rockchip,pins = + /* mac_txclk */ + <1 RK_PB4 2 &pcfg_pull_none_12ma>, + /* mac_rxclk */ + <1 RK_PB5 2 &pcfg_pull_none_2ma>, + /* mac_mdio */ + <1 RK_PC3 2 &pcfg_pull_none_2ma>, + /* mac_txen */ + <1 RK_PD1 2 &pcfg_pull_none_12ma>, + /* mac_clk */ + <1 RK_PC5 2 &pcfg_pull_none_2ma>, + /* mac_rxdv */ + <1 RK_PC6 2 &pcfg_pull_none_2ma>, + /* mac_mdc */ + <1 RK_PC7 2 &pcfg_pull_none_2ma>, + /* mac_rxd1 */ + <1 RK_PB2 2 &pcfg_pull_none_2ma>, + /* mac_rxd0 */ + <1 RK_PB3 2 &pcfg_pull_none_2ma>, + /* mac_txd1 */ + <1 RK_PB0 2 &pcfg_pull_none_12ma>, + /* mac_txd0 */ + <1 RK_PB1 2 &pcfg_pull_none_12ma>, + /* mac_rxd3 */ + <1 RK_PB6 2 &pcfg_pull_none_2ma>, + /* mac_rxd2 */ + <1 RK_PB7 2 &pcfg_pull_none_2ma>, + /* mac_txd3 */ + <1 RK_PC0 2 &pcfg_pull_none_12ma>, + /* mac_txd2 */ + <1 RK_PC1 2 &pcfg_pull_none_12ma>, + + /* mac_txclk */ + <0 RK_PB0 1 &pcfg_pull_none>, + /* mac_txen */ + <0 RK_PB4 1 &pcfg_pull_none>, + /* mac_clk */ + <0 RK_PD0 1 &pcfg_pull_none>, + /* mac_txd1 */ + <0 RK_PC0 1 &pcfg_pull_none>, + /* mac_txd0 */ + <0 RK_PC1 1 &pcfg_pull_none>, + /* mac_txd3 */ + <0 RK_PC7 1 &pcfg_pull_none>, + /* mac_txd2 */ + <0 RK_PC6 1 &pcfg_pull_none>; + }; + + rmiim1_pins: rmiim1-pins { + rockchip,pins = + /* mac_mdio */ + <1 RK_PC3 2 &pcfg_pull_none_2ma>, + /* mac_txen */ + <1 RK_PD1 2 &pcfg_pull_none_12ma>, + /* mac_clk */ + <1 RK_PC5 2 &pcfg_pull_none_2ma>, + /* mac_rxer */ + <1 RK_PD0 2 &pcfg_pull_none_2ma>, + /* mac_rxdv */ + <1 RK_PC6 2 &pcfg_pull_none_2ma>, + /* mac_mdc */ + <1 RK_PC7 2 &pcfg_pull_none_2ma>, + /* mac_rxd1 */ + <1 RK_PB2 2 &pcfg_pull_none_2ma>, + /* mac_rxd0 */ + <1 RK_PB3 2 &pcfg_pull_none_2ma>, + /* mac_txd1 */ + <1 RK_PB0 2 &pcfg_pull_none_12ma>, + /* mac_txd0 */ + <1 RK_PB1 2 &pcfg_pull_none_12ma>, + + /* mac_mdio */ + <0 RK_PB3 1 &pcfg_pull_none>, + /* mac_txen */ + <0 RK_PB4 1 &pcfg_pull_none>, + /* mac_clk */ + <0 RK_PD0 1 &pcfg_pull_none>, + /* mac_mdc */ + <0 RK_PC3 1 &pcfg_pull_none>, + /* mac_txd1 */ + <0 RK_PC0 1 &pcfg_pull_none>, + /* mac_txd0 */ + <0 RK_PC1 1 &pcfg_pull_none>; + }; + }; + + gmac2phy { + fephyled_speed100: fephyled-speed100 { + rockchip,pins = <0 RK_PD7 1 &pcfg_pull_none>; + }; + + fephyled_speed10: fephyled-speed10 { + rockchip,pins = <0 RK_PD6 1 &pcfg_pull_none>; + }; + + fephyled_duplex: fephyled-duplex { + rockchip,pins = <0 RK_PD6 2 &pcfg_pull_none>; + }; + + fephyled_rxm0: fephyled-rxm0 { + rockchip,pins = <0 RK_PD5 1 &pcfg_pull_none>; + }; + + fephyled_txm0: fephyled-txm0 { + rockchip,pins = <0 RK_PD5 2 &pcfg_pull_none>; + }; + + fephyled_linkm0: fephyled-linkm0 { + rockchip,pins = <0 RK_PD4 1 &pcfg_pull_none>; + }; + + fephyled_rxm1: fephyled-rxm1 { + rockchip,pins = <2 RK_PD1 2 &pcfg_pull_none>; + }; + + fephyled_txm1: fephyled-txm1 { + rockchip,pins = <2 RK_PD1 3 &pcfg_pull_none>; + }; + + fephyled_linkm1: fephyled-linkm1 { + rockchip,pins = <2 RK_PD0 2 &pcfg_pull_none>; + }; + }; + + tsadc_pin { + tsadc_int: tsadc-int { + rockchip,pins = <2 RK_PB5 2 &pcfg_pull_none>; + }; + tsadc_gpio: tsadc-gpio { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + hdmi_pin { + hdmi_cec: hdmi-cec { + rockchip,pins = <0 RK_PA3 1 &pcfg_pull_none>; + }; + + hdmi_hpd: hdmi-hpd { + rockchip,pins = <0 RK_PA4 1 &pcfg_pull_down>; + }; + }; + + cif-0 { + dvp_d2d9_m0:dvp-d2d9-m0 { + rockchip,pins = + /* cif_d0 */ + <3 RK_PA4 2 &pcfg_pull_none>, + /* cif_d1 */ + <3 RK_PA5 2 &pcfg_pull_none>, + /* cif_d2 */ + <3 RK_PA6 2 &pcfg_pull_none>, + /* cif_d3 */ + <3 RK_PA7 2 &pcfg_pull_none>, + /* cif_d4 */ + <3 RK_PB0 2 &pcfg_pull_none>, + /* cif_d5m0 */ + <3 RK_PB1 2 &pcfg_pull_none>, + /* cif_d6m0 */ + <3 RK_PB2 2 &pcfg_pull_none>, + /* cif_d7m0 */ + <3 RK_PB3 2 &pcfg_pull_none>, + /* cif_href */ + <3 RK_PA1 2 &pcfg_pull_none>, + /* cif_vsync */ + <3 RK_PA0 2 &pcfg_pull_none>, + /* cif_clkoutm0 */ + <3 RK_PA3 2 &pcfg_pull_none>, + /* cif_clkin */ + <3 RK_PA2 2 &pcfg_pull_none>; + }; + }; + + cif-1 { + dvp_d2d9_m1:dvp-d2d9-m1 { + rockchip,pins = + /* cif_d0 */ + <3 RK_PA4 2 &pcfg_pull_none>, + /* cif_d1 */ + <3 RK_PA5 2 &pcfg_pull_none>, + /* cif_d2 */ + <3 RK_PA6 2 &pcfg_pull_none>, + /* cif_d3 */ + <3 RK_PA7 2 &pcfg_pull_none>, + /* cif_d4 */ + <3 RK_PB0 2 &pcfg_pull_none>, + /* cif_d5m1 */ + <2 RK_PC0 4 &pcfg_pull_none>, + /* cif_d6m1 */ + <2 RK_PC1 4 &pcfg_pull_none>, + /* cif_d7m1 */ + <2 RK_PC2 4 &pcfg_pull_none>, + /* cif_href */ + <3 RK_PA1 2 &pcfg_pull_none>, + /* cif_vsync */ + <3 RK_PA0 2 &pcfg_pull_none>, + /* cif_clkoutm1 */ + <2 RK_PB7 4 &pcfg_pull_none>, + /* cif_clkin */ + <3 RK_PA2 2 &pcfg_pull_none>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts index 8cdb3bff9c55..ff48edd8e348 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts @@ -53,7 +53,7 @@ }; memory@0 { - reg = <0x0 0x0 0x0 0x80000000>; + reg = <0x0 0x0 0x0 0x40000000>; device_type = "memory"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index a635adc47e74..6d5dc0587e59 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi @@ -108,23 +108,10 @@ }; }; - idle-states { - entry-method = "psci"; - - cpu_sleep: cpu-sleep-0 { - compatible = "arm,idle-state"; - arm,psci-suspend-param = <0x1010000>; - entry-latency-us = <0x3fffffff>; - exit-latency-us = <0x40000000>; - min-residency-us = <0xffffffff>; - }; - }; - cpu_l0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x0>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; #cooling-cells = <2>; /* min followed by max */ @@ -134,7 +121,6 @@ device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x1>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; }; @@ -142,7 +128,6 @@ device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x2>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; }; @@ -150,7 +135,6 @@ device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x3>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; }; @@ -158,7 +142,6 @@ device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x100>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; #cooling-cells = <2>; /* min followed by max */ @@ -168,7 +151,6 @@ device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x101>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; }; @@ -176,7 +158,6 @@ device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x102>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; }; @@ -184,11 +165,39 @@ device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x103>; - cpu-idle-states = <&cpu_sleep>; enable-method = "psci"; }; }; + amba { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dmac_peri: dma-controller@ff250000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0xff250000 0x0 0x4000>; + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; + clocks = <&cru ACLK_DMAC_PERI>; + clock-names = "apb_pclk"; + }; + + dmac_bus: dma-controller@ff600000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0xff600000 0x0 0x4000>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; + clocks = <&cru ACLK_DMAC_BUS>; + clock-names = "apb_pclk"; + }; + }; + arm-pmu { compatible = "arm,armv8-pmuv3"; interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>, @@ -237,6 +246,8 @@ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + resets = <&cru SRST_MMC0>; + reset-names = "reset"; status = "disabled"; }; @@ -249,6 +260,8 @@ clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; + resets = <&cru SRST_SDIO0>; + reset-names = "reset"; status = "disabled"; }; @@ -261,6 +274,8 @@ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; + resets = <&cru SRST_EMMC>; + reset-names = "reset"; status = "disabled"; }; @@ -631,6 +646,7 @@ clocks = <&cru PCLK_MAILBOX>; clock-names = "pclk_mailbox"; #mbox-cells = <1>; + status = "disabled"; }; pmugrf: syscon@ff738000 { @@ -684,6 +700,30 @@ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; }; + i2s_2ch: i2s-2ch@ff890000 { + compatible = "rockchip,rk3368-i2s", "rockchip,rk3066-i2s"; + reg = <0x0 0xff890000 0x0 0x1000>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "i2s_clk", "i2s_hclk"; + clocks = <&cru SCLK_I2S_2CH>, <&cru HCLK_I2S_2CH>; + dmas = <&dmac_bus 6>, <&dmac_bus 7>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + i2s_8ch: i2s-8ch@ff898000 { + compatible = "rockchip,rk3368-i2s", "rockchip,rk3066-i2s"; + reg = <0x0 0xff898000 0x0 0x1000>; + interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "i2s_clk", "i2s_hclk"; + clocks = <&cru SCLK_I2S_8CH>, <&cru HCLK_I2S_8CH>; + dmas = <&dmac_bus 0>, <&dmac_bus 1>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s_8ch_bus>; + status = "disabled"; + }; + gic: interrupt-controller@ffb71000 { compatible = "arm,gic-400"; interrupt-controller; @@ -886,6 +926,20 @@ }; }; + i2s { + i2s_8ch_bus: i2s-8ch-bus { + rockchip,pins = <2 12 RK_FUNC_1 &pcfg_pull_none>, + <2 13 RK_FUNC_1 &pcfg_pull_none>, + <2 14 RK_FUNC_1 &pcfg_pull_none>, + <2 15 RK_FUNC_1 &pcfg_pull_none>, + <2 16 RK_FUNC_1 &pcfg_pull_none>, + <2 17 RK_FUNC_1 &pcfg_pull_none>, + <2 18 RK_FUNC_1 &pcfg_pull_none>, + <2 19 RK_FUNC_1 &pcfg_pull_none>, + <2 20 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + pwm0 { pwm0_pin: pwm0-pin { rockchip,pins = <3 8 RK_FUNC_2 &pcfg_pull_none>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts new file mode 100644 index 000000000000..658bb9dc9dfd --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts @@ -0,0 +1,306 @@ +/* + * Google Gru-Kevin Rev 6+ board device tree source + * + * Copyright 2016-2017 Google, Inc + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "rk3399-gru.dtsi" +#include <include/dt-bindings/input/linux-event-codes.h> + +/* + * Kevin-specific things + * + * Things in this section should use names from Kevin schematic since no + * equivalent exists in Gru schematic. If referring to signals that exist + * in Gru we use the Gru names, though. Confusing enough for you? + */ +/ { + model = "Google Kevin"; + compatible = "google,kevin-rev15", "google,kevin-rev14", + "google,kevin-rev13", "google,kevin-rev12", + "google,kevin-rev11", "google,kevin-rev10", + "google,kevin-rev9", "google,kevin-rev8", + "google,kevin-rev7", "google,kevin-rev6", + "google,kevin", "google,gru", "rockchip,rk3399"; + + /* Power tree */ + + p3_3v_dig: p3-3v-dig { + compatible = "regulator-fixed"; + regulator-name = "p3.3v_dig"; + pinctrl-names = "default"; + pinctrl-0 = <&cpu3_pen_pwr_en>; + + enable-active-high; + gpio = <&gpio4 30 GPIO_ACTIVE_HIGH>; + vin-supply = <&pp3300>; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&cros_ec_pwm 1>; + brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 30 + 31 32 33 34 35 36 37 38 39 40 41 42 43 44 + 45 46 47 48 49 50 51 52 53 54 55 56 57 58 + 59 60 61 62 63 64 65 66 67 68 69 70 71 72 + 73 74 75 76 77 78 79 80 81 82 83 84 85 86 + 87 88 89 90 91 92 93 94 95 96 97 98 99 100>; + default-brightness-level = <51>; + enable-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>; + power-supply = <&pp3300_disp>; + pinctrl-names = "default"; + pinctrl-0 = <&bl_en>; + pwm-delay-us = <10000>; + }; + + thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu { + compatible = "murata,ncp15wb473"; + pullup-uv = <1800000>; + pullup-ohm = <25500>; + pulldown-ohm = <0>; + io-channels = <&saradc 2>; + #thermal-sensor-cells = <0>; + }; + + thermistor_ppvar_litcpu: thermistor-ppvar-litcpu { + compatible = "murata,ncp15wb473"; + pullup-uv = <1800000>; + pullup-ohm = <25500>; + pulldown-ohm = <0>; + io-channels = <&saradc 3>; + #thermal-sensor-cells = <0>; + }; +}; + +&gpio_keys { + pinctrl-names = "default"; + pinctrl-0 = <&bt_host_wake_l>, <&cpu1_pen_eject>; + + pen-insert { + label = "Pen Insert"; + /* Insert = low, eject = high */ + gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + linux,code = <SW_PEN_INSERTED>; + linux,input-type = <EV_SW>; + wakeup-source; + }; +}; + +&thermal_zones { + bigcpu_reg_thermal: bigcpu-reg-thermal { + polling-delay-passive = <100>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + thermal-sensors = <&thermistor_ppvar_bigcpu 0>; + sustainable-power = <4000>; + + ppvar_bigcpu_trips: trips { + ppvar_bigcpu_on: ppvar-bigcpu-on { + temperature = <40000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + + ppvar_bigcpu_alert: ppvar-bigcpu-alert { + temperature = <50000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + + ppvar_bigcpu_crit: ppvar-bigcpu-crit { + temperature = <90000>; /* millicelsius */ + hysteresis = <0>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&ppvar_bigcpu_alert>; + cooling-device = + <&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + contribution = <4096>; + }; + map1 { + trip = <&ppvar_bigcpu_alert>; + cooling-device = + <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + contribution = <1024>; + }; + }; + }; + + litcpu_reg_thermal: litcpu-reg-thermal { + polling-delay-passive = <100>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + thermal-sensors = <&thermistor_ppvar_litcpu 0>; + sustainable-power = <4000>; + + ppvar_litcpu_trips: trips { + ppvar_litcpu_on: ppvar-litcpu-on { + temperature = <40000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + + ppvar_litcpu_alert: ppvar-litcpu-alert { + temperature = <50000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + + ppvar_litcpu_crit: ppvar-litcpu-crit { + temperature = <90000>; /* millicelsius */ + hysteresis = <0>; /* millicelsius */ + type = "critical"; + }; + }; + }; +}; + +ap_i2c_tpm: &i2c0 { + status = "okay"; + + clock-frequency = <400000>; + + /* These are relatively safe rise/fall times. */ + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; + + tpm: tpm@20 { + compatible = "infineon,slb9645tt"; + reg = <0x20>; + powered-while-suspended; + }; +}; + +ap_i2c_dig: &i2c2 { + status = "okay"; + + clock-frequency = <400000>; + + /* These are relatively safe rise/fall times. */ + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; + + digitizer: digitizer@9 { + /* wacom,w9013 */ + compatible = "hid-over-i2c"; + reg = <0x9>; + pinctrl-names = "default"; + pinctrl-0 = <&cpu1_dig_irq_l &cpu1_dig_pdct_l>; + + vdd-supply = <&p3_3v_dig>; + post-power-on-delay-ms = <100>; + + interrupt-parent = <&gpio2>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + + hid-descr-addr = <0x1>; + }; +}; + +/* Adjustments to things in the gru baseboard */ + +&ap_i2c_tp { + trackpad@4a { + compatible = "atmel,atmel_mxt_tp"; + reg = <0x4a>; + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_int_l>; + interrupt-parent = <&gpio1>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + wakeup-source; + }; +}; + +&ap_i2c_ts { + touchscreen@4b { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4b>; + pinctrl-names = "default"; + pinctrl-0 = <&touch_int_l>; + interrupt-parent = <&gpio3>; + interrupts = <13 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&saradc { + status = "okay"; + vref-supply = <&pp1800_ap_io>; +}; + +&mvl_wifi { + marvell,wakeup-pin = <14>; /* GPIO_14 on Marvell */ +}; + +&pinctrl { + digitizer { + /* Has external pullup */ + cpu1_dig_irq_l: cpu1-dig-irq-l { + rockchip,pins = <2 4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + /* Has external pullup */ + cpu1_dig_pdct_l: cpu1-dig-pdct-l { + rockchip,pins = <2 5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + discrete-regulators { + cpu3_pen_pwr_en: cpu3-pen-pwr-en { + rockchip,pins = <4 30 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pen { + cpu1_pen_eject: cpu1-pen-eject { + rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wifi { + wlan_host_wake_l: wlan-host-wake-l { + rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi new file mode 100644 index 000000000000..0d960b7f7625 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi @@ -0,0 +1,1103 @@ +/* + * Google Gru (and derivatives) board device tree source + * + * Copyright 2016-2017 Google, Inc + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/input/input.h> +#include "rk3399.dtsi" +#include "rk3399-opp.dtsi" + +/ { + chosen { + stdout-path = "serial2:115200n8"; + }; + + /* + * Power Tree + * + * In general an attempt is made to include all rails called out by + * the schematic as long as those rails interact in some way with + * the AP. AKA: + * - Rails that only connect to the EC (or devices that the EC talks to) + * are not included. + * - Rails _are_ included if the rails go to the AP even if the AP + * doesn't currently care about them / they are always on. The idea + * here is that it makes it easier to map to the schematic or extend + * later. + * + * If two rails are substantially the same from the AP's point of + * view, though, we won't create a full fixed regulator. We'll just + * put the child rail as an alias of the parent rail. Sometimes rails + * look the same to the AP because one of these is true: + * - The EC controls the enable and the EC always enables a rail as + * long as the AP is running. + * - The rails are actually connected to each other by a jumper and + * the distinction is just there to add clarity/flexibility to the + * schematic. + */ + + ppvar_sys: ppvar-sys { + compatible = "regulator-fixed"; + regulator-name = "ppvar_sys"; + regulator-always-on; + regulator-boot-on; + }; + + pp900_ap: pp900-ap { + compatible = "regulator-fixed"; + regulator-name = "pp900_ap"; + + /* EC turns on w/ pp900_ap_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + + vin-supply = <&ppvar_sys>; + }; + + pp1200_lpddr: pp1200-lpddr { + compatible = "regulator-fixed"; + regulator-name = "pp1200_lpddr"; + + /* EC turns on w/ lpddr_pwr_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + vin-supply = <&ppvar_sys>; + }; + + pp1800: pp1800 { + compatible = "regulator-fixed"; + regulator-name = "pp1800"; + + /* Always on when ppvar_sys shows power good */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + vin-supply = <&ppvar_sys>; + }; + + pp3000: pp3000 { + compatible = "regulator-fixed"; + regulator-name = "pp3000"; + pinctrl-names = "default"; + pinctrl-0 = <&pp3000_en>; + + enable-active-high; + gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + + vin-supply = <&ppvar_sys>; + }; + + pp3300: pp3300 { + compatible = "regulator-fixed"; + regulator-name = "pp3300"; + + /* Always on; plain and simple */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + vin-supply = <&ppvar_sys>; + }; + + pp5000: pp5000 { + compatible = "regulator-fixed"; + regulator-name = "pp5000"; + + /* EC turns on w/ pp5000_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + + vin-supply = <&ppvar_sys>; + }; + + ppvar_bigcpu: ppvar-bigcpu { + compatible = "pwm-regulator"; + regulator-name = "ppvar_bigcpu"; + /* + * OVP circuit requires special handling which is not yet + * represented. Keep disabled for now. + */ + status = "disabled"; + + pwms = <&pwm1 0 3337 0>; + pwm-supply = <&ppvar_sys>; + pwm-dutycycle-range = <100 0>; + pwm-dutycycle-unit = <100>; + + /* EC turns on w/ ap_core_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <798674>; + regulator-max-microvolt = <1302172>; + }; + + ppvar_litcpu: ppvar-litcpu { + compatible = "pwm-regulator"; + regulator-name = "ppvar_litcpu"; + /* + * OVP circuit requires special handling which is not yet + * represented. Keep disabled for now. + */ + status = "disabled"; + + pwms = <&pwm2 0 3337 0>; + pwm-supply = <&ppvar_sys>; + pwm-dutycycle-range = <100 0>; + pwm-dutycycle-unit = <100>; + + /* EC turns on w/ ap_core_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <799065>; + regulator-max-microvolt = <1303738>; + }; + + ppvar_gpu: ppvar-gpu { + compatible = "pwm-regulator"; + regulator-name = "ppvar_gpu"; + /* + * OVP circuit requires special handling which is not yet + * represented. Keep disabled for now. + */ + status = "disabled"; + + pwms = <&pwm0 0 3337 0>; + pwm-supply = <&ppvar_sys>; + pwm-dutycycle-range = <100 0>; + pwm-dutycycle-unit = <100>; + + /* EC turns on w/ ap_core_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <785782>; + regulator-max-microvolt = <1217729>; + }; + + ppvar_centerlogic: ppvar-centerlogic { + compatible = "pwm-regulator"; + regulator-name = "ppvar_centerlogic"; + /* + * OVP circuit requires special handling which is not yet + * represented. Keep disabled for now. + */ + status = "disabled"; + + pwms = <&pwm3 0 3337 0>; + pwm-supply = <&ppvar_sys>; + pwm-dutycycle-range = <100 0>; + pwm-dutycycle-unit = <100>; + + /* EC turns on w/ ppvar_centerlogic_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800069>; + regulator-max-microvolt = <1049692>; + }; + + /* Schematics call this PPVAR even though it's fixed */ + ppvar_logic: ppvar-logic { + compatible = "regulator-fixed"; + regulator-name = "ppvar_logic"; + + /* EC turns on w/ ppvar_logic_en; always on for AP */ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + + vin-supply = <&ppvar_sys>; + }; + + /* EC turns on w/ pp900_ddrpll_en */ + pp900_ddrpll: pp900-ap { + }; + + /* EC turns on w/ pp900_pcie_en */ + pp900_pcie: pp900-ap { + }; + + /* EC turns on w/ pp900_pll_en */ + pp900_pll: pp900-ap { + }; + + /* EC turns on w/ pp900_pmu_en */ + pp900_pmu: pp900-ap { + }; + + /* EC turns on w/ pp900_usb_en */ + pp900_usb: pp900-ap { + }; + + /* EC turns on w/ pp1800_s0_en_l */ + pp1800_ap_io: pp1800_emmc: pp1800_nfc: pp1800_s0: pp1800 { + }; + + /* EC turns on w/ pp1800_avdd_en_l */ + pp1800_avdd: pp1800 { + }; + + /* EC turns on w/ pp1800_lid_en_l */ + pp1800_lid: pp1800_mic: pp1800 { + }; + + /* EC turns on w/ lpddr_pwr_en */ + pp1800_lpddr: pp1800 { + }; + + /* EC turns on w/ pp1800_pmu_en_l */ + pp1800_pmu: pp1800 { + }; + + /* EC turns on w/ pp1800_usb_en_l */ + pp1800_usb: pp1800 { + }; + + pp1500_ap_io: pp1500-ap-io { + compatible = "regulator-fixed"; + regulator-name = "pp1500_ap_io"; + pinctrl-names = "default"; + pinctrl-0 = <&pp1500_en>; + + enable-active-high; + gpio = <&gpio0 10 GPIO_ACTIVE_HIGH>; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + + vin-supply = <&pp1800>; + }; + + pp1800_audio: pp1800-audio { + compatible = "regulator-fixed"; + regulator-name = "pp1800_audio"; + pinctrl-names = "default"; + pinctrl-0 = <&pp1800_audio_en>; + + enable-active-high; + gpio = <&gpio0 2 GPIO_ACTIVE_HIGH>; + + regulator-always-on; + regulator-boot-on; + + vin-supply = <&pp1800>; + }; + + /* gpio is shared with pp3300_wifi_bt */ + pp1800_pcie: pp1800-pcie { + compatible = "regulator-fixed"; + regulator-name = "pp1800_pcie"; + pinctrl-names = "default"; + pinctrl-0 = <&wlan_module_pd_l>; + + enable-active-high; + gpio = <&gpio0 4 GPIO_ACTIVE_HIGH>; + + /* + * Need to wait 1ms + ramp-up time before we can power on WiFi. + * This has been approximated as 8ms total. + */ + regulator-enable-ramp-delay = <8000>; + + vin-supply = <&pp1800>; + }; + + /* + * This is a bit of a hack. The WiFi module should be reset at least + * 1ms after its regulators have ramped up (max rampup time is ~7ms). + * With some stretching of the imagination, we can call the 1.8V + * regulator a supply. + */ + wlan_pd_n: wlan-pd-n { + compatible = "regulator-fixed"; + regulator-name = "wlan_pd_n"; + + /* Note the wlan_module_reset_l pinctrl */ + enable-active-high; + gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>; + + vin-supply = <&pp1800_pcie>; + }; + + /* Always on; plain and simple */ + pp3000_ap: pp3000_emmc: pp3000 { + }; + + pp3000_sd_slot: pp3000-sd-slot { + compatible = "regulator-fixed"; + regulator-name = "pp3000_sd_slot"; + pinctrl-names = "default"; + pinctrl-0 = <&sd_slot_pwr_en>; + + enable-active-high; + gpio = <&gpio4 29 GPIO_ACTIVE_HIGH>; + + vin-supply = <&pp3000>; + }; + + /* + * Technically, this is a small abuse of 'regulator-gpio'; this + * regulator is a mux between pp1800 and pp3300. pp1800 and pp3300 are + * always on though, so it is sufficient to simply control the mux + * here. + */ + ppvar_sd_card_io: ppvar-sd-card-io { + compatible = "regulator-gpio"; + regulator-name = "ppvar_sd_card_io"; + pinctrl-names = "default"; + pinctrl-0 = <&sd_io_pwr_en &sd_pwr_1800_sel>; + + enable-active-high; + enable-gpio = <&gpio2 2 GPIO_ACTIVE_HIGH>; + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>; + states = <1800000 0x1 + 3000000 0x0>; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + }; + + /* EC turns on w/ pp3300_trackpad_en_l */ + pp3300_trackpad: pp3300-trackpad { + }; + + /* EC turns on w/ pp3300_usb_en_l */ + pp3300_usb: pp3300 { + }; + + pp3300_disp: pp3300-disp { + compatible = "regulator-fixed"; + regulator-name = "pp3300_disp"; + pinctrl-names = "default"; + pinctrl-0 = <&pp3300_disp_en>; + + enable-active-high; + gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>; + + startup-delay-us = <2000>; + vin-supply = <&pp3300>; + }; + + /* gpio is shared with pp1800_pcie and pinctrl is set there */ + pp3300_wifi_bt: pp3300-wifi-bt { + compatible = "regulator-fixed"; + regulator-name = "pp3300_wifi_bt"; + + enable-active-high; + gpio = <&gpio0 4 GPIO_ACTIVE_HIGH>; + + vin-supply = <&pp3300>; + }; + + /* EC turns on w/ usb_a_en */ + pp5000_usb_a_vbus: pp5000 { + }; + + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_host_wake_l>; + + wake-on-bt { + label = "Wake-on-Bluetooth"; + gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; + linux,code = <KEY_WAKEUP>; + wakeup-source; + }; + }; + + max98357a: max98357a { + compatible = "maxim,max98357a"; + pinctrl-names = "default"; + pinctrl-0 = <&sdmode_en>; + sdmode-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + sdmode-delay = <2>; + #sound-dai-cells = <0>; + status = "okay"; + }; + + sound { + compatible = "rockchip,rk3399-gru-sound"; + rockchip,cpu = <&i2s0 &i2s2>; + rockchip,codec = <&max98357a &headsetcodec &codec>; + }; +}; + +/* + * Set some suspend operating points to avoid OVP in suspend + * + * When we go into S3 ARM Trusted Firmware will transition our PWM regulators + * from wherever they're at back to the "default" operating point (whatever + * voltage we get when we set the PWM pins to "input"). + * + * This quick transition under light load has the possibility to trigger the + * regulator "over voltage protection" (OVP). + * + * To make extra certain that we don't hit this OVP at suspend time, we'll + * transition to a voltage that's much closer to the default (~1.0 V) so that + * there will not be a big jump. Technically we only need to get within 200 mV + * of the default voltage, but the speed here should be fast enough and we need + * suspend/resume to be rock solid. + */ + +&cluster0_opp { + opp05 { + opp-suspend; + }; +}; + +&cluster1_opp { + opp06 { + opp-suspend; + }; +}; + +&cpu_l0 { + cpu-supply = <&ppvar_litcpu>; +}; + +&cpu_l1 { + cpu-supply = <&ppvar_litcpu>; +}; + +&cpu_l2 { + cpu-supply = <&ppvar_litcpu>; +}; + +&cpu_l3 { + cpu-supply = <&ppvar_litcpu>; +}; + +&cpu_b0 { + cpu-supply = <&ppvar_bigcpu>; +}; + +&cpu_b1 { + cpu-supply = <&ppvar_bigcpu>; +}; + + +&cru { + assigned-clocks = + <&cru PLL_GPLL>, <&cru PLL_CPLL>, + <&cru PLL_NPLL>, + <&cru ACLK_PERIHP>, <&cru HCLK_PERIHP>, + <&cru PCLK_PERIHP>, + <&cru ACLK_PERILP0>, <&cru HCLK_PERILP0>, + <&cru PCLK_PERILP0>, <&cru ACLK_CCI>, + <&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>; + assigned-clock-rates = + <600000000>, <800000000>, + <1000000000>, + <150000000>, <75000000>, + <37500000>, + <100000000>, <100000000>, + <50000000>, <800000000>, + <100000000>, <50000000>; +}; + +&emmc_phy { + status = "okay"; +}; + +ap_i2c_mic: &i2c1 { + status = "okay"; + + clock-frequency = <400000>; + + /* These are relatively safe rise/fall times */ + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; + + headsetcodec: rt5514@57 { + compatible = "realtek,rt5514"; + reg = <0x57>; + interrupt-parent = <&gpio1>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mic_int>; + realtek,dmic-init-delay = <20>; + wakeup-source; + }; +}; + +ap_i2c_ts: &i2c3 { + status = "okay"; + + clock-frequency = <400000>; + + /* These are relatively safe rise/fall times */ + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; +}; + +ap_i2c_tp: &i2c5 { + status = "okay"; + + clock-frequency = <400000>; + + /* These are relatively safe rise/fall times */ + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; + + /* + * Note strange pullup enable. Apparently this avoids leakage but + * still allows us to get nice 4.7K pullups for high speed i2c + * transfers. Basically we want the pullup on whenever the ap is + * alive, so the "en" pin just gets set to output high. + */ + pinctrl-0 = <&i2c5_xfer &ap_i2c_tp_pu_en>; +}; + +ap_i2c_audio: &i2c8 { + status = "okay"; + + clock-frequency = <400000>; + + /* These are relatively safe rise/fall times */ + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; + + codec: da7219@1a { + compatible = "dlg,da7219"; + reg = <0x1a>; + interrupt-parent = <&gpio1>; + interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + clocks = <&cru SCLK_I2S_8CH_OUT>; + clock-names = "mclk"; + dlg,micbias-lvl = <2600>; + dlg,mic-amp-in-sel = "diff"; + pinctrl-names = "default"; + pinctrl-0 = <&headset_int_l>; + VDD-supply = <&pp1800>; + VDDMIC-supply = <&pp3300>; + VDDIO-supply = <&pp1800>; + + da7219_aad { + dlg,adc-1bit-rpt = <1>; + dlg,btn-avg = <4>; + dlg,btn-cfg = <50>; + dlg,mic-det-thr = <500>; + dlg,jack-ins-deb = <20>; + dlg,jack-det-rate = "32ms_64ms"; + dlg,jack-rem-deb = <1>; + + dlg,a-d-btn-thr = <0xa>; + dlg,d-b-btn-thr = <0x16>; + dlg,b-c-btn-thr = <0x21>; + dlg,c-mic-btn-thr = <0x3E>; + }; + }; +}; + +&i2s0 { + status = "okay"; +}; + +&i2s2 { + status = "okay"; +}; + +&io_domains { + status = "okay"; + + audio-supply = <&pp1800_audio>; /* APIO5_VDD; 3d 4a */ + bt656-supply = <&pp1800_ap_io>; /* APIO2_VDD; 2a 2b */ + gpio1830-supply = <&pp3000_ap>; /* APIO4_VDD; 4c 4d */ + sdmmc-supply = <&ppvar_sd_card_io>; /* SDMMC0_VDD; 4b */ +}; + +&pcie0 { + status = "okay"; + + ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>; + vpcie3v3-supply = <&pp3300_wifi_bt>; + vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */ + vpcie0v9-supply = <&pp900_pcie>; + + pci_rootport: pcie@0,0 { + reg = <0x83000000 0x0 0x00000000 0x0 0x00000000>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + mvl_wifi: wifi@0,0 { + compatible = "pci1b4b,2b42"; + reg = <0x83010000 0x0 0x00000000 0x0 0x00100000 + 0x83010000 0x0 0x00100000 0x0 0x00100000>; + interrupt-parent = <&gpio0>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&wlan_host_wake_l>; + wakeup-source; + }; + }; +}; + +&pcie_phy { + status = "okay"; +}; + +&pmu_io_domains { + status = "okay"; + + pmu1830-supply = <&pp1800_pmu>; /* PMUIO2_VDD */ +}; + +&pwm0 { + status = "okay"; +}; + +&pwm1 { + status = "okay"; +}; + +&pwm2 { + status = "okay"; +}; + +&pwm3 { + status = "okay"; +}; + +&sdhci { + /* + * Signal integrity isn't great at 200 MHz and 150 MHz (DDR) gives the + * same (or nearly the same) performance for all eMMC that are intended + * to be used. + */ + assigned-clock-rates = <150000000>; + + bus-width = <8>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + non-removable; + status = "okay"; +}; + +&sdmmc { + status = "okay"; + + /* + * Note: configure "sdmmc_cd" as card detect even though it's actually + * hooked to ground. Because we specified "cd-gpios" below dw_mmc + * should be ignoring card detect anyway. Specifying the pin as + * sdmmc_cd means that even if you've got GRF_SOC_CON7[12] (force_jtag) + * turned on that the system will still make sure the port is + * configured as SDMMC and not JTAG. + */ + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_cd_gpio + &sdmmc_bus4>; + + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + cd-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>; + disable-wp; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + vmmc-supply = <&pp3000_sd_slot>; + vqmmc-supply = <&ppvar_sd_card_io>; +}; + +&spi1 { + status = "okay"; + + pinctrl-names = "default", "sleep"; + pinctrl-1 = <&spi1_sleep>; + + spiflash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + + /* May run faster once verified. */ + spi-max-frequency = <10000000>; + }; +}; + +&spi2 { + status = "okay"; + + wacky_spi_audio: spi2@0 { + compatible = "realtek,rt5514"; + reg = <0>; + + /* May run faster once verified. */ + spi-max-frequency = <10000000>; + }; +}; + +&spi5 { + status = "okay"; + + cros_ec: ec@0 { + compatible = "google,cros-ec-spi"; + reg = <0>; + interrupt-parent = <&gpio0>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ec_ap_int_l>; + spi-max-frequency = <3000000>; + + i2c_tunnel: i2c-tunnel { + compatible = "google,cros-ec-i2c-tunnel"; + google,remote-bus = <4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cros_ec_pwm: ec-pwm { + compatible = "google,cros-ec-pwm"; + #pwm-cells = <1>; + }; + }; +}; + +&tsadc { + status = "okay"; + + rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */ + rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */ +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy1 { + status = "okay"; +}; + +&u2phy0_host { + status = "okay"; +}; + +&u2phy1_host { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; +}; + +&u2phy1_otg { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usbdrd3_0 { + status = "okay"; +}; + +&usbdrd_dwc3_0 { + status = "okay"; + dr_mode = "host"; +}; + +&usbdrd3_1 { + status = "okay"; +}; + +&usbdrd_dwc3_1 { + status = "okay"; + dr_mode = "host"; +}; + +#include <arm/cros-ec-keyboard.dtsi> +#include <arm/cros-ec-sbs.dtsi> + +&pinctrl { + /* + * pinctrl settings for pins that have no real owners. + * + * At the moment settings are identical for S0 and S3, but if we later + * need to configure things differently for S3 we'll adjust here. + */ + pinctrl-names = "default"; + pinctrl-0 = < + &ap_pwroff /* AP will auto-assert this when in S3 */ + &clk_32k /* This pin is always 32k on gru boards */ + + /* + * We want this driven low ASAP; firmware should help us, but + * we can help ourselves too. + */ + &wlan_module_reset_l + >; + + pcfg_output_low: pcfg-output-low { + output-low; + }; + + pcfg_output_high: pcfg-output-high { + output-high; + }; + + pcfg_pull_none_8ma: pcfg-pull-none-8ma { + bias-disable; + drive-strength = <8>; + }; + + backlight-enable { + bl_en: bl-en { + rockchip,pins = <1 17 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + cros-ec { + ec_ap_int_l: ec-ap-int-l { + rockchip,pins = <RK_GPIO0 1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + discrete-regulators { + pp1500_en: pp1500-en { + rockchip,pins = <RK_GPIO0 10 RK_FUNC_GPIO + &pcfg_pull_none>; + }; + + pp1800_audio_en: pp1800-audio-en { + rockchip,pins = <RK_GPIO0 2 RK_FUNC_GPIO + &pcfg_pull_down>; + }; + + pp3300_disp_en: pp3300-disp-en { + rockchip,pins = <RK_GPIO4 27 RK_FUNC_GPIO + &pcfg_pull_none>; + }; + + pp3000_en: pp3000-en { + rockchip,pins = <RK_GPIO0 12 RK_FUNC_GPIO + &pcfg_pull_none>; + }; + + sd_io_pwr_en: sd-io-pwr-en { + rockchip,pins = <RK_GPIO2 2 RK_FUNC_GPIO + &pcfg_pull_none>; + }; + + sd_pwr_1800_sel: sd-pwr-1800-sel { + rockchip,pins = <RK_GPIO2 28 RK_FUNC_GPIO + &pcfg_pull_none>; + }; + + sd_slot_pwr_en: sd-slot-pwr-en { + rockchip,pins = <RK_GPIO4 29 RK_FUNC_GPIO + &pcfg_pull_none>; + }; + + wlan_module_pd_l: wlan-module-pd-l { + rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO + &pcfg_pull_down>; + }; + }; + + codec { + /* Has external pullup */ + headset_int_l: headset-int-l { + rockchip,pins = <1 23 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + mic_int: mic-int { + rockchip,pins = <1 13 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + max98357a { + sdmode_en: sdmode-en { + rockchip,pins = <1 2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + pcie { + pcie_clkreqn_cpm: pci-clkreqn-cpm { + /* + * Since our pcie doesn't support ClockPM(CPM), we want + * to hack this as gpio, so the EP could be able to + * de-assert it along and make ClockPM(CPM) work. + */ + rockchip,pins = <2 26 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sdmmc { + /* + * We run sdmmc at max speed; bump up drive strength. + * We also have external pulls, so disable the internal ones. + */ + sdmmc_bus4: sdmmc-bus4 { + rockchip,pins = + <4 8 RK_FUNC_1 &pcfg_pull_none_8ma>, + <4 9 RK_FUNC_1 &pcfg_pull_none_8ma>, + <4 10 RK_FUNC_1 &pcfg_pull_none_8ma>, + <4 11 RK_FUNC_1 &pcfg_pull_none_8ma>; + }; + + sdmmc_clk: sdmmc-clk { + rockchip,pins = + <4 12 RK_FUNC_1 &pcfg_pull_none_8ma>; + }; + + sdmmc_cmd: sdmmc-cmd { + rockchip,pins = + <4 13 RK_FUNC_1 &pcfg_pull_none_8ma>; + }; + + /* + * In our case the official card detect is hooked to ground + * to avoid getting access to JTAG just by sticking something + * in the SD card slot (see the force_jtag bit in the TRM). + * + * We still configure it as card detect because it doesn't + * hurt and dw_mmc will ignore it. We make sure to disable + * the pull though so we don't burn needless power. + */ + sdmmc_cd: sdmcc-cd { + rockchip,pins = + <0 7 RK_FUNC_1 &pcfg_pull_none>; + }; + + /* This is where we actually hook up CD; has external pull */ + sdmmc_cd_gpio: sdmmc-cd-gpio { + rockchip,pins = <4 24 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + spi1 { + spi1_sleep: spi1-sleep { + /* + * Pull down SPI1 CLK/CS/RX/TX during suspend, to + * prevent leakage. + */ + rockchip,pins = <1 9 RK_FUNC_GPIO &pcfg_pull_down>, + <1 10 RK_FUNC_GPIO &pcfg_pull_down>, + <1 7 RK_FUNC_GPIO &pcfg_pull_down>, + <1 8 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + touchscreen { + touch_int_l: touch-int-l { + rockchip,pins = <3 13 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + touch_reset_l: touch-reset-l { + rockchip,pins = <4 26 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + trackpad { + ap_i2c_tp_pu_en: ap-i2c-tp-pu-en { + rockchip,pins = <3 12 RK_FUNC_GPIO &pcfg_output_high>; + }; + + trackpad_int_l: trackpad-int-l { + rockchip,pins = <1 4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wifi { + wifi_perst_l: wifi-perst-l { + rockchip,pins = <2 27 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wlan_module_reset_l: wlan-module-reset-l { + /* + * We want this driven low ASAP (As {Soon,Strongly} As + * Possible), to avoid leakage through the powered-down + * WiFi. + */ + rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_output_low>; + }; + + bt_host_wake_l: bt-host-wake-l { + /* Kevin has an external pull up, but Gru does not */ + rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + write-protect { + ap_fw_wp: ap-fw-wp { + rockchip,pins = <1 18 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi new file mode 100644 index 000000000000..dd82e16236a8 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016-2017 Fuzhou Rockchip Electronics Co., Ltd + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/ { + cluster0_opp: opp-table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <800000>; + clock-latency-ns = <40000>; + }; + opp01 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <800000>; + }; + opp02 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <800000>; + }; + opp03 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <875000>; + }; + opp04 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <925000>; + }; + opp05 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <1050000>; + }; + opp06 { + opp-hz = /bits/ 64 <1512000000>; + opp-microvolt = <1125000>; + }; + }; + + cluster1_opp: opp-table1 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <800000>; + clock-latency-ns = <40000>; + }; + opp01 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <800000>; + }; + opp02 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <825000>; + }; + opp03 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <875000>; + }; + opp04 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <950000>; + }; + opp05 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <1025000>; + }; + opp06 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <1075000>; + }; + opp07 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <1150000>; + }; + opp08 { + opp-hz = /bits/ 64 <2016000000>; + opp-microvolt = <1250000>; + }; + }; +}; + +&cpu_l0 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_l1 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_l2 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_l3 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_b0 { + operating-points-v2 = <&cluster1_opp>; +}; + +&cpu_b1 { + operating-points-v2 = <&cluster1_opp>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 8e6d1bdeb9c3..f4f3c96c798d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -211,6 +211,51 @@ }; }; + pcie0: pcie@f8000000 { + compatible = "rockchip,rk3399-pcie"; + reg = <0x0 0xf8000000 0x0 0x2000000>, + <0x0 0xfd000000 0x0 0x1000000>; + reg-names = "axi-base", "apb-base"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + aspm-no-l0s; + bus-range = <0x0 0x1>; + clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>, + <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>; + clock-names = "aclk", "aclk-perf", + "hclk", "pm"; + interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "sys", "legacy", "client"; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie0_intc 0>, + <0 0 0 2 &pcie0_intc 1>, + <0 0 0 3 &pcie0_intc 2>, + <0 0 0 4 &pcie0_intc 3>; + linux,pci-domain = <0>; + max-link-speed = <1>; + msi-map = <0x0 &its 0x0 0x1000>; + phys = <&pcie_phy>; + phy-names = "pcie-phy"; + ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x600000 + 0x81000000 0x0 0xfa600000 0x0 0xfa600000 0x0 0x100000>; + resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>, + <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>, + <&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>, + <&cru SRST_A_PCIE>; + reset-names = "core", "mgmt", "mgmt-sticky", "pipe", + "pm", "pclk", "aclk"; + status = "disabled"; + + pcie0_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + gmac: ethernet@fe300000 { compatible = "rockchip,rk3399-gmac"; reg = <0x0 0xfe300000 0x0 0x10000>; @@ -241,6 +286,8 @@ <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; + resets = <&cru SRST_SDIO0>; + reset-names = "reset"; status = "disabled"; }; @@ -255,6 +302,8 @@ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; power-domains = <&power RK3399_PD_SD>; + resets = <&cru SRST_SDMMC>; + reset-names = "reset"; status = "disabled"; }; @@ -275,50 +324,6 @@ status = "disabled"; }; - pcie0: pcie@f8000000 { - compatible = "rockchip,rk3399-pcie"; - reg = <0x0 0xf8000000 0x0 0x2000000>, - <0x0 0xfd000000 0x0 0x1000000>; - reg-names = "axi-base", "apb-base"; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - aspm-no-l0s; - bus-range = <0x0 0x1>; - clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>, - <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>; - clock-names = "aclk", "aclk-perf", - "hclk", "pm"; - interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>, - <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>, - <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>; - interrupt-names = "sys", "legacy", "client"; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0 0 0 1 &pcie0_intc 0>, - <0 0 0 2 &pcie0_intc 1>, - <0 0 0 3 &pcie0_intc 2>, - <0 0 0 4 &pcie0_intc 3>; - max-link-speed = <1>; - msi-map = <0x0 &its 0x0 0x1000>; - phys = <&pcie_phy>; - phy-names = "pcie-phy"; - ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x600000 - 0x81000000 0x0 0xfa600000 0x0 0xfa600000 0x0 0x100000>; - resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>, - <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>, - <&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>, - <&cru SRST_A_PCIE>; - reset-names = "core", "mgmt", "mgmt-sticky", "pipe", - "pm", "pclk", "aclk"; - status = "disabled"; - - pcie0_intc: interrupt-controller { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <1>; - }; - }; - usb_host0_ehci: usb@fe380000 { compatible = "generic-ehci"; reg = <0x0 0xfe380000 0x0 0x20000>; @@ -371,6 +376,60 @@ status = "disabled"; }; + usbdrd3_0: usb@fe800000 { + compatible = "rockchip,rk3399-dwc3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>, + <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_GRF>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk", "grf_clk"; + status = "disabled"; + + usbdrd_dwc3_0: dwc3 { + compatible = "snps,dwc3"; + reg = <0x0 0xfe800000 0x0 0x100000>; + interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>; + dr_mode = "otg"; + phys = <&u2phy0_otg>; + phy-names = "usb2-phy"; + phy_type = "utmi_wide"; + snps,dis_enblslpm_quirk; + snps,dis-u2-freeclk-exists-quirk; + snps,dis_u2_susphy_quirk; + snps,dis-del-phy-power-chg-quirk; + status = "disabled"; + }; + }; + + usbdrd3_1: usb@fe900000 { + compatible = "rockchip,rk3399-dwc3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>, + <&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_GRF>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk", "grf_clk"; + status = "disabled"; + + usbdrd_dwc3_1: dwc3 { + compatible = "snps,dwc3"; + reg = <0x0 0xfe900000 0x0 0x100000>; + interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>; + dr_mode = "otg"; + phys = <&u2phy1_otg>; + phy-names = "usb2-phy"; + phy_type = "utmi_wide"; + snps,dis_enblslpm_quirk; + snps,dis-u2-freeclk-exists-quirk; + snps,dis_u2_susphy_quirk; + snps,dis-del-phy-power-chg-quirk; + status = "disabled"; + }; + }; + gic: interrupt-controller@fee00000 { compatible = "arm,gic-v3"; #interrupt-cells = <4>; diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts b/arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts index 7168cf818ad8..0173e93ab141 100644 --- a/arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts +++ b/arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts @@ -52,11 +52,6 @@ model = "UniPhier LD11 Reference Board"; compatible = "socionext,uniphier-ld11-ref", "socionext,uniphier-ld11"; - memory { - device_type = "memory"; - reg = <0 0x80000000 0 0x40000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -73,6 +68,11 @@ i2c4 = &i2c4; i2c5 = &i2c5; }; + + memory@80000000 { + device_type = "memory"; + reg = <0 0x80000000 0 0x40000000>; + }; }; ðsc { diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi index da881f5b6ed4..151c043b4835 100644 --- a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi +++ b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi @@ -140,7 +140,7 @@ <1 10 4>; }; - soc { + soc@0 { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -304,6 +304,8 @@ compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc"; reg = <0x5a000000 0x400>; interrupts = <0 78 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emmc>; clocks = <&sys_clk 4>; bus-width = <8>; mmc-ddr-1_8v; @@ -318,7 +320,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb0>; clocks = <&mio_clk 7>, <&mio_clk 8>, <&mio_clk 12>; - resets = <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>, <&sys_rst 8>; + resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 8>, + <&mio_rst 12>; }; usb1: usb@5a810100 { @@ -329,7 +332,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb1>; clocks = <&mio_clk 7>, <&mio_clk 9>, <&mio_clk 13>; - resets = <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>, <&sys_rst 8>; + resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 9>, + <&mio_rst 13>; }; usb2: usb@5a820100 { @@ -340,7 +344,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb2>; clocks = <&mio_clk 7>, <&mio_clk 10>, <&mio_clk 14>; - resets = <&mio_rst 7>, <&mio_rst 10>, <&mio_rst 14>, <&sys_rst 8>; + resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 10>, + <&mio_rst 14>; }; mioctrl@5b3e0000 { diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dts b/arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dts index 609162a1a322..fca4c479b469 100644 --- a/arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dts +++ b/arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dts @@ -52,11 +52,6 @@ model = "UniPhier LD20 Reference Board"; compatible = "socionext,uniphier-ld20-ref", "socionext,uniphier-ld20"; - memory { - device_type = "memory"; - reg = <0 0x80000000 0 0xc0000000>; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -73,6 +68,11 @@ i2c4 = &i2c4; i2c5 = &i2c5; }; + + memory@80000000 { + device_type = "memory"; + reg = <0 0x80000000 0 0xc0000000>; + }; }; ðsc { diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi index a6b3a70dae83..6193f11acb78 100644 --- a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi +++ b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi @@ -209,7 +209,7 @@ <1 10 4>; }; - soc { + soc@0 { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -378,6 +378,8 @@ compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc"; reg = <0x5a000000 0x400>; interrupts = <0 78 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emmc>; clocks = <&sys_clk 4>; bus-width = <8>; mmc-ddr-1_8v; diff --git a/arch/arm64/boot/dts/sprd/Makefile b/arch/arm64/boot/dts/sprd/Makefile index b658c5e09b15..f0535e6eaaaa 100644 --- a/arch/arm64/boot/dts/sprd/Makefile +++ b/arch/arm64/boot/dts/sprd/Makefile @@ -1,4 +1,5 @@ -dtb-$(CONFIG_ARCH_SPRD) += sc9836-openphone.dtb +dtb-$(CONFIG_ARCH_SPRD) += sc9836-openphone.dtb \ + sp9860g-1h10.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/sprd/sc9860.dtsi b/arch/arm64/boot/dts/sprd/sc9860.dtsi new file mode 100644 index 000000000000..7b7d8cedacda --- /dev/null +++ b/arch/arm64/boot/dts/sprd/sc9860.dtsi @@ -0,0 +1,569 @@ +/* + * Spreadtrum SC9860 SoC + * + * Copyright (C) 2016, Spreadtrum Communications Inc. + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include "whale2.dtsi" + +/ { + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + core1 { + cpu = <&CPU5>; + }; + core2 { + cpu = <&CPU6>; + }; + core3 { + cpu = <&CPU7>; + }; + }; + }; + + CPU0: cpu@530000 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530000>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + + CPU1: cpu@530001 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530001>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + + CPU2: cpu@530002 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530002>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + + CPU3: cpu@530003 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530003>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + + CPU4: cpu@530100 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530100>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + + CPU5: cpu@530101 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530101>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + + CPU6: cpu@530102 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530102>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + + CPU7: cpu@530103 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x530103>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD &CLUSTER_PD>; + }; + }; + + idle-states{ + entry-method = "arm,psci"; + + CORE_PD: core_pd { + compatible = "arm,idle-state"; + entry-latency-us = <1000>; + exit-latency-us = <700>; + min-residency-us = <2500>; + local-timer-stop; + arm,psci-suspend-param = <0x00010002>; + }; + + CLUSTER_PD: cluster_pd { + compatible = "arm,idle-state"; + entry-latency-us = <1000>; + exit-latency-us = <1000>; + min-residency-us = <3000>; + local-timer-stop; + arm,psci-suspend-param = <0x01010003>; + }; + }; + + gic: interrupt-controller@12001000 { + compatible = "arm,gic-400"; + reg = <0 0x12001000 0 0x1000>, + <0 0x12002000 0 0x2000>, + <0 0x12004000 0 0x2000>, + <0 0x12006000 0 0x2000>; + #interrupt-cells = <3>; + interrupt-controller; + interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(8) + | IRQ_TYPE_LEVEL_HIGH)>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(8) + | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(8) + | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) + | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) + | IRQ_TYPE_LEVEL_LOW)>; + }; + + pmu { + compatible = "arm,cortex-a53-pmu", "arm,armv8-pmuv3"; + interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>; + interrupt-affinity = <&CPU0>, + <&CPU1>, + <&CPU2>, + <&CPU3>, + <&CPU4>, + <&CPU5>, + <&CPU6>, + <&CPU7>; + }; + + soc { + funnel@10001000 { /* SoC Funnel */ + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0 0x10001000 0 0x1000>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + soc_funnel_out_port: endpoint { + remote-endpoint = <&etb_in>; + }; + }; + + port@1 { + reg = <0>; + soc_funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = + <&main_funnel_out_port>; + }; + }; + + port@2 { + reg = <4>; + soc_funnel_in_port1: endpoint { + slave-mode; + remote-endpioint = + <&stm_out_port>; + }; + }; + }; + }; + + etb@10003000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x10003000 0 0x1000>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + port { + etb_in: endpoint { + slave-mode; + remote-endpoint = + <&soc_funnel_out_port>; + }; + }; + }; + + stm@10006000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0 0x10006000 0 0x1000>, + <0 0x01000000 0 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + port { + stm_out_port: endpoint { + remote-endpoint = + <&soc_funnel_in_port1>; + }; + }; + }; + + funnel@11001000 { /* Cluster0 Funnel */ + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0 0x11001000 0 0x1000>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + cluster0_funnel_out_port: endpoint { + remote-endpoint = + <&cluster0_etf_in>; + }; + }; + + port@1 { + reg = <0>; + cluster0_funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = <&etm0_out>; + }; + }; + + port@2 { + reg = <1>; + cluster0_funnel_in_port1: endpoint { + slave-mode; + remote-endpoint = <&etm1_out>; + }; + }; + + port@3 { + reg = <2>; + cluster0_funnel_in_port2: endpoint { + slave-mode; + remote-endpoint = <&etm2_out>; + }; + }; + + port@4 { + reg = <4>; + cluster0_funnel_in_port3: endpoint { + slave-mode; + remote-endpoint = <&etm3_out>; + }; + }; + }; + }; + + funnel@11002000 { /* Cluster1 Funnel */ + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0 0x11002000 0 0x1000>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + cluster1_funnel_out_port: endpoint { + remote-endpoint = + <&cluster1_etf_in>; + }; + }; + + port@1 { + reg = <0>; + cluster1_funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = <&etm4_out>; + }; + }; + + port@2 { + reg = <1>; + cluster1_funnel_in_port1: endpoint { + slave-mode; + remote-endpoint = <&etm5_out>; + }; + }; + + port@3 { + reg = <2>; + cluster1_funnel_in_port2: endpoint { + slave-mode; + remote-endpoint = <&etm6_out>; + }; + }; + + port@4 { + reg = <3>; + cluster1_funnel_in_port3: endpoint { + slave-mode; + remote-endpoint = <&etm7_out>; + }; + }; + }; + }; + + etf@11003000 { /* ETF on Cluster0 */ + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x11003000 0 0x1000>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + cluster0_etf_out: endpoint { + remote-endpoint = + <&main_funnel_in_port0>; + }; + }; + + port@1 { + reg = <0>; + cluster0_etf_in: endpoint { + slave-mode; + remote-endpoint = + <&cluster0_funnel_out_port>; + }; + }; + }; + }; + + etf@11004000 { /* ETF on Cluster1 */ + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x11004000 0 0x1000>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + cluster1_etf_out: endpoint { + remote-endpoint = + <&main_funnel_in_port1>; + }; + }; + + port@1 { + reg = <0>; + cluster1_etf_in: endpoint { + slave-mode; + remote-endpoint = + <&cluster1_funnel_out_port>; + }; + }; + }; + }; + + funnel@11005000 { /* Main Funnel */ + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0 0x11005000 0 0x1000>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + main_funnel_out_port: endpoint { + remote-endpoint = + <&soc_funnel_in_port0>; + }; + }; + + port@1 { + reg = <0>; + main_funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = + <&cluster0_etf_out>; + }; + }; + + port@2 { + reg = <1>; + main_funnel_in_port1: endpoint { + slave-mode; + remote-endpoint = + <&cluster1_etf_out>; + }; + }; + }; + }; + + etm@11440000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11440000 0 0x1000>; + cpu = <&CPU0>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm0_out: endpoint { + remote-endpoint = + <&cluster0_funnel_in_port0>; + }; + }; + }; + + etm@11540000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11540000 0 0x1000>; + cpu = <&CPU1>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm1_out: endpoint { + remote-endpoint = + <&cluster0_funnel_in_port1>; + }; + }; + }; + + etm@11640000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11640000 0 0x1000>; + cpu = <&CPU2>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm2_out: endpoint { + remote-endpoint = + <&cluster0_funnel_in_port2>; + }; + }; + }; + + etm@11740000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11740000 0 0x1000>; + cpu = <&CPU3>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm3_out: endpoint { + remote-endpoint = + <&cluster0_funnel_in_port3>; + }; + }; + }; + + etm@11840000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11840000 0 0x1000>; + cpu = <&CPU4>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm4_out: endpoint { + remote-endpoint = + <&cluster1_funnel_in_port0>; + }; + }; + }; + + etm@11940000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11940000 0 0x1000>; + cpu = <&CPU5>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm5_out: endpoint { + remote-endpoint = + <&cluster1_funnel_in_port1>; + }; + }; + }; + + etm@11a40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11a40000 0 0x1000>; + cpu = <&CPU6>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm6_out: endpoint { + remote-endpoint = + <&cluster1_funnel_in_port2>; + }; + }; + }; + + etm@11b40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x11b40000 0 0x1000>; + cpu = <&CPU7>; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; + + port { + etm7_out: endpoint { + remote-endpoint = + <&cluster1_funnel_in_port3>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/sprd/sp9860g-1h10.dts b/arch/arm64/boot/dts/sprd/sp9860g-1h10.dts new file mode 100644 index 000000000000..ae0b28ce6319 --- /dev/null +++ b/arch/arm64/boot/dts/sprd/sp9860g-1h10.dts @@ -0,0 +1,56 @@ +/* + * Spreadtrum SP9860g board + * + * Copyright (C) 2017, Spreadtrum Communications Inc. + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/dts-v1/; + +#include "sc9860.dtsi" + +/ { + model = "Spreadtrum SP9860G 3GFHD Board"; + + compatible = "sprd,sp9860g-1h10", "sprd,sc9860"; + + aliases { + serial0 = &uart0; /* for Bluetooth */ + serial1 = &uart1; /* UART console */ + serial2 = &uart2; /* Reserved */ + serial3 = &uart3; /* for GPS */ + }; + + memory{ + device_type = "memory"; + reg = <0x0 0x80000000 0 0x60000000>, + <0x1 0x80000000 0 0x60000000>; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/sprd/whale2.dtsi b/arch/arm64/boot/dts/sprd/whale2.dtsi new file mode 100644 index 000000000000..7c217c547f85 --- /dev/null +++ b/arch/arm64/boot/dts/sprd/whale2.dtsi @@ -0,0 +1,71 @@ +/* + * Spreadtrum Whale2 platform peripherals + * + * Copyright (C) 2016, Spreadtrum Communications Inc. + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/ { + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ap-apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x70000000 0x10000000>; + + uart0: serial@0 { + compatible = "sprd,sc9860-uart", + "sprd,sc9836-uart"; + reg = <0x0 0x100>; + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ext_26m>; + status = "disabled"; + }; + + uart1: serial@100000 { + compatible = "sprd,sc9860-uart", + "sprd,sc9836-uart"; + reg = <0x100000 0x100>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ext_26m>; + status = "disabled"; + }; + + uart2: serial@200000 { + compatible = "sprd,sc9860-uart", + "sprd,sc9836-uart"; + reg = <0x200000 0x100>; + interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ext_26m>; + status = "disabled"; + }; + + uart3: serial@300000 { + compatible = "sprd,sc9860-uart", + "sprd,sc9836-uart"; + reg = <0x300000 0x100>; + interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ext_26m>; + status = "disabled"; + }; + }; + + }; + + ext_26m: ext-26m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + clock-output-names = "ext_26m"; + }; +}; diff --git a/arch/arm64/boot/dts/zte/zx296718-evb.dts b/arch/arm64/boot/dts/zte/zx296718-evb.dts index e164ff6de5fc..bb900d2bbcfb 100644 --- a/arch/arm64/boot/dts/zte/zx296718-evb.dts +++ b/arch/arm64/boot/dts/zte/zx296718-evb.dts @@ -57,6 +57,34 @@ reg = <0x40000000 0x40000000>; }; + sound0 { + compatible = "simple-audio-card"; + simple-audio-card,name = "zx_snd_spdif0"; + + simple-audio-card,cpu { + sound-dai = <&spdif0>; + }; + + simple-audio-card,codec { + sound-dai = <&hdmi>; + }; + }; +}; + +&emmc { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&sd1 { + status = "okay"; +}; + +&spdif0 { + status = "okay"; }; &uart0 { diff --git a/arch/arm64/boot/dts/zte/zx296718.dtsi b/arch/arm64/boot/dts/zte/zx296718.dtsi index b850b2cd0adc..316dc713268c 100644 --- a/arch/arm64/boot/dts/zte/zx296718.dtsi +++ b/arch/arm64/boot/dts/zte/zx296718.dtsi @@ -235,13 +235,6 @@ clock-output-names = "pll_mac"; }; - pll_vga: clk-pll-1073m { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <1073000000>; - clock-output-names = "pll_vga"; - }; - pll_mm0: clk-pll-1188m { compatible = "fixed-clock"; #clock-cells = <0>; @@ -305,6 +298,51 @@ status = "disabled"; }; + sd0: mmc@1110000 { + compatible = "zte,zx296718-dw-mshc"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x01110000 0x1000>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + fifo-depth = <32>; + data-addr = <0x200>; + fifo-watermark-aligned; + bus-width = <4>; + clock-frequency = <50000000>; + clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>; + clock-names = "biu", "ciu"; + num-slots = <1>; + max-frequency = <50000000>; + cap-sdio-irq; + cap-sd-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + sd-uhs-ddr50; + status = "disabled"; + }; + + sd1: mmc@1111000 { + compatible = "zte,zx296718-dw-mshc"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x01111000 0x1000>; + interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; + fifo-depth = <32>; + data-addr = <0x200>; + fifo-watermark-aligned; + bus-width = <4>; + clock-frequency = <167000000>; + clocks = <&topcrm SD1_AHB>, <&topcrm SD1_WCLK>; + clock-names = "biu", "ciu"; + num-slots = <1>; + max-frequency = <167000000>; + cap-sdio-irq; + cap-sd-highspeed; + status = "disabled"; + }; + dma: dma-controller@1460000 { compatible = "zte,zx296702-dma"; reg = <0x01460000 0x1000>; @@ -328,6 +366,47 @@ #clock-cells = <1>; }; + vou: vou@1440000 { + compatible = "zte,zx296718-vou"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1440000 0x10000>; + + dpc: dpc@0 { + compatible = "zte,zx296718-dpc"; + reg = <0x0000 0x1000>, <0x1000 0x1000>, + <0x5000 0x1000>, <0x6000 0x1000>, + <0xa000 0x1000>; + reg-names = "osd", "timing_ctrl", + "dtrc", "vou_ctrl", + "otfppu"; + interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&topcrm VOU_ACLK>, <&topcrm VOU_PPU_WCLK>, + <&topcrm VOU_MAIN_WCLK>, <&topcrm VOU_AUX_WCLK>; + clock-names = "aclk", "ppu_wclk", + "main_wclk", "aux_wclk"; + }; + + hdmi: hdmi@c000 { + compatible = "zte,zx296718-hdmi"; + reg = <0xc000 0x4000>; + interrupts = <GIC_SPI 82 IRQ_TYPE_EDGE_RISING>; + clocks = <&topcrm HDMI_OSC_CEC>, + <&topcrm HDMI_OSC_CLK>, + <&topcrm HDMI_XCLK>; + clock-names = "osc_cec", "osc_clk", "xclk"; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + tvenc: tvenc@2000 { + compatible = "zte,zx296718-tvenc"; + reg = <0x2000 0x1000>; + zte,tvenc-power-control = <&sysctrl 0x170 0x10>; + status = "disabled"; + }; + }; + topcrm: clock-controller@1461000 { compatible = "zte,zx296718-topcrm"; reg = <0x01461000 0x1000>; @@ -339,10 +418,43 @@ reg = <0x1463000 0x1000>; }; + emmc: mmc@1470000{ + compatible = "zte,zx296718-dw-mshc"; + reg = <0x01470000 0x1000>; + interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>; + zte,aon-syscon = <&aon_sysctrl>; + bus-width = <8>; + fifo-depth = <128>; + data-addr = <0x200>; + fifo-watermark-aligned; + clock-frequency = <167000000>; + clocks = <&topcrm EMMC_NAND_AHB>, <&topcrm EMMC_WCLK>; + clock-names = "biu", "ciu"; + max-frequency = <167000000>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + disable-wp; + status = "disabled"; + }; + audiocrm: clock-controller@1480000 { compatible = "zte,zx296718-audiocrm"; reg = <0x01480000 0x1000>; #clock-cells = <1>; }; + + spdif0: spdif@1488000 { + compatible = "zte,zx296702-spdif"; + reg = <0x1488000 0x1000>; + clocks = <&audiocrm AUDIO_SPDIF0_WCLK>; + clock-names = "tx"; + interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; + #sound-dai-cells = <0>; + dmas = <&dma 30>; + dma-names = "tx"; + status = "disabled"; + }; }; }; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 927ee18bbdf2..ce072859e3b2 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -186,6 +186,8 @@ CONFIG_HNS_ENET=y CONFIG_E1000E=y CONFIG_IGB=y CONFIG_IGBVF=y +CONFIG_MVPP2=y +CONFIG_MVNETA=y CONFIG_SKY2=y CONFIG_RAVB=y CONFIG_SMC91X=y @@ -250,8 +252,10 @@ CONFIG_I2C_DESIGNWARE_PLATFORM=y CONFIG_I2C_IMX=y CONFIG_I2C_MESON=y CONFIG_I2C_MV64XXX=y +CONFIG_I2C_PXA=y CONFIG_I2C_QUP=y CONFIG_I2C_RK3X=y +CONFIG_I2C_SH_MOBILE=y CONFIG_I2C_TEGRA=y CONFIG_I2C_UNIPHIER_F=y CONFIG_I2C_RCAR=y @@ -300,6 +304,7 @@ CONFIG_RENESAS_WDT=y CONFIG_S3C2410_WATCHDOG=y CONFIG_MESON_GXBB_WATCHDOG=m CONFIG_MESON_WATCHDOG=m +CONFIG_MFD_EXYNOS_LPASS=m CONFIG_MFD_MAX77620=y CONFIG_MFD_RK808=y CONFIG_MFD_SPMI_PMIC=y @@ -325,10 +330,20 @@ CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y # CONFIG_DVB_NET is not set CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m +CONFIG_VIDEO_SAMSUNG_S5P_MFC=m +CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m CONFIG_VIDEO_RENESAS_FCP=m CONFIG_VIDEO_RENESAS_VSP1=m CONFIG_DRM=m CONFIG_DRM_NOUVEAU=m +CONFIG_DRM_EXYNOS=m +CONFIG_DRM_EXYNOS5433_DECON=y +CONFIG_DRM_EXYNOS7_DECON=y +CONFIG_DRM_EXYNOS_DSI=y +# CONFIG_DRM_EXYNOS_DP is not set +CONFIG_DRM_EXYNOS_HDMI=y +CONFIG_DRM_EXYNOS_MIC=y CONFIG_DRM_RCAR_DU=m CONFIG_DRM_RCAR_HDMI=y CONFIG_DRM_RCAR_LVDS=y @@ -399,11 +414,15 @@ CONFIG_MMC_DW_EXYNOS=y CONFIG_MMC_DW_K3=y CONFIG_MMC_DW_ROCKCHIP=y CONFIG_MMC_SUNXI=y +CONFIG_MMC_SDHCI_XENON=y +CONFIG_MMC_BCM2835=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PWM=y CONFIG_LEDS_SYSCON=y CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_CPU=y CONFIG_RTC_CLASS=y @@ -470,6 +489,7 @@ CONFIG_PHY_RCAR_GEN3_USB2=y CONFIG_PHY_HI6220_USB=y CONFIG_PHY_ROCKCHIP_INNO_USB2=y CONFIG_PHY_ROCKCHIP_EMMC=y +CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_XGENE=y CONFIG_PHY_TEGRA_XUSB=y CONFIG_ARM_SCPI_PROTOCOL=y @@ -519,6 +539,7 @@ CONFIG_MEMTEST=y CONFIG_SECURITY=y CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_SAFEXCEL=m CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 4dac4afc95a5..3216e098c058 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -28,6 +28,7 @@ #include <linux/dma-contiguous.h> #include <linux/vmalloc.h> #include <linux/swiotlb.h> +#include <linux/pci.h> #include <asm/cacheflush.h> @@ -879,34 +880,26 @@ static const struct dma_map_ops iommu_dma_ops = { .mapping_error = iommu_dma_mapping_error, }; -/* - * TODO: Right now __iommu_setup_dma_ops() gets called too early to do - * everything it needs to - the device is only partially created and the - * IOMMU driver hasn't seen it yet, so it can't have a group. Thus we - * need this delayed attachment dance. Once IOMMU probe ordering is sorted - * to move the arch_setup_dma_ops() call later, all the notifier bits below - * become unnecessary, and will go away. - */ -struct iommu_dma_notifier_data { - struct list_head list; - struct device *dev; - const struct iommu_ops *ops; - u64 dma_base; - u64 size; -}; -static LIST_HEAD(iommu_dma_masters); -static DEFINE_MUTEX(iommu_dma_notifier_lock); +static int __init __iommu_dma_init(void) +{ + return iommu_dma_init(); +} +arch_initcall(__iommu_dma_init); -static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops, - u64 dma_base, u64 size) +static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, + const struct iommu_ops *ops) { - struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + struct iommu_domain *domain; + + if (!ops) + return; /* - * If the IOMMU driver has the DMA domain support that we require, - * then the IOMMU core will have already configured a group for this - * device, and allocated the default domain for that group. + * The IOMMU core code allocates the default DMA domain, which the + * underlying IOMMU driver needs to support via the dma-iommu layer. */ + domain = iommu_get_domain_for_dev(dev); + if (!domain) goto out_err; @@ -917,109 +910,11 @@ static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops, dev->dma_ops = &iommu_dma_ops; } - return true; + return; + out_err: - pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", + pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", dev_name(dev)); - return false; -} - -static void queue_iommu_attach(struct device *dev, const struct iommu_ops *ops, - u64 dma_base, u64 size) -{ - struct iommu_dma_notifier_data *iommudata; - - iommudata = kzalloc(sizeof(*iommudata), GFP_KERNEL); - if (!iommudata) - return; - - iommudata->dev = dev; - iommudata->ops = ops; - iommudata->dma_base = dma_base; - iommudata->size = size; - - mutex_lock(&iommu_dma_notifier_lock); - list_add(&iommudata->list, &iommu_dma_masters); - mutex_unlock(&iommu_dma_notifier_lock); -} - -static int __iommu_attach_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct iommu_dma_notifier_data *master, *tmp; - - if (action != BUS_NOTIFY_BIND_DRIVER) - return 0; - - mutex_lock(&iommu_dma_notifier_lock); - list_for_each_entry_safe(master, tmp, &iommu_dma_masters, list) { - if (data == master->dev && do_iommu_attach(master->dev, - master->ops, master->dma_base, master->size)) { - list_del(&master->list); - kfree(master); - break; - } - } - mutex_unlock(&iommu_dma_notifier_lock); - return 0; -} - -static int __init register_iommu_dma_ops_notifier(struct bus_type *bus) -{ - struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL); - int ret; - - if (!nb) - return -ENOMEM; - - nb->notifier_call = __iommu_attach_notifier; - - ret = bus_register_notifier(bus, nb); - if (ret) { - pr_warn("Failed to register DMA domain notifier; IOMMU DMA ops unavailable on bus '%s'\n", - bus->name); - kfree(nb); - } - return ret; -} - -static int __init __iommu_dma_init(void) -{ - int ret; - - ret = iommu_dma_init(); - if (!ret) - ret = register_iommu_dma_ops_notifier(&platform_bus_type); - if (!ret) - ret = register_iommu_dma_ops_notifier(&amba_bustype); -#ifdef CONFIG_PCI - if (!ret) - ret = register_iommu_dma_ops_notifier(&pci_bus_type); -#endif - return ret; -} -arch_initcall(__iommu_dma_init); - -static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *ops) -{ - struct iommu_group *group; - - if (!ops) - return; - /* - * TODO: As a concession to the future, we're ready to handle being - * called both early and late (i.e. after bus_add_device). Once all - * the platform bus code is reworked to call us late and the notifier - * junk above goes away, move the body of do_iommu_attach here. - */ - group = iommu_group_get(dev); - if (group) { - do_iommu_attach(dev, ops, dma_base, size); - iommu_group_put(group); - } else { - queue_iommu_attach(dev, ops, dma_base, size); - } } void arch_teardown_dma_ops(struct device *dev) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d8834e8bfb05..964da1891ea9 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -146,6 +146,7 @@ config PPC select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if PPC64 select ARCH_WANT_IPC_PARSE_VERSION + select ARCH_WEAK_RELEASE_ACQUIRE select BINFMT_ELF select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 44101196d02b..41a407328667 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -939,3 +939,9 @@ ENTRY(__retl_o1) retl mov %o1, %o0 ENDPROC(__retl_o1) + +ENTRY(__retl_o1_asi) + wr %o5, 0x0, %asi + retl + mov %o1, %o0 +ENDPROC(__retl_o1_asi) diff --git a/arch/sparc/kernel/led.c b/arch/sparc/kernel/led.c index 44a3ed93c214..e278bf52963b 100644 --- a/arch/sparc/kernel/led.c +++ b/arch/sparc/kernel/led.c @@ -70,16 +70,9 @@ static ssize_t led_proc_write(struct file *file, const char __user *buffer, if (count > LED_MAX_LENGTH) count = LED_MAX_LENGTH; - buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (copy_from_user(buf, buffer, count)) { - kfree(buf); - return -EFAULT; - } - - buf[count] = '\0'; + buf = memdup_user_nul(buffer, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); /* work around \n when echo'ing into proc */ if (buf[count - 1] == '\n') diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 6f06058c5ae7..6722308d1a98 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -148,7 +148,7 @@ static void __init boot_flags_init(char *commands) { while (*commands) { /* Move to the start of the next "argument". */ - while (*commands && *commands == ' ') + while (*commands == ' ') commands++; /* Process any command switches, otherwise skip it. */ diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 6b7331d198e9..422b17880955 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -133,7 +133,7 @@ static void __init boot_flags_init(char *commands) { while (*commands) { /* Move to the start of the next "argument". */ - while (*commands && *commands == ' ') + while (*commands == ' ') commands++; /* Process any command switches, otherwise skip it. */ diff --git a/arch/sparc/lib/GENbzero.S b/arch/sparc/lib/GENbzero.S index 8e7a843ddd88..2fbf6297d57c 100644 --- a/arch/sparc/lib/GENbzero.S +++ b/arch/sparc/lib/GENbzero.S @@ -8,7 +8,7 @@ 98: x,y; \ .section __ex_table,"a";\ .align 4; \ - .word 98b, __retl_o1; \ + .word 98b, __retl_o1_asi;\ .text; \ .align 4; diff --git a/arch/sparc/lib/NGbzero.S b/arch/sparc/lib/NGbzero.S index beab29bf419b..33053bdf3766 100644 --- a/arch/sparc/lib/NGbzero.S +++ b/arch/sparc/lib/NGbzero.S @@ -8,7 +8,7 @@ 98: x,y; \ .section __ex_table,"a";\ .align 4; \ - .word 98b, __retl_o1; \ + .word 98b, __retl_o1_asi;\ .text; \ .align 4; diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index d4c8011a2293..4b1724059909 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -514,6 +514,9 @@ int tboot_force_iommu(void) if (!tboot_enabled()) return 0; + if (!intel_iommu_tboot_noforce) + return 1; + if (no_iommu || swiotlb || dmar_disabled) pr_warning("Forcing Intel-IOMMU to enabled\n"); diff --git a/drivers/Kconfig b/drivers/Kconfig index 117ca14ccf85..ba2901e76769 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -204,4 +204,6 @@ source "drivers/fpga/Kconfig" source "drivers/fsi/Kconfig" +source "drivers/tee/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index edba1edc6654..cfabd141dba2 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -180,3 +180,4 @@ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ obj-$(CONFIG_FSI) += fsi/ +obj-$(CONFIG_TEE) += tee/ diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d78065cc9324..b1aacfc62b1f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -50,6 +50,7 @@ acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o acpi-y += sysfs.o acpi-y += property.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.o +acpi-$(CONFIG_X86) += x86/utils.o acpi-$(CONFIG_DEBUG_FS) += debugfs.o acpi-$(CONFIG_ACPI_NUMA) += numa.o acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 17a1eb14847a..fc6c416f8724 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -106,6 +106,16 @@ static const struct apd_device_desc vulcan_spi_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 133000000, }; + +static const struct apd_device_desc hip07_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 200000000, +}; + +static const struct apd_device_desc hip08_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 250000000, +}; #endif #else @@ -170,6 +180,8 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, { "BRCM900D", APD_ADDR(vulcan_spi_desc) }, { "CAV900D", APD_ADDR(vulcan_spi_desc) }, + { "HISI0A21", APD_ADDR(hip07_i2c_desc) }, + { "HISI0A22", APD_ADDR(hip08_i2c_desc) }, #endif { } }; diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 5edfd9c49044..10347e3d73ad 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -143,6 +143,22 @@ static void lpss_deassert_reset(struct lpss_private_data *pdata) writel(val, pdata->mmio_base + offset); } +/* + * BYT PWM used for backlight control by the i915 driver on systems without + * the Crystal Cove PMIC. + */ +static struct pwm_lookup byt_pwm_lookup[] = { + PWM_LOOKUP_WITH_MODULE("80860F09:00", 0, "0000:00:02.0", + "pwm_backlight", 0, PWM_POLARITY_NORMAL, + "pwm-lpss-platform"), +}; + +static void byt_pwm_setup(struct lpss_private_data *pdata) +{ + if (!acpi_dev_present("INT33FD", NULL, -1)) + pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); +} + #define LPSS_I2C_ENABLE 0x6c static void byt_i2c_setup(struct lpss_private_data *pdata) @@ -200,6 +216,7 @@ static const struct lpss_device_desc lpt_sdio_dev_desc = { static const struct lpss_device_desc byt_pwm_dev_desc = { .flags = LPSS_SAVE_CTX, + .setup = byt_pwm_setup, }; static const struct lpss_device_desc bsw_pwm_dev_desc = { diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 32d93edbc479..dea65306b687 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -2,7 +2,7 @@ # Makefile for ACPICA Core interpreter # -ccflags-y := -Os -DBUILDING_ACPICA +ccflags-y := -Os -D_LINUX -DBUILDING_ACPICA ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # use acpi.o to put all files here into acpi.o modparam namespace diff --git a/drivers/acpi/acpica/acconvert.h b/drivers/acpi/acpica/acconvert.h new file mode 100644 index 000000000000..c84223b60b35 --- /dev/null +++ b/drivers/acpi/acpica/acconvert.h @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * Module Name: acapps - common include for ACPI applications/tools + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2017, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACCONVERT +#define _ACCONVERT + +/* Definitions for comment state */ + +#define ASL_COMMENT_STANDARD 1 +#define ASLCOMMENT_INLINE 2 +#define ASL_COMMENT_OPEN_PAREN 3 +#define ASL_COMMENT_CLOSE_PAREN 4 +#define ASL_COMMENT_CLOSE_BRACE 5 + +/* Definitions for comment print function*/ + +#define AML_COMMENT_STANDARD 1 +#define AMLCOMMENT_INLINE 2 +#define AML_COMMENT_END_NODE 3 +#define AML_NAMECOMMENT 4 +#define AML_COMMENT_CLOSE_BRACE 5 +#define AML_COMMENT_ENDBLK 6 +#define AML_COMMENT_INCLUDE 7 + +#ifdef ACPI_ASL_COMPILER +/* + * cvcompiler + */ +void +cv_process_comment(struct asl_comment_state current_state, + char *string_buffer, int c1); + +void +cv_process_comment_type2(struct asl_comment_state current_state, + char *string_buffer); + +u32 cv_calculate_comment_lengths(union acpi_parse_object *op); + +void cv_process_comment_state(char input); + +char *cv_append_inline_comment(char *inline_comment, char *to_add); + +void cv_add_to_comment_list(char *to_add); + +void cv_place_comment(u8 type, char *comment_string); + +u32 cv_parse_op_block_type(union acpi_parse_object *op); + +struct acpi_comment_node *cv_comment_node_calloc(void); + +void cg_write_aml_def_block_comment(union acpi_parse_object *op); + +void +cg_write_one_aml_comment(union acpi_parse_object *op, + char *comment_to_print, u8 input_option); + +void cg_write_aml_comment(union acpi_parse_object *op); + +/* + * cvparser + */ +void +cv_init_file_tree(struct acpi_table_header *table, + u8 *aml_start, u32 aml_length); + +void cv_clear_op_comments(union acpi_parse_object *op); + +struct acpi_file_node *cv_filename_exists(char *filename, + struct acpi_file_node *head); + +void cv_label_file_node(union acpi_parse_object *op); + +void +cv_capture_list_comments(struct acpi_parse_state *parser_state, + struct acpi_comment_node *list_head, + struct acpi_comment_node *list_tail); + +void cv_capture_comments_only(struct acpi_parse_state *parser_state); + +void cv_capture_comments(struct acpi_walk_state *walk_state); + +void cv_transfer_comments(union acpi_parse_object *op); + +/* + * cvdisasm + */ +void cv_switch_files(u32 level, union acpi_parse_object *op); + +u8 cv_file_has_switched(union acpi_parse_object *op); + +void cv_close_paren_write_comment(union acpi_parse_object *op, u32 level); + +void cv_close_brace_write_comment(union acpi_parse_object *op, u32 level); + +void +cv_print_one_comment_list(struct acpi_comment_node *comment_list, u32 level); + +void +cv_print_one_comment_type(union acpi_parse_object *op, + u8 comment_type, char *end_str, u32 level); + +#endif + +#endif /* _ACCONVERT */ diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 1d955fe216c4..abe8c316908c 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -370,6 +370,59 @@ ACPI_GLOBAL(const char, *acpi_gbl_pld_shape_list[]); #endif +/* + * Meant for the -ca option. + */ +ACPI_INIT_GLOBAL(char *, acpi_gbl_current_inline_comment, NULL); +ACPI_INIT_GLOBAL(char *, acpi_gbl_current_end_node_comment, NULL); +ACPI_INIT_GLOBAL(char *, acpi_gbl_current_open_brace_comment, NULL); +ACPI_INIT_GLOBAL(char *, acpi_gbl_current_close_brace_comment, NULL); + +ACPI_INIT_GLOBAL(char *, acpi_gbl_root_filename, NULL); +ACPI_INIT_GLOBAL(char *, acpi_gbl_current_filename, NULL); +ACPI_INIT_GLOBAL(char *, acpi_gbl_current_parent_filename, NULL); +ACPI_INIT_GLOBAL(char *, acpi_gbl_current_include_filename, NULL); + +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_last_list_head, NULL); + +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_def_blk_comment_list_head, + NULL); +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_def_blk_comment_list_tail, + NULL); + +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_reg_comment_list_head, + NULL); +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_reg_comment_list_tail, + NULL); + +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_inc_comment_list_head, + NULL); +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_inc_comment_list_tail, + NULL); + +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_end_blk_comment_list_head, + NULL); +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_end_blk_comment_list_tail, + NULL); + +ACPI_INIT_GLOBAL(struct acpi_comment_addr_node, + *acpi_gbl_comment_addr_list_head, NULL); + +ACPI_INIT_GLOBAL(union acpi_parse_object, *acpi_gbl_current_scope, NULL); + +ACPI_INIT_GLOBAL(struct acpi_file_node, *acpi_gbl_file_tree_root, NULL); + +ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_reg_comment_cache); +ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_comment_addr_cache); +ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_file_cache); + +ACPI_INIT_GLOBAL(u8, gbl_capture_comments, FALSE); + +ACPI_INIT_GLOBAL(u8, acpi_gbl_debug_asl_conversion, FALSE); +ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_conv_debug_file, NULL); + +ACPI_GLOBAL(char, acpi_gbl_table_sig[4]); + /***************************************************************************** * * Application globals diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 8fd495e8fdce..f9b3f7fef462 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -53,7 +53,7 @@ typedef u32 acpi_mutex_handle; /* Total number of aml opcodes defined */ -#define AML_NUM_OPCODES 0x82 +#define AML_NUM_OPCODES 0x83 /* Forward declarations */ @@ -754,21 +754,52 @@ union acpi_parse_value { #define ACPI_DISASM_ONLY_MEMBERS(a) #endif +#if defined(ACPI_ASL_COMPILER) +#define ACPI_CONVERTER_ONLY_MEMBERS(a) a; +#else +#define ACPI_CONVERTER_ONLY_MEMBERS(a) +#endif + #define ACPI_PARSE_COMMON \ - union acpi_parse_object *parent; /* Parent op */\ - u8 descriptor_type; /* To differentiate various internal objs */\ - u8 flags; /* Type of Op */\ - u16 aml_opcode; /* AML opcode */\ - u8 *aml; /* Address of declaration in AML */\ - union acpi_parse_object *next; /* Next op */\ - struct acpi_namespace_node *node; /* For use by interpreter */\ - union acpi_parse_value value; /* Value or args associated with the opcode */\ - u8 arg_list_length; /* Number of elements in the arg list */\ - ACPI_DISASM_ONLY_MEMBERS (\ - u16 disasm_flags; /* Used during AML disassembly */\ - u8 disasm_opcode; /* Subtype used for disassembly */\ - char *operator_symbol;/* Used for C-style operator name strings */\ - char aml_op_name[16]) /* Op name (debug only) */ + union acpi_parse_object *parent; /* Parent op */\ + u8 descriptor_type; /* To differentiate various internal objs */\ + u8 flags; /* Type of Op */\ + u16 aml_opcode; /* AML opcode */\ + u8 *aml; /* Address of declaration in AML */\ + union acpi_parse_object *next; /* Next op */\ + struct acpi_namespace_node *node; /* For use by interpreter */\ + union acpi_parse_value value; /* Value or args associated with the opcode */\ + u8 arg_list_length; /* Number of elements in the arg list */\ + ACPI_DISASM_ONLY_MEMBERS (\ + u16 disasm_flags; /* Used during AML disassembly */\ + u8 disasm_opcode; /* Subtype used for disassembly */\ + char *operator_symbol; /* Used for C-style operator name strings */\ + char aml_op_name[16]) /* Op name (debug only) */\ + ACPI_CONVERTER_ONLY_MEMBERS (\ + char *inline_comment; /* Inline comment */\ + char *end_node_comment; /* End of node comment */\ + char *name_comment; /* Comment associated with the first parameter of the name node */\ + char *close_brace_comment; /* Comments that come after } on the same as } */\ + struct acpi_comment_node *comment_list; /* comments that appears before this node */\ + struct acpi_comment_node *end_blk_comment; /* comments that at the end of a block but before ) or } */\ + char *cv_filename; /* Filename associated with this node. Used for ASL/ASL+ converter */\ + char *cv_parent_filename) /* Parent filename associated with this node. Used for ASL/ASL+ converter */ + +/* categories of comments */ + +typedef enum { + STANDARD_COMMENT = 1, + INLINE_COMMENT, + ENDNODE_COMMENT, + OPENBRACE_COMMENT, + CLOSE_BRACE_COMMENT, + STD_DEFBLK_COMMENT, + END_DEFBLK_COMMENT, + FILENAME_COMMENT, + PARENTFILENAME_COMMENT, + ENDBLK_COMMENT, + INCLUDE_COMMENT +} asl_comment_types; /* Internal opcodes for disasm_opcode field above */ @@ -784,9 +815,38 @@ union acpi_parse_value { #define ACPI_DASM_LNOT_SUFFIX 0x09 /* End of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_HID_STRING 0x0A /* String is a _HID or _CID */ #define ACPI_DASM_IGNORE_SINGLE 0x0B /* Ignore the opcode but not it's children */ -#define ACPI_DASM_SWITCH_PREDICATE 0x0C /* Object is a predicate for a Switch or Case block */ -#define ACPI_DASM_CASE 0x0D /* If/Else is a Case in a Switch/Case block */ -#define ACPI_DASM_DEFAULT 0x0E /* Else is a Default in a Switch/Case block */ +#define ACPI_DASM_SWITCH 0x0C /* While is a Switch */ +#define ACPI_DASM_SWITCH_PREDICATE 0x0D /* Object is a predicate for a Switch or Case block */ +#define ACPI_DASM_CASE 0x0E /* If/Else is a Case in a Switch/Case block */ +#define ACPI_DASM_DEFAULT 0x0F /* Else is a Default in a Switch/Case block */ + +/* + * List struct used in the -ca option + */ +struct acpi_comment_node { + char *comment; + struct acpi_comment_node *next; +}; + +struct acpi_comment_addr_node { + u8 *addr; + struct acpi_comment_addr_node *next; +}; + +/* + * File node - used for "Include" operator file stack and + * depdendency tree for the -ca option + */ +struct acpi_file_node { + void *file; + char *filename; + char *file_start; /* Points to AML and indicates when the AML for this particular file starts. */ + char *file_end; /* Points to AML and indicates when the AML for this particular file ends. */ + struct acpi_file_node *next; + struct acpi_file_node *parent; + u8 include_written; + struct acpi_comment_node *include_comment; +}; /* * Generic operation (for example: If, While, Store) @@ -813,6 +873,8 @@ struct acpi_parse_obj_asl { ACPI_PARSE_COMMON union acpi_parse_object *child; union acpi_parse_object *parent_method; char *filename; + u8 file_changed; + char *parent_filename; char *external_name; char *namepath; char name_seg[4]; @@ -842,6 +904,14 @@ union acpi_parse_object { struct acpi_parse_obj_asl asl; }; +struct asl_comment_state { + u8 comment_type; + u32 spaces_before; + union acpi_parse_object *latest_parse_node; + union acpi_parse_object *parsing_paren_brace_node; + u8 capture_comments; +}; + /* * Parse state - one state per parser invocation and each control * method. diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index c3337514e0ed..c7f0c96cc00f 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -493,4 +493,39 @@ #define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) +/* + * Macors used for the ASL-/ASL+ converter utility + */ +#ifdef ACPI_ASL_COMPILER + +#define ASL_CV_LABEL_FILENODE(a) cv_label_file_node(a); +#define ASL_CV_CAPTURE_COMMENTS_ONLY(a) cv_capture_comments_only (a); +#define ASL_CV_CAPTURE_COMMENTS(a) cv_capture_comments (a); +#define ASL_CV_TRANSFER_COMMENTS(a) cv_transfer_comments (a); +#define ASL_CV_CLOSE_PAREN(a,b) cv_close_paren_write_comment(a,b); +#define ASL_CV_CLOSE_BRACE(a,b) cv_close_brace_write_comment(a,b); +#define ASL_CV_SWITCH_FILES(a,b) cv_switch_files(a,b); +#define ASL_CV_CLEAR_OP_COMMENTS(a) cv_clear_op_comments(a); +#define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d) cv_print_one_comment_type (a,b,c,d); +#define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b) cv_print_one_comment_list (a,b); +#define ASL_CV_FILE_HAS_SWITCHED(a) cv_file_has_switched(a) +#define ASL_CV_INIT_FILETREE(a,b,c) cv_init_file_tree(a,b,c); + +#else + +#define ASL_CV_LABEL_FILENODE(a) +#define ASL_CV_CAPTURE_COMMENTS_ONLY(a) +#define ASL_CV_CAPTURE_COMMENTS(a) +#define ASL_CV_TRANSFER_COMMENTS(a) +#define ASL_CV_CLOSE_PAREN(a,b) acpi_os_printf (")"); +#define ASL_CV_CLOSE_BRACE(a,b) acpi_os_printf ("}"); +#define ASL_CV_SWITCH_FILES(a,b) +#define ASL_CV_CLEAR_OP_COMMENTS(a) +#define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d) +#define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b) +#define ASL_CV_FILE_HAS_SWITCHED(a) 0 +#define ASL_CV_INIT_FILETREE(a,b,c) + +#endif + #endif /* ACMACROS_H */ diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index e758f098ff4b..a5d9af758c52 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -90,6 +90,7 @@ #define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) #define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA) #define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_COMMENT_OP ARGP_LIST2 (ARGP_BYTEDATA, ARGP_COMMENT) #define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SIMPLENAME, ARGP_TARGET) @@ -223,6 +224,7 @@ #define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_BYTE_OP ARGI_INVALID_OPCODE #define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE +#define ARGI_COMMENT_OP ARGI_INVALID_OPCODE #define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_ANYTYPE, ARGI_ANYTYPE, ARGI_TARGETREF) #define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) #define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index b536fd471292..176f7e9b4d0e 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -48,11 +48,8 @@ /* primary opcodes */ -#define AML_NULL_CHAR (u16) 0x00 - #define AML_ZERO_OP (u16) 0x00 #define AML_ONE_OP (u16) 0x01 -#define AML_UNASSIGNED (u16) 0x02 #define AML_ALIAS_OP (u16) 0x06 #define AML_NAME_OP (u16) 0x08 #define AML_BYTE_OP (u16) 0x0a @@ -63,17 +60,15 @@ #define AML_SCOPE_OP (u16) 0x10 #define AML_BUFFER_OP (u16) 0x11 #define AML_PACKAGE_OP (u16) 0x12 -#define AML_VAR_PACKAGE_OP (u16) 0x13 /* ACPI 2.0 */ +#define AML_VARIABLE_PACKAGE_OP (u16) 0x13 /* ACPI 2.0 */ #define AML_METHOD_OP (u16) 0x14 #define AML_EXTERNAL_OP (u16) 0x15 /* ACPI 6.0 */ #define AML_DUAL_NAME_PREFIX (u16) 0x2e -#define AML_MULTI_NAME_PREFIX_OP (u16) 0x2f -#define AML_NAME_CHAR_SUBSEQ (u16) 0x30 -#define AML_NAME_CHAR_FIRST (u16) 0x41 -#define AML_EXTENDED_OP_PREFIX (u16) 0x5b +#define AML_MULTI_NAME_PREFIX (u16) 0x2f +#define AML_EXTENDED_PREFIX (u16) 0x5b #define AML_ROOT_PREFIX (u16) 0x5c #define AML_PARENT_PREFIX (u16) 0x5e -#define AML_LOCAL_OP (u16) 0x60 +#define AML_FIRST_LOCAL_OP (u16) 0x60 /* Used for Local op # calculations */ #define AML_LOCAL0 (u16) 0x60 #define AML_LOCAL1 (u16) 0x61 #define AML_LOCAL2 (u16) 0x62 @@ -82,7 +77,7 @@ #define AML_LOCAL5 (u16) 0x65 #define AML_LOCAL6 (u16) 0x66 #define AML_LOCAL7 (u16) 0x67 -#define AML_ARG_OP (u16) 0x68 +#define AML_FIRST_ARG_OP (u16) 0x68 /* Used for Arg op # calculations */ #define AML_ARG0 (u16) 0x68 #define AML_ARG1 (u16) 0x69 #define AML_ARG2 (u16) 0x6a @@ -93,7 +88,7 @@ #define AML_STORE_OP (u16) 0x70 #define AML_REF_OF_OP (u16) 0x71 #define AML_ADD_OP (u16) 0x72 -#define AML_CONCAT_OP (u16) 0x73 +#define AML_CONCATENATE_OP (u16) 0x73 #define AML_SUBTRACT_OP (u16) 0x74 #define AML_INCREMENT_OP (u16) 0x75 #define AML_DECREMENT_OP (u16) 0x76 @@ -110,7 +105,7 @@ #define AML_FIND_SET_LEFT_BIT_OP (u16) 0x81 #define AML_FIND_SET_RIGHT_BIT_OP (u16) 0x82 #define AML_DEREF_OF_OP (u16) 0x83 -#define AML_CONCAT_RES_OP (u16) 0x84 /* ACPI 2.0 */ +#define AML_CONCATENATE_TEMPLATE_OP (u16) 0x84 /* ACPI 2.0 */ #define AML_MOD_OP (u16) 0x85 /* ACPI 2.0 */ #define AML_NOTIFY_OP (u16) 0x86 #define AML_SIZE_OF_OP (u16) 0x87 @@ -122,18 +117,18 @@ #define AML_CREATE_BIT_FIELD_OP (u16) 0x8d #define AML_OBJECT_TYPE_OP (u16) 0x8e #define AML_CREATE_QWORD_FIELD_OP (u16) 0x8f /* ACPI 2.0 */ -#define AML_LAND_OP (u16) 0x90 -#define AML_LOR_OP (u16) 0x91 -#define AML_LNOT_OP (u16) 0x92 -#define AML_LEQUAL_OP (u16) 0x93 -#define AML_LGREATER_OP (u16) 0x94 -#define AML_LLESS_OP (u16) 0x95 +#define AML_LOGICAL_AND_OP (u16) 0x90 +#define AML_LOGICAL_OR_OP (u16) 0x91 +#define AML_LOGICAL_NOT_OP (u16) 0x92 +#define AML_LOGICAL_EQUAL_OP (u16) 0x93 +#define AML_LOGICAL_GREATER_OP (u16) 0x94 +#define AML_LOGICAL_LESS_OP (u16) 0x95 #define AML_TO_BUFFER_OP (u16) 0x96 /* ACPI 2.0 */ -#define AML_TO_DECSTRING_OP (u16) 0x97 /* ACPI 2.0 */ -#define AML_TO_HEXSTRING_OP (u16) 0x98 /* ACPI 2.0 */ +#define AML_TO_DECIMAL_STRING_OP (u16) 0x97 /* ACPI 2.0 */ +#define AML_TO_HEX_STRING_OP (u16) 0x98 /* ACPI 2.0 */ #define AML_TO_INTEGER_OP (u16) 0x99 /* ACPI 2.0 */ #define AML_TO_STRING_OP (u16) 0x9c /* ACPI 2.0 */ -#define AML_COPY_OP (u16) 0x9d /* ACPI 2.0 */ +#define AML_COPY_OBJECT_OP (u16) 0x9d /* ACPI 2.0 */ #define AML_MID_OP (u16) 0x9e /* ACPI 2.0 */ #define AML_CONTINUE_OP (u16) 0x9f /* ACPI 2.0 */ #define AML_IF_OP (u16) 0xa0 @@ -142,18 +137,27 @@ #define AML_NOOP_OP (u16) 0xa3 #define AML_RETURN_OP (u16) 0xa4 #define AML_BREAK_OP (u16) 0xa5 -#define AML_BREAK_POINT_OP (u16) 0xcc +#define AML_COMMENT_OP (u16) 0xa9 +#define AML_BREAKPOINT_OP (u16) 0xcc #define AML_ONES_OP (u16) 0xff -/* prefixed opcodes */ +/* + * Combination opcodes (actually two one-byte opcodes) + * Used by the disassembler and iASL compiler + */ +#define AML_LOGICAL_GREATER_EQUAL_OP (u16) 0x9295 /* LNot (LLess) */ +#define AML_LOGICAL_LESS_EQUAL_OP (u16) 0x9294 /* LNot (LGreater) */ +#define AML_LOGICAL_NOT_EQUAL_OP (u16) 0x9293 /* LNot (LEqual) */ + +/* Prefixed (2-byte) opcodes (with AML_EXTENDED_PREFIX) */ -#define AML_EXTENDED_OPCODE (u16) 0x5b00 /* prefix for 2-byte opcodes */ +#define AML_EXTENDED_OPCODE (u16) 0x5b00 /* Prefix for 2-byte opcodes */ #define AML_MUTEX_OP (u16) 0x5b01 #define AML_EVENT_OP (u16) 0x5b02 -#define AML_SHIFT_RIGHT_BIT_OP (u16) 0x5b10 -#define AML_SHIFT_LEFT_BIT_OP (u16) 0x5b11 -#define AML_COND_REF_OF_OP (u16) 0x5b12 +#define AML_SHIFT_RIGHT_BIT_OP (u16) 0x5b10 /* Obsolete, not in ACPI spec */ +#define AML_SHIFT_LEFT_BIT_OP (u16) 0x5b11 /* Obsolete, not in ACPI spec */ +#define AML_CONDITIONAL_REF_OF_OP (u16) 0x5b12 #define AML_CREATE_FIELD_OP (u16) 0x5b13 #define AML_LOAD_TABLE_OP (u16) 0x5b1f /* ACPI 2.0 */ #define AML_LOAD_OP (u16) 0x5b20 @@ -175,21 +179,13 @@ #define AML_FIELD_OP (u16) 0x5b81 #define AML_DEVICE_OP (u16) 0x5b82 #define AML_PROCESSOR_OP (u16) 0x5b83 -#define AML_POWER_RES_OP (u16) 0x5b84 +#define AML_POWER_RESOURCE_OP (u16) 0x5b84 #define AML_THERMAL_ZONE_OP (u16) 0x5b85 #define AML_INDEX_FIELD_OP (u16) 0x5b86 #define AML_BANK_FIELD_OP (u16) 0x5b87 #define AML_DATA_REGION_OP (u16) 0x5b88 /* ACPI 2.0 */ /* - * Combination opcodes (actually two one-byte opcodes) - * Used by the disassembler and iASL compiler - */ -#define AML_LGREATEREQUAL_OP (u16) 0x9295 -#define AML_LLESSEQUAL_OP (u16) 0x9294 -#define AML_LNOTEQUAL_OP (u16) 0x9293 - -/* * Opcodes for "Field" operators */ #define AML_FIELD_OFFSET_OP (u8) 0x00 @@ -241,6 +237,7 @@ #define ARGP_SIMPLENAME 0x12 /* name_string | local_term | arg_term */ #define ARGP_NAME_OR_REF 0x13 /* For object_type only */ #define ARGP_MAX 0x13 +#define ARGP_COMMENT 0x14 /* * Resolved argument types for the AML Interpreter @@ -308,24 +305,19 @@ #define ARGI_INVALID_OPCODE 0xFFFFFFFF /* - * hash offsets - */ -#define AML_EXTOP_HASH_OFFSET 22 -#define AML_LNOT_HASH_OFFSET 19 - -/* - * opcode groups and types + * Some of the flags and types below are of the form: + * + * AML_FLAGS_EXEC_#A_#T,#R, or + * AML_TYPE_EXEC_#A_#T,#R where: + * + * #A is the number of required arguments + * #T is the number of target operands + * #R indicates whether there is a return value */ -#define OPGRP_NAMED 0x01 -#define OPGRP_FIELD 0x02 -#define OPGRP_BYTELIST 0x04 /* - * Opcode information + * Opcode information flags */ - -/* Opcode flags */ - #define AML_LOGICAL 0x0001 #define AML_LOGICAL_NUMERIC 0x0002 #define AML_MATH 0x0004 @@ -342,7 +334,7 @@ #define AML_CONSTANT 0x2000 #define AML_NO_OPERAND_RESOLVE 0x4000 -/* Convenient flag groupings */ +/* Convenient flag groupings of the flags above */ #define AML_FLAGS_EXEC_0A_0T_1R AML_HAS_RETVAL #define AML_FLAGS_EXEC_1A_0T_0R AML_HAS_ARGS /* Monadic1 */ @@ -359,7 +351,7 @@ /* * The opcode Type is used in a dispatch table, do not change - * without updating the table. + * or add anything new without updating the table. */ #define AML_TYPE_EXEC_0A_0T_1R 0x00 #define AML_TYPE_EXEC_1A_0T_0R 0x01 /* Monadic1 */ @@ -385,7 +377,7 @@ #define AML_TYPE_METHOD_CALL 0x10 -/* Misc */ +/* Miscellaneous types */ #define AML_TYPE_CREATE_FIELD 0x11 #define AML_TYPE_CREATE_OBJECT 0x12 @@ -395,7 +387,6 @@ #define AML_TYPE_NAMED_SIMPLE 0x16 #define AML_TYPE_NAMED_COMPLEX 0x17 #define AML_TYPE_RETURN 0x18 - #define AML_TYPE_UNDEFINED 0x19 #define AML_TYPE_BOGUS 0x1A diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c index 15c8237b8a80..df62c9245efc 100644 --- a/drivers/acpi/acpica/dbmethod.c +++ b/drivers/acpi/acpica/dbmethod.c @@ -422,6 +422,7 @@ acpi_db_walk_for_execute(acpi_handle obj_handle, status = acpi_get_object_info(obj_handle, &obj_info); if (ACPI_FAILURE(status)) { + ACPI_FREE(pathname); return (status); } diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 205b8e0eded5..8f665d94b8b5 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -45,6 +45,7 @@ #include "accommon.h" #include "amlcode.h" #include "acdebug.h" +#include "acinterp.h" #define _COMPONENT ACPI_CA_DEBUGGER ACPI_MODULE_NAME("dbxface") @@ -125,7 +126,7 @@ error_exit: * * RETURN: Status * - * DESCRIPTION: Called for AML_BREAK_POINT_OP + * DESCRIPTION: Called for AML_BREAKPOINT_OP * ******************************************************************************/ @@ -368,7 +369,9 @@ acpi_db_single_step(struct acpi_walk_state *walk_state, walk_state->method_breakpoint = 1; /* Must be non-zero! */ } + acpi_ex_exit_interpreter(); status = acpi_db_start_command(walk_state, op); + acpi_ex_enter_interpreter(); /* User commands complete, continue execution of the interrupted method */ diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index d31b49feaa79..f470e81b0499 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -347,7 +347,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state, break; - case AML_BREAK_POINT_OP: + case AML_BREAKPOINT_OP: acpi_db_signal_break_point(walk_state); diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index adcc72cd53a7..27a7de95f7b0 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -672,7 +672,8 @@ acpi_ds_store_object_to_local(u8 type, * * FUNCTION: acpi_ds_method_data_get_type * - * PARAMETERS: opcode - Either AML_LOCAL_OP or AML_ARG_OP + * PARAMETERS: opcode - Either AML_FIRST LOCAL_OP or + * AML_FIRST_ARG_OP * index - Which Local or Arg whose type to get * walk_state - Current walk state object * diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 8deaa16493a0..7df3152ed856 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -114,7 +114,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || (op->common.parent->common.aml_opcode == - AML_VAR_PACKAGE_OP))) { + AML_VARIABLE_PACKAGE_OP))) { /* * We didn't find the target and we are populating elements * of a package - ignore if slack enabled. Some ASL code @@ -144,7 +144,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || (op->common.parent->common.aml_opcode == - AML_VAR_PACKAGE_OP)) { + AML_VARIABLE_PACKAGE_OP)) { /* * Attempt to resolve the node to a value before we insert it into * the package. If this is a reference to a common data type, @@ -398,7 +398,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, parent = op->common.parent; while ((parent->common.aml_opcode == AML_PACKAGE_OP) || - (parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { + (parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) { parent = parent->common.parent; } @@ -769,10 +769,10 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, switch (op_info->type) { case AML_TYPE_LOCAL_VARIABLE: - /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ + /* Local ID (0-7) is (AML opcode - base AML_FIRST_LOCAL_OP) */ obj_desc->reference.value = - ((u32)opcode) - AML_LOCAL_OP; + ((u32)opcode) - AML_FIRST_LOCAL_OP; obj_desc->reference.class = ACPI_REFCLASS_LOCAL; #ifndef ACPI_NO_METHOD_EXECUTION @@ -790,9 +790,10 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, case AML_TYPE_METHOD_ARGUMENT: - /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ + /* Arg ID (0-6) is (AML opcode - base AML_FIRST_ARG_OP) */ - obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP; + obj_desc->reference.value = + ((u32)opcode) - AML_FIRST_ARG_OP; obj_desc->reference.class = ACPI_REFCLASS_ARG; #ifndef ACPI_NO_METHOD_EXECUTION diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 148523205d41..9a8f8a992b3e 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -639,7 +639,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, break; case AML_PACKAGE_OP: - case AML_VAR_PACKAGE_OP: + case AML_VARIABLE_PACKAGE_OP: status = acpi_ds_build_internal_package_obj(walk_state, op, length, @@ -660,7 +660,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, if ((!op->common.parent) || ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && (op->common.parent->common.aml_opcode != - AML_VAR_PACKAGE_OP) + AML_VARIABLE_PACKAGE_OP) && (op->common.parent->common.aml_opcode != AML_NAME_OP))) { walk_state->result_obj = obj_desc; diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 049fbab4e5a6..406edec20de7 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -275,10 +275,10 @@ acpi_ds_is_result_used(union acpi_parse_object * op, if ((op->common.parent->common.aml_opcode == AML_REGION_OP) || (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) || (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) - || (op->common.parent->common.aml_opcode == - AML_VAR_PACKAGE_OP) || (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || (op->common.parent->common.aml_opcode == + AML_VARIABLE_PACKAGE_OP) + || (op->common.parent->common.aml_opcode == AML_INT_EVAL_SUBTREE_OP) || (op->common.parent->common.aml_opcode == AML_BANK_FIELD_OP)) { @@ -551,7 +551,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, */ if (status == AE_NOT_FOUND) { if (parent_op->common.aml_opcode == - AML_COND_REF_OF_OP) { + AML_CONDITIONAL_REF_OF_OP) { /* * For the Conditional Reference op, it's OK if * the name is not found; We just need a way to @@ -806,7 +806,7 @@ acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state) } if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || - (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP) || (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) { /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */ diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index 78f8e6a4f72f..a2ff8ad70d58 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -497,7 +497,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) if ((op->asl.parent) && ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) || (op->asl.parent->asl.aml_opcode == - AML_VAR_PACKAGE_OP))) { + AML_VARIABLE_PACKAGE_OP))) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op)); diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 44d4553dfbdd..8d510c7e20c8 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -528,7 +528,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) status = acpi_ex_create_processor(walk_state); break; - case AML_POWER_RES_OP: + case AML_POWER_RESOURCE_OP: status = acpi_ex_create_power_resource(walk_state); break; diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 1a6f59079ea5..f222a80ca38e 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -249,14 +249,14 @@ acpi_ex_do_logical_numeric_op(u16 opcode, ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op); switch (opcode) { - case AML_LAND_OP: /* LAnd (Integer0, Integer1) */ + case AML_LOGICAL_AND_OP: /* LAnd (Integer0, Integer1) */ if (integer0 && integer1) { local_result = TRUE; } break; - case AML_LOR_OP: /* LOr (Integer0, Integer1) */ + case AML_LOGICAL_OR_OP: /* LOr (Integer0, Integer1) */ if (integer0 || integer1) { local_result = TRUE; @@ -365,21 +365,21 @@ acpi_ex_do_logical_op(u16 opcode, integer1 = local_operand1->integer.value; switch (opcode) { - case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + case AML_LOGICAL_EQUAL_OP: /* LEqual (Operand0, Operand1) */ if (integer0 == integer1) { local_result = TRUE; } break; - case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + case AML_LOGICAL_GREATER_OP: /* LGreater (Operand0, Operand1) */ if (integer0 > integer1) { local_result = TRUE; } break; - case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + case AML_LOGICAL_LESS_OP: /* LLess (Operand0, Operand1) */ if (integer0 < integer1) { local_result = TRUE; @@ -408,7 +408,7 @@ acpi_ex_do_logical_op(u16 opcode, (length0 > length1) ? length1 : length0); switch (opcode) { - case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + case AML_LOGICAL_EQUAL_OP: /* LEqual (Operand0, Operand1) */ /* Length and all bytes must be equal */ @@ -420,7 +420,7 @@ acpi_ex_do_logical_op(u16 opcode, } break; - case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + case AML_LOGICAL_GREATER_OP: /* LGreater (Operand0, Operand1) */ if (compare > 0) { local_result = TRUE; @@ -437,7 +437,7 @@ acpi_ex_do_logical_op(u16 opcode, } break; - case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + case AML_LOGICAL_LESS_OP: /* LLess (Operand0, Operand1) */ if (compare > 0) { goto cleanup; /* FALSE */ diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index ee7b62a86661..caa5ed1f65ec 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -122,7 +122,7 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs) /* Set up multi prefixes */ - *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP; + *temp_ptr++ = AML_MULTI_NAME_PREFIX; *temp_ptr++ = (char)num_name_segs; } else if (2 == num_name_segs) { @@ -342,7 +342,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, } break; - case AML_MULTI_NAME_PREFIX_OP: + case AML_MULTI_NAME_PREFIX: ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "MultiNamePrefix at %p\n", diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index af73fcde7e5c..e327349675cd 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -274,7 +274,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) case AML_FIND_SET_RIGHT_BIT_OP: case AML_FROM_BCD_OP: case AML_TO_BCD_OP: - case AML_COND_REF_OF_OP: + case AML_CONDITIONAL_REF_OF_OP: /* Create a return object of type Integer for these opcodes */ @@ -405,7 +405,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) } break; - case AML_COND_REF_OF_OP: /* cond_ref_of (source_object, Result) */ + case AML_CONDITIONAL_REF_OF_OP: /* cond_ref_of (source_object, Result) */ /* * This op is a little strange because the internal return value is * different than the return value stored in the result descriptor @@ -475,14 +475,14 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) /* * ACPI 2.0 Opcodes */ - case AML_COPY_OP: /* Copy (Source, Target) */ + case AML_COPY_OBJECT_OP: /* copy_object (Source, Target) */ status = acpi_ut_copy_iobject_to_iobject(operand[0], &return_desc, walk_state); break; - case AML_TO_DECSTRING_OP: /* to_decimal_string (Data, Result) */ + case AML_TO_DECIMAL_STRING_OP: /* to_decimal_string (Data, Result) */ status = acpi_ex_convert_to_string(operand[0], &return_desc, @@ -495,7 +495,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) } break; - case AML_TO_HEXSTRING_OP: /* to_hex_string (Data, Result) */ + case AML_TO_HEX_STRING_OP: /* to_hex_string (Data, Result) */ status = acpi_ex_convert_to_string(operand[0], &return_desc, @@ -603,7 +603,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* Examine the AML opcode */ switch (walk_state->opcode) { - case AML_LNOT_OP: /* LNot (Operand) */ + case AML_LOGICAL_NOT_OP: /* LNot (Operand) */ return_desc = acpi_ut_create_integer_object((u64) 0); if (!return_desc) { @@ -652,9 +652,8 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) * NOTE: We use LNOT_OP here in order to force resolution of the * reference operand to an actual integer. */ - status = - acpi_ex_resolve_operands(AML_LNOT_OP, &temp_desc, - walk_state); + status = acpi_ex_resolve_operands(AML_LOGICAL_NOT_OP, + &temp_desc, walk_state); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "While resolving operands for [%s]", diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 44ecba50c0da..eecb3bff7fd7 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -298,7 +298,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) NULL, &return_desc->integer.value); break; - case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ + case AML_CONCATENATE_OP: /* Concatenate (Data1, Data2, Result) */ status = acpi_ex_do_concatenate(operand[0], operand[1], &return_desc, @@ -343,7 +343,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) operand[0]->buffer.pointer, length); break; - case AML_CONCAT_RES_OP: + case AML_CONCATENATE_TEMPLATE_OP: /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 31e4df97cbe1..688032b58a21 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -124,8 +124,8 @@ acpi_ex_do_match(u32 match_op, * Change to: (M == P[i]) */ status = - acpi_ex_do_logical_op(AML_LEQUAL_OP, match_obj, package_obj, - &logical_result); + acpi_ex_do_logical_op(AML_LOGICAL_EQUAL_OP, match_obj, + package_obj, &logical_result); if (ACPI_FAILURE(status)) { return (FALSE); } @@ -137,8 +137,8 @@ acpi_ex_do_match(u32 match_op, * Change to: (M >= P[i]) (M not_less than P[i]) */ status = - acpi_ex_do_logical_op(AML_LLESS_OP, match_obj, package_obj, - &logical_result); + acpi_ex_do_logical_op(AML_LOGICAL_LESS_OP, match_obj, + package_obj, &logical_result); if (ACPI_FAILURE(status)) { return (FALSE); } @@ -151,7 +151,7 @@ acpi_ex_do_match(u32 match_op, * Change to: (M > P[i]) */ status = - acpi_ex_do_logical_op(AML_LGREATER_OP, match_obj, + acpi_ex_do_logical_op(AML_LOGICAL_GREATER_OP, match_obj, package_obj, &logical_result); if (ACPI_FAILURE(status)) { return (FALSE); @@ -164,7 +164,7 @@ acpi_ex_do_match(u32 match_op, * Change to: (M <= P[i]) (M not_greater than P[i]) */ status = - acpi_ex_do_logical_op(AML_LGREATER_OP, match_obj, + acpi_ex_do_logical_op(AML_LOGICAL_GREATER_OP, match_obj, package_obj, &logical_result); if (ACPI_FAILURE(status)) { return (FALSE); @@ -178,8 +178,8 @@ acpi_ex_do_match(u32 match_op, * Change to: (M < P[i]) */ status = - acpi_ex_do_logical_op(AML_LLESS_OP, match_obj, package_obj, - &logical_result); + acpi_ex_do_logical_op(AML_LOGICAL_LESS_OP, match_obj, + package_obj, &logical_result); if (ACPI_FAILURE(status)) { return (FALSE); } diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index 7fecefc2e1b4..aa8c6fd74cc3 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -196,7 +196,8 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, if ((walk_state->opcode == AML_INT_METHODCALL_OP) - || (walk_state->opcode == AML_COPY_OP)) { + || (walk_state->opcode == + AML_COPY_OBJECT_OP)) { break; } diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index a2f8001aeb86..bdd43cde8f36 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -416,7 +416,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, /* Only limited target types possible for everything except copy_object */ - if (walk_state->opcode != AML_COPY_OP) { + if (walk_state->opcode != AML_COPY_OBJECT_OP) { /* * Only copy_object allows all object types to be overwritten. For * target_ref(s), there are restrictions on the object types that @@ -499,7 +499,8 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: - if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) { + if ((walk_state->opcode == AML_COPY_OBJECT_OP) || + !implicit_conversion) { /* * However, copy_object and Stores to arg_x do not perform * an implicit conversion, as per the ACPI specification. diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index 85db4716a043..56f59cf5da29 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -107,7 +107,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, /* For copy_object, no further validation necessary */ - if (walk_state->opcode == AML_COPY_OP) { + if (walk_state->opcode == AML_COPY_OBJECT_OP) { break; } diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 531620abed80..3094cec4eab4 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -102,7 +102,7 @@ static const struct acpi_port_info acpi_protected_ports[] = { {"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP} }; -#define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (acpi_protected_ports) +#define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (acpi_protected_ports) /****************************************************************************** * @@ -128,7 +128,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) acpi_io_address last_address; const struct acpi_port_info *port_info; - ACPI_FUNCTION_TRACE(hw_validate_io_request); + ACPI_FUNCTION_NAME(hw_validate_io_request); /* Supported widths are 8/16/32 */ @@ -153,13 +153,13 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) ACPI_ERROR((AE_INFO, "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X", ACPI_FORMAT_UINT64(address), byte_width)); - return_ACPI_STATUS(AE_LIMIT); + return (AE_LIMIT); } /* Exit if requested address is not within the protected port table */ if (address > acpi_protected_ports[ACPI_PORT_INFO_ENTRIES - 1].end) { - return_ACPI_STATUS(AE_OK); + return (AE_OK); } /* Check request against the list of protected I/O ports */ @@ -167,7 +167,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, port_info++) { /* * Check if the requested address range will write to a reserved - * port. Four cases to consider: + * port. There are four cases to consider: * * 1) Address range is contained completely in the port address range * 2) Address range overlaps port range at the port range start @@ -198,7 +198,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) } } - return_ACPI_STATUS(AE_OK); + return (AE_OK); } /****************************************************************************** @@ -206,7 +206,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) * FUNCTION: acpi_hw_read_port * * PARAMETERS: Address Address of I/O port/register to read - * Value Where value is placed + * Value Where value (data) is returned * Width Number of bits * * RETURN: Status and value read from port @@ -244,7 +244,7 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) /* * There has been a protection violation within the request. Fall * back to byte granularity port I/O and ignore the failing bytes. - * This provides Windows compatibility. + * This provides compatibility with other ACPI implementations. */ for (i = 0, *value = 0; i < width; i += 8) { @@ -307,7 +307,7 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) /* * There has been a protection violation within the request. Fall * back to byte granularity port I/O and ignore the failing bytes. - * This provides Windows compatibility. + * This provides compatibility with other ACPI implementations. */ for (i = 0; i < width; i += 8) { diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 498bb8f70e6b..fb265b5737de 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -485,7 +485,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, flags)); break; - case AML_MULTI_NAME_PREFIX_OP: + case AML_MULTI_NAME_PREFIX: /* More than one name_seg, search rules do not apply */ diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 38316266521e..418ef2ac82ab 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -290,22 +290,12 @@ object_repaired: /* Object was successfully repaired */ if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { - /* - * The original object is a package element. We need to - * decrement the reference count of the original object, - * for removing it from the package. - * - * However, if the original object was just wrapped with a - * package object as part of the repair, we don't need to - * change the reference count. - */ + + /* Update reference count of new object */ + if (!(info->return_flags & ACPI_OBJECT_WRAPPED)) { new_object->common.reference_count = return_object->common.reference_count; - - if (return_object->common.reference_count > 1) { - return_object->common.reference_count--; - } } ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 352265498e90..06037e044694 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -403,16 +403,12 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info, return (status); } - /* Take care with reference counts */ - if (original_element != *element_ptr) { - /* Element was replaced */ + /* Update reference count of new object */ (*element_ptr)->common.reference_count = original_ref_count; - - acpi_ut_remove_reference(original_element); } element_ptr++; diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 661676714f7b..2fe87d0dd9d5 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -252,7 +252,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) internal_name[1] = AML_DUAL_NAME_PREFIX; result = &internal_name[2]; } else { - internal_name[1] = AML_MULTI_NAME_PREFIX_OP; + internal_name[1] = AML_MULTI_NAME_PREFIX; internal_name[2] = (char)num_segments; result = &internal_name[3]; } @@ -274,7 +274,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) internal_name[i] = AML_DUAL_NAME_PREFIX; result = &internal_name[(acpi_size)i + 1]; } else { - internal_name[i] = AML_MULTI_NAME_PREFIX_OP; + internal_name[i] = AML_MULTI_NAME_PREFIX; internal_name[(acpi_size)i + 1] = (char)num_segments; result = &internal_name[(acpi_size)i + 2]; } @@ -450,7 +450,7 @@ acpi_ns_externalize_name(u32 internal_name_length, */ if (prefix_length < internal_name_length) { switch (internal_name[prefix_length]) { - case AML_MULTI_NAME_PREFIX_OP: + case AML_MULTI_NAME_PREFIX: /* <count> 4-byte names */ @@ -594,25 +594,20 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) void acpi_ns_terminate(void) { acpi_status status; + union acpi_operand_object *prev; + union acpi_operand_object *next; ACPI_FUNCTION_TRACE(ns_terminate); -#ifdef ACPI_EXEC_APP - { - union acpi_operand_object *prev; - union acpi_operand_object *next; + /* Delete any module-level code blocks */ - /* Delete any module-level code blocks */ - - next = acpi_gbl_module_code_list; - while (next) { - prev = next; - next = next->method.mutex; - prev->method.mutex = NULL; /* Clear the Mutex (cheated) field */ - acpi_ut_remove_reference(prev); - } + next = acpi_gbl_module_code_list; + while (next) { + prev = next; + next = next->method.mutex; + prev->method.mutex = NULL; /* Clear the Mutex (cheated) field */ + acpi_ut_remove_reference(prev); } -#endif /* * Free the entire namespace -- all nodes and all objects diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 05b62ad44c3e..eb9dfaca555f 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -47,6 +47,7 @@ #include "amlcode.h" #include "acnamesp.h" #include "acdispat.h" +#include "acconvert.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psargs") @@ -186,7 +187,7 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state) end += 1 + (2 * ACPI_NAME_SIZE); break; - case AML_MULTI_NAME_PREFIX_OP: + case AML_MULTI_NAME_PREFIX: /* Multiple name segments, 4 chars each, count in next byte */ @@ -339,7 +340,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, /* 2) not_found during a cond_ref_of(x) is ok by definition */ else if (walk_state->op->common.aml_opcode == - AML_COND_REF_OF_OP) { + AML_CONDITIONAL_REF_OF_OP) { status = AE_OK; } @@ -352,7 +353,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, ((arg->common.parent->common.aml_opcode == AML_PACKAGE_OP) || (arg->common.parent->common.aml_opcode == - AML_VAR_PACKAGE_OP))) { + AML_VARIABLE_PACKAGE_OP))) { status = AE_OK; } } @@ -502,6 +503,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state ACPI_FUNCTION_TRACE(ps_get_next_field); + ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state); aml = parser_state->aml; /* Determine field type */ @@ -546,6 +548,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state /* Decode the field type */ + ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state); switch (opcode) { case AML_INT_NAMEDFIELD_OP: @@ -555,6 +558,22 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state acpi_ps_set_name(field, name); parser_state->aml += ACPI_NAME_SIZE; + ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state); + +#ifdef ACPI_ASL_COMPILER + /* + * Because the package length isn't represented as a parse tree object, + * take comments surrounding this and add to the previously created + * parse node. + */ + if (field->common.inline_comment) { + field->common.name_comment = + field->common.inline_comment; + } + field->common.inline_comment = acpi_gbl_current_inline_comment; + acpi_gbl_current_inline_comment = NULL; +#endif + /* Get the length which is encoded as a package length */ field->common.value.size = @@ -609,11 +628,13 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state if (ACPI_GET8(parser_state->aml) == AML_BUFFER_OP) { parser_state->aml++; + ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state); pkg_end = parser_state->aml; pkg_length = acpi_ps_get_next_package_length(parser_state); pkg_end += pkg_length; + ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state); if (parser_state->aml < pkg_end) { /* Non-empty list */ @@ -630,6 +651,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state opcode = ACPI_GET8(parser_state->aml); parser_state->aml++; + ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state); switch (opcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ @@ -660,6 +682,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state /* Fill in bytelist data */ + ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state); arg->named.value.size = buffer_length; arg->named.data = parser_state->aml; } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 14d689606d2f..b4224005783c 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -55,6 +55,7 @@ #include "acparser.h" #include "acdispat.h" #include "amlcode.h" +#include "acconvert.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psloop") @@ -132,6 +133,21 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, !walk_state->arg_count) { walk_state->aml = walk_state->parser_state.aml; + switch (op->common.aml_opcode) { + case AML_METHOD_OP: + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VARIABLE_PACKAGE_OP: + case AML_WHILE_OP: + + break; + + default: + + ASL_CV_CAPTURE_COMMENTS(walk_state); + break; + } + status = acpi_ps_get_next_arg(walk_state, &(walk_state->parser_state), @@ -254,7 +270,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, case AML_BUFFER_OP: case AML_PACKAGE_OP: - case AML_VAR_PACKAGE_OP: + case AML_VARIABLE_PACKAGE_OP: if ((op->common.parent) && (op->common.parent->common.aml_opcode == @@ -480,6 +496,8 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) /* Iterative parsing loop, while there is more AML to process: */ while ((parser_state->aml < parser_state->aml_end) || (op)) { + ASL_CV_CAPTURE_COMMENTS(walk_state); + aml_op_start = parser_state->aml; if (!op) { status = @@ -516,6 +534,20 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) */ walk_state->arg_count = 0; + switch (op->common.aml_opcode) { + case AML_BYTE_OP: + case AML_WORD_OP: + case AML_DWORD_OP: + case AML_QWORD_OP: + + break; + + default: + + ASL_CV_CAPTURE_COMMENTS(walk_state); + break; + } + /* Are there any arguments that must be processed? */ if (walk_state->arg_types) { diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 5c4aff0f4f26..5bcb61831706 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -45,6 +45,7 @@ #include "accommon.h" #include "acparser.h" #include "amlcode.h" +#include "acconvert.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psobject") @@ -190,6 +191,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, */ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { + ASL_CV_CAPTURE_COMMENTS(walk_state); status = acpi_ps_get_next_arg(walk_state, &(walk_state->parser_state), @@ -203,6 +205,18 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, INCREMENT_ARG_LIST(walk_state->arg_types); } + /* are there any inline comments associated with the name_seg?? If so, save this. */ + + ASL_CV_CAPTURE_COMMENTS(walk_state); + +#ifdef ACPI_ASL_COMPILER + if (acpi_gbl_current_inline_comment != NULL) { + unnamed_op->common.name_comment = + acpi_gbl_current_inline_comment; + acpi_gbl_current_inline_comment = NULL; + } +#endif + /* * Make sure that we found a NAME and didn't run out of arguments */ @@ -243,6 +257,30 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, acpi_ps_append_arg(*op, unnamed_op->common.value.arg); +#ifdef ACPI_ASL_COMPILER + + /* save any comments that might be associated with unnamed_op. */ + + (*op)->common.inline_comment = unnamed_op->common.inline_comment; + (*op)->common.end_node_comment = unnamed_op->common.end_node_comment; + (*op)->common.close_brace_comment = + unnamed_op->common.close_brace_comment; + (*op)->common.name_comment = unnamed_op->common.name_comment; + (*op)->common.comment_list = unnamed_op->common.comment_list; + (*op)->common.end_blk_comment = unnamed_op->common.end_blk_comment; + (*op)->common.cv_filename = unnamed_op->common.cv_filename; + (*op)->common.cv_parent_filename = + unnamed_op->common.cv_parent_filename; + (*op)->named.aml = unnamed_op->common.aml; + + unnamed_op->common.inline_comment = NULL; + unnamed_op->common.end_node_comment = NULL; + unnamed_op->common.close_brace_comment = NULL; + unnamed_op->common.name_comment = NULL; + unnamed_op->common.comment_list = NULL; + unnamed_op->common.end_blk_comment = NULL; +#endif + if ((*op)->common.aml_opcode == AML_REGION_OP || (*op)->common.aml_opcode == AML_DATA_REGION_OP) { /* diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 451b672915f1..c343a0d5a3d2 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -69,7 +69,7 @@ ACPI_MODULE_NAME("psopcode") AML_DEVICE_OP AML_THERMAL_ZONE_OP AML_METHOD_OP - AML_POWER_RES_OP + AML_POWER_RESOURCE_OP AML_PROCESSOR_OP AML_FIELD_OP AML_INDEX_FIELD_OP @@ -95,7 +95,7 @@ ACPI_MODULE_NAME("psopcode") AML_DEVICE_OP AML_THERMAL_ZONE_OP AML_METHOD_OP - AML_POWER_RES_OP + AML_POWER_RESOURCE_OP AML_PROCESSOR_OP AML_FIELD_OP AML_INDEX_FIELD_OP @@ -113,7 +113,7 @@ ACPI_MODULE_NAME("psopcode") AML_DEVICE_OP AML_THERMAL_ZONE_OP AML_METHOD_OP - AML_POWER_RES_OP + AML_POWER_RESOURCE_OP AML_PROCESSOR_OP AML_NAME_OP AML_ALIAS_OP @@ -136,7 +136,7 @@ ACPI_MODULE_NAME("psopcode") AML_DEVICE_OP AML_THERMAL_ZONE_OP AML_METHOD_OP - AML_POWER_RES_OP + AML_POWER_RESOURCE_OP AML_PROCESSOR_OP AML_NAME_OP AML_ALIAS_OP @@ -149,7 +149,7 @@ ACPI_MODULE_NAME("psopcode") must be deferred until needed AML_METHOD_OP - AML_VAR_PACKAGE_OP + AML_VARIABLE_PACKAGE_OP AML_CREATE_FIELD_OP AML_CREATE_BIT_FIELD_OP AML_CREATE_BYTE_FIELD_OP @@ -652,7 +652,10 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 81 */ ACPI_OP("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, /* ? */ - AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R) + AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R), +/* 82 */ ACPI_OP("Comment", ARGP_COMMENT_OP, ARGI_COMMENT_OP, + ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT) /*! [End] no source code translation !*/ }; diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index 89f95b7f26e9..eff22950232b 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -226,7 +226,7 @@ const u8 acpi_gbl_short_op_index[256] = { /* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74, /* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A, /* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61, -/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xA8 */ 0x62, 0x82, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index a813bbbd5a8b..8116a670de39 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -105,7 +105,7 @@ u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state) aml = parser_state->aml; opcode = (u16) ACPI_GET8(aml); - if (opcode == AML_EXTENDED_OP_PREFIX) { + if (opcode == AML_EXTENDED_PREFIX) { /* Extended opcode, get the second opcode byte */ @@ -210,7 +210,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state *walk_state, || (op->common.parent->common.aml_opcode == AML_BANK_FIELD_OP) || (op->common.parent->common.aml_opcode == - AML_VAR_PACKAGE_OP)) { + AML_VARIABLE_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, op->common.aml); @@ -225,7 +225,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state *walk_state, if ((op->common.aml_opcode == AML_BUFFER_OP) || (op->common.aml_opcode == AML_PACKAGE_OP) || (op->common.aml_opcode == - AML_VAR_PACKAGE_OP)) { + AML_VARIABLE_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op(op->common. aml_opcode, diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index 9677fff8fd47..c06d6e2fc7a5 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -45,6 +45,7 @@ #include "accommon.h" #include "acparser.h" #include "amlcode.h" +#include "acconvert.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("pstree") @@ -216,6 +217,7 @@ union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, next = acpi_ps_get_arg(op, 0); if (next) { + ASL_CV_LABEL_FILENODE(next); return (next); } @@ -223,6 +225,7 @@ union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, next = op->common.next; if (next) { + ASL_CV_LABEL_FILENODE(next); return (next); } @@ -233,6 +236,8 @@ union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, while (parent) { arg = acpi_ps_get_arg(parent, 0); while (arg && (arg != origin) && (arg != op)) { + + ASL_CV_LABEL_FILENODE(arg); arg = arg->common.next; } @@ -247,6 +252,7 @@ union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, /* Found sibling of parent */ + ASL_CV_LABEL_FILENODE(parent->common.next); return (parent->common.next); } @@ -254,6 +260,7 @@ union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, parent = parent->common.parent; } + ASL_CV_LABEL_FILENODE(next); return (next); } @@ -296,7 +303,7 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op) child = acpi_ps_get_arg(op, 1); break; - case AML_POWER_RES_OP: + case AML_POWER_RESOURCE_OP: case AML_INDEX_FIELD_OP: child = acpi_ps_get_arg(op, 2); diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 2fa38bb76a55..02642760cb93 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -45,6 +45,7 @@ #include "accommon.h" #include "acparser.h" #include "amlcode.h" +#include "acconvert.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psutils") @@ -152,6 +153,15 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml) acpi_ps_init_op(op, opcode); op->common.aml = aml; op->common.flags = flags; + ASL_CV_CLEAR_OP_COMMENTS(op); + + if (opcode == AML_SCOPE_OP) { + acpi_gbl_current_scope = op; + } + } + + if (gbl_capture_comments) { + ASL_CV_TRANSFER_COMMENTS(op); } return (op); @@ -174,6 +184,7 @@ void acpi_ps_free_op(union acpi_parse_object *op) { ACPI_FUNCTION_NAME(ps_free_op); + ASL_CV_CLEAR_OP_COMMENTS(op); if (op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", op)); diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index a3401bd29413..5594a359dbf1 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -142,6 +142,45 @@ acpi_status acpi_ut_create_caches(void) if (ACPI_FAILURE(status)) { return (status); } +#ifdef ACPI_ASL_COMPILER + /* + * For use with the ASL-/ASL+ option. This cache keeps track of regular + * 0xA9 0x01 comments. + */ + status = + acpi_os_create_cache("Acpi-Comment", + sizeof(struct acpi_comment_node), + ACPI_MAX_COMMENT_CACHE_DEPTH, + &acpi_gbl_reg_comment_cache); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* + * This cache keeps track of the starting addresses of where the comments + * lie. This helps prevent duplication of comments. + */ + status = + acpi_os_create_cache("Acpi-Comment-Addr", + sizeof(struct acpi_comment_addr_node), + ACPI_MAX_COMMENT_CACHE_DEPTH, + &acpi_gbl_comment_addr_cache); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* + * This cache will be used for nodes that represent files. + */ + status = + acpi_os_create_cache("Acpi-File", sizeof(struct acpi_file_node), + ACPI_MAX_COMMENT_CACHE_DEPTH, + &acpi_gbl_file_cache); + if (ACPI_FAILURE(status)) { + return (status); + } +#endif + #ifdef ACPI_DBG_TRACK_ALLOCATIONS /* Memory allocation lists */ @@ -201,6 +240,17 @@ acpi_status acpi_ut_delete_caches(void) (void)acpi_os_delete_cache(acpi_gbl_ps_node_ext_cache); acpi_gbl_ps_node_ext_cache = NULL; +#ifdef ACPI_ASL_COMPILER + (void)acpi_os_delete_cache(acpi_gbl_reg_comment_cache); + acpi_gbl_reg_comment_cache = NULL; + + (void)acpi_os_delete_cache(acpi_gbl_comment_addr_cache); + acpi_gbl_comment_addr_cache = NULL; + + (void)acpi_os_delete_cache(acpi_gbl_file_cache); + acpi_gbl_file_cache = NULL; +#endif + #ifdef ACPI_DBG_TRACK_ALLOCATIONS /* Debug only - display leftover memory allocation, if any */ diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 11c7f72f2d56..531493306dee 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -71,7 +71,7 @@ acpi_os_create_cache(char *cache_name, ACPI_FUNCTION_ENTRY(); - if (!cache_name || !return_cache || (object_size < 16)) { + if (!cache_name || !return_cache || !object_size) { return (AE_BAD_PARAMETER); } diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index bd5ea3101eb7..615a885e2ca3 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -627,4 +627,5 @@ acpi_trace_point(acpi_trace_event_type type, u8 begin, u8 *aml, char *pathname) } ACPI_EXPORT_SYMBOL(acpi_trace_point) + #endif diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index ff096d9755b9..e0587c85bafd 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -474,6 +474,15 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } + /* + * The end_tag opcode must be followed by a zero byte. + * Although this byte is technically defined to be a checksum, + * in practice, all ASL compilers set this byte to zero. + */ + if (*(aml + 1) != 0) { + return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); + } + /* Return the pointer to the end_tag if requested */ if (!user_function) { diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index a16bd9eac653..950a1e500bfa 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -91,7 +91,7 @@ ACPI_EXPORT_SYMBOL(acpi_error) * * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) - * status - Status to be formatted + * status - Status value to be decoded/formatted * format - Printf format string + additional args * * RETURN: None @@ -132,8 +132,8 @@ ACPI_EXPORT_SYMBOL(acpi_exception) * * FUNCTION: acpi_warning * - * PARAMETERS: module_name - Caller's module name (for error output) - * line_number - Caller's line number (for error output) + * PARAMETERS: module_name - Caller's module name (for warning output) + * line_number - Caller's line number (for warning output) * format - Printf format string + additional args * * RETURN: None @@ -163,17 +163,13 @@ ACPI_EXPORT_SYMBOL(acpi_warning) * * FUNCTION: acpi_info * - * PARAMETERS: module_name - Caller's module name (for error output) - * line_number - Caller's line number (for error output) - * format - Printf format string + additional args + * PARAMETERS: format - Printf format string + additional args * * RETURN: None * * DESCRIPTION: Print generic "ACPI:" information message. There is no * module/line/version info in order to keep the message simple. * - * TBD: module_name and line_number args are not needed, should be removed. - * ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE acpi_info(const char *format, ...) { @@ -229,8 +225,8 @@ ACPI_EXPORT_SYMBOL(acpi_bios_error) * * FUNCTION: acpi_bios_warning * - * PARAMETERS: module_name - Caller's module name (for error output) - * line_number - Caller's line number (for error output) + * PARAMETERS: module_name - Caller's module name (for warning output) + * line_number - Caller's line number (for warning output) * format - Printf format string + additional args * * RETURN: None diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 22e08d272db7..c5fecf97ee2f 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -618,6 +618,46 @@ static int arm_smmu_iort_xlate(struct device *dev, u32 streamid, return ret; } +static inline bool iort_iommu_driver_enabled(u8 type) +{ + switch (type) { + case ACPI_IORT_NODE_SMMU_V3: + return IS_BUILTIN(CONFIG_ARM_SMMU_V3); + case ACPI_IORT_NODE_SMMU: + return IS_BUILTIN(CONFIG_ARM_SMMU); + default: + pr_warn("IORT node type %u does not describe an SMMU\n", type); + return false; + } +} + +#ifdef CONFIG_IOMMU_API +static inline +const struct iommu_ops *iort_fwspec_iommu_ops(struct iommu_fwspec *fwspec) +{ + return (fwspec && fwspec->ops) ? fwspec->ops : NULL; +} + +static inline +int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) +{ + int err = 0; + + if (!IS_ERR_OR_NULL(ops) && ops->add_device && dev->bus && + !dev->iommu_group) + err = ops->add_device(dev); + + return err; +} +#else +static inline +const struct iommu_ops *iort_fwspec_iommu_ops(struct iommu_fwspec *fwspec) +{ return NULL; } +static inline +int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) +{ return 0; } +#endif + static const struct iommu_ops *iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node, u32 streamid) @@ -626,14 +666,31 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, int ret = -ENODEV; struct fwnode_handle *iort_fwnode; + /* + * If we already translated the fwspec there + * is nothing left to do, return the iommu_ops. + */ + ops = iort_fwspec_iommu_ops(dev->iommu_fwspec); + if (ops) + return ops; + if (node) { iort_fwnode = iort_get_fwnode(node); if (!iort_fwnode) return NULL; ops = iommu_ops_from_fwnode(iort_fwnode); + /* + * If the ops look-up fails, this means that either + * the SMMU drivers have not been probed yet or that + * the SMMU drivers are not built in the kernel; + * Depending on whether the SMMU drivers are built-in + * in the kernel or not, defer the IOMMU configuration + * or just abort it. + */ if (!ops) - return NULL; + return iort_iommu_driver_enabled(node->type) ? + ERR_PTR(-EPROBE_DEFER) : NULL; ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops); } @@ -676,6 +733,7 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) struct acpi_iort_node *node, *parent; const struct iommu_ops *ops = NULL; u32 streamid = 0; + int err; if (dev_is_pci(dev)) { struct pci_bus *bus = to_pci_dev(dev)->bus; @@ -707,6 +765,8 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) while (parent) { ops = iort_iommu_xlate(dev, parent, streamid); + if (IS_ERR_OR_NULL(ops)) + return ops; parent = iort_node_map_platform_id(node, &streamid, IORT_IOMMU_TYPE, @@ -714,6 +774,14 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) } } + /* + * If we have reason to believe the IOMMU driver missed the initial + * add_device callback for dev, replay it to get things in order. + */ + err = iort_add_device_replay(ops, dev); + if (err) + ops = ERR_PTR(err); + return ops; } @@ -1052,6 +1120,4 @@ void __init acpi_iort_init(void) } iort_init_platform_devices(); - - acpi_probe_device_table(iort); } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index d42eeef9d928..a9a9ab3399d4 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -782,7 +782,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume) if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) || (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && (battery->capacity_now <= battery->alarm))) - pm_wakeup_event(&battery->device->dev, 0); + pm_wakeup_hard_event(&battery->device->dev); return result; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 34fbe027e73a..784bda663d16 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -114,6 +114,11 @@ int acpi_bus_get_status(struct acpi_device *device) acpi_status status; unsigned long long sta; + if (acpi_device_always_present(device)) { + acpi_set_device_status(device, ACPI_STA_DEFAULT); + return 0; + } + status = acpi_bus_get_status_handle(device->handle, &sta); if (ACPI_FAILURE(status)) return -ENODEV; diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 668137e4a069..b7c2a06963d6 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -216,7 +216,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) } if (state) - pm_wakeup_event(&device->dev, 0); + pm_wakeup_hard_event(&device->dev); ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); if (ret == NOTIFY_DONE) @@ -398,7 +398,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) } else { int keycode; - pm_wakeup_event(&device->dev, 0); + pm_wakeup_hard_event(&device->dev); if (button->suspended) break; @@ -530,6 +530,7 @@ static int acpi_button_add(struct acpi_device *device) lid_device = device; } + device_init_wakeup(&device->dev, true); printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); return 0; diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 993fd31394c8..798d5003a039 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -24,6 +24,7 @@ #include <linux/pm_qos.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/suspend.h> #include "internal.h" @@ -399,7 +400,7 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) mutex_lock(&acpi_pm_notifier_lock); if (adev->wakeup.flags.notifier_present) { - __pm_wakeup_event(adev->wakeup.ws, 0); + pm_wakeup_ws_event(adev->wakeup.ws, 0, true); if (adev->wakeup.context.work.func) queue_pm_work(&adev->wakeup.context.work); } diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 3e7020751d34..3be1433853bf 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -179,7 +179,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) struct list_head *physnode_list; unsigned int node_id; int retval = -EINVAL; - enum dev_dma_attr attr; if (has_acpi_companion(dev)) { if (acpi_dev) { @@ -236,10 +235,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) if (!has_acpi_companion(dev)) ACPI_COMPANION_SET(dev, acpi_dev); - attr = acpi_get_dma_attr(acpi_dev); - if (attr != DEV_DMA_NOT_SUPPORTED) - acpi_dma_configure(dev, attr); - acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, physical_node_name); diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 55f51115f016..1a76c784cd4c 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -27,97 +27,97 @@ static struct pmic_table power_table[] = { .address = 0x00, .reg = 0x13, .bit = 0x05, - }, + }, /* ALD1 */ { .address = 0x04, .reg = 0x13, .bit = 0x06, - }, + }, /* ALD2 */ { .address = 0x08, .reg = 0x13, .bit = 0x07, - }, + }, /* ALD3 */ { .address = 0x0c, .reg = 0x12, .bit = 0x03, - }, + }, /* DLD1 */ { .address = 0x10, .reg = 0x12, .bit = 0x04, - }, + }, /* DLD2 */ { .address = 0x14, .reg = 0x12, .bit = 0x05, - }, + }, /* DLD3 */ { .address = 0x18, .reg = 0x12, .bit = 0x06, - }, + }, /* DLD4 */ { .address = 0x1c, .reg = 0x12, .bit = 0x00, - }, + }, /* ELD1 */ { .address = 0x20, .reg = 0x12, .bit = 0x01, - }, + }, /* ELD2 */ { .address = 0x24, .reg = 0x12, .bit = 0x02, - }, + }, /* ELD3 */ { .address = 0x28, .reg = 0x13, .bit = 0x02, - }, + }, /* FLD1 */ { .address = 0x2c, .reg = 0x13, .bit = 0x03, - }, + }, /* FLD2 */ { .address = 0x30, .reg = 0x13, .bit = 0x04, - }, + }, /* FLD3 */ { - .address = 0x38, + .address = 0x34, .reg = 0x10, .bit = 0x03, - }, + }, /* BUC1 */ { - .address = 0x3c, + .address = 0x38, .reg = 0x10, .bit = 0x06, - }, + }, /* BUC2 */ { - .address = 0x40, + .address = 0x3c, .reg = 0x10, .bit = 0x05, - }, + }, /* BUC3 */ { - .address = 0x44, + .address = 0x40, .reg = 0x10, .bit = 0x04, - }, + }, /* BUC4 */ { - .address = 0x48, + .address = 0x44, .reg = 0x10, .bit = 0x01, - }, + }, /* BUC5 */ { - .address = 0x4c, + .address = 0x48, .reg = 0x10, .bit = 0x00 - }, + }, /* BUC6 */ }; /* TMP0 - TMP5 are the same, all from GPADC */ diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 1c2b846c5776..3a6c9b741b23 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -864,6 +864,16 @@ void acpi_resume_power_resources(void) mutex_unlock(&resource->resource_lock); } + + mutex_unlock(&power_resource_list_lock); +} + +void acpi_turn_off_unused_power_resources(void) +{ + struct acpi_power_resource *resource; + + mutex_lock(&power_resource_list_lock); + list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) { int result, state; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c26931067415..e39ec7b7cb67 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1363,20 +1363,25 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) * @dev: The pointer to the device * @attr: device dma attributes */ -void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) +int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { const struct iommu_ops *iommu; + u64 size; iort_set_dma_mask(dev); iommu = iort_iommu_configure(dev); + if (IS_ERR(iommu)) + return PTR_ERR(iommu); + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); /* * Assume dma valid range starts at 0 and covers the whole * coherent_dma_mask. */ - arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu, - attr == DEV_DMA_COHERENT); + arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT); + + return 0; } EXPORT_SYMBOL_GPL(acpi_dma_configure); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index a4327af676fe..a6574d626340 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -474,6 +474,7 @@ static void acpi_pm_start(u32 acpi_state) */ static void acpi_pm_end(void) { + acpi_turn_off_unused_power_resources(); acpi_scan_lock_release(); /* * This is necessary in case acpi_pm_finish() is not called during a @@ -662,14 +663,40 @@ static int acpi_freeze_prepare(void) acpi_os_wait_events_complete(); if (acpi_sci_irq_valid()) enable_irq_wake(acpi_sci_irq); + return 0; } +static void acpi_freeze_wake(void) +{ + /* + * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means + * that the SCI has triggered while suspended, so cancel the wakeup in + * case it has not been a wakeup event (the GPEs will be checked later). + */ + if (acpi_sci_irq_valid() && + !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) + pm_system_cancel_wakeup(); +} + +static void acpi_freeze_sync(void) +{ + /* + * Process all pending events in case there are any wakeup ones. + * + * The EC driver uses the system workqueue, so that one needs to be + * flushed too. + */ + acpi_os_wait_events_complete(); + flush_scheduled_work(); +} + static void acpi_freeze_restore(void) { acpi_disable_wakeup_devices(ACPI_STATE_S0); if (acpi_sci_irq_valid()) disable_irq_wake(acpi_sci_irq); + acpi_enable_all_runtime_gpes(); } @@ -681,6 +708,8 @@ static void acpi_freeze_end(void) static const struct platform_freeze_ops acpi_freeze_ops = { .begin = acpi_freeze_begin, .prepare = acpi_freeze_prepare, + .wake = acpi_freeze_wake, + .sync = acpi_freeze_sync, .restore = acpi_freeze_restore, .end = acpi_freeze_end, }; diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h index a9cc34e663f9..a82ff74faf7a 100644 --- a/drivers/acpi/sleep.h +++ b/drivers/acpi/sleep.h @@ -6,6 +6,7 @@ extern struct list_head acpi_wakeup_device_list; extern struct mutex acpi_device_lock; extern void acpi_resume_power_resources(void); +extern void acpi_turn_off_unused_power_resources(void); static inline acpi_status acpi_set_waking_vector(u32 wakeup_address) { diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c new file mode 100644 index 000000000000..bd86b809c848 --- /dev/null +++ b/drivers/acpi/x86/utils.c @@ -0,0 +1,90 @@ +/* + * X86 ACPI Utility Functions + * + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> + * + * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: + * Copyright (C) 2013-2015 Intel Corporation. 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 as + * published by the Free Software Foundation. + */ + +#include <linux/acpi.h> +#include <asm/cpu_device_id.h> +#include <asm/intel-family.h> +#include "../internal.h" + +/* + * Some ACPI devices are hidden (status == 0x0) in recent BIOS-es because + * some recent Windows drivers bind to one device but poke at multiple + * devices at the same time, so the others get hidden. + * We work around this by always reporting ACPI_STA_DEFAULT for these + * devices. Note this MUST only be done for devices where this is safe. + * + * This forcing of devices to be present is limited to specific CPU (SoC) + * models both to avoid potentially causing trouble on other models and + * because some HIDs are re-used on different SoCs for completely + * different devices. + */ +struct always_present_id { + struct acpi_device_id hid[2]; + struct x86_cpu_id cpu_ids[2]; + const char *uid; +}; + +#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } + +#define ENTRY(hid, uid, cpu_models) { \ + { { hid, }, {} }, \ + { cpu_models, {} }, \ + uid, \ +} + +static const struct always_present_id always_present_ids[] = { + /* + * Bay / Cherry Trail PWM directly poked by GPU driver in win10, + * but Linux uses a separate PWM driver, harmless if not used. + */ + ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1)), + ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)), + /* + * The INT0002 device is necessary to clear wakeup interrupt sources + * on Cherry Trail devices, without it we get nobody cared IRQ msgs. + */ + ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)), +}; + +bool acpi_device_always_present(struct acpi_device *adev) +{ + u32 *status = (u32 *)&adev->status; + u32 old_status = *status; + bool ret = false; + unsigned int i; + + /* acpi_match_device_ids checks status, so set it to default */ + *status = ACPI_STA_DEFAULT; + for (i = 0; i < ARRAY_SIZE(always_present_ids); i++) { + if (acpi_match_device_ids(adev, always_present_ids[i].hid)) + continue; + + if (!adev->pnp.unique_id || + strcmp(adev->pnp.unique_id, always_present_ids[i].uid)) + continue; + + if (!x86_match_cpu(always_present_ids[i].cpu_ids)) + continue; + + if (old_status != ACPI_STA_DEFAULT) /* Log only once */ + dev_info(&adev->dev, + "Device [%s] is in always present list\n", + adev->pnp.bus_id); + + ret = true; + break; + } + *status = old_status; + + return ret; +} diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index ff6cb9e4c381..de3eaf051697 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -518,6 +518,15 @@ config PATA_BF54X If unsure, say N. +config PATA_BK3710 + tristate "Palmchip BK3710 PATA support" + depends on ARCH_DAVINCI + help + This option enables support for the integrated IDE controller on + the TI DaVinci SoC. + + If unsure, say N. + config PATA_CMD64X tristate "CMD64x PATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 3048cc100a46..cd931a5eba92 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_PATA_ARTOP) += pata_artop.o obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o obj-$(CONFIG_PATA_ATP867X) += pata_atp867x.o obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o +obj-$(CONFIG_PATA_BK3710) += pata_bk3710.o obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o diff --git a/drivers/ata/pata_bk3710.c b/drivers/ata/pata_bk3710.c new file mode 100644 index 000000000000..6c3bd5fae3e4 --- /dev/null +++ b/drivers/ata/pata_bk3710.c @@ -0,0 +1,382 @@ +/* + * Palmchip BK3710 PATA controller driver + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Based on palm_bk3710.c: + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/ata.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/libata.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#define DRV_NAME "pata_bk3710" + +#define BK3710_TF_OFFSET 0x1F0 +#define BK3710_CTL_OFFSET 0x3F6 + +#define BK3710_BMISP 0x02 +#define BK3710_IDETIMP 0x40 +#define BK3710_UDMACTL 0x48 +#define BK3710_MISCCTL 0x50 +#define BK3710_REGSTB 0x54 +#define BK3710_REGRCVR 0x58 +#define BK3710_DATSTB 0x5C +#define BK3710_DATRCVR 0x60 +#define BK3710_DMASTB 0x64 +#define BK3710_DMARCVR 0x68 +#define BK3710_UDMASTB 0x6C +#define BK3710_UDMATRP 0x70 +#define BK3710_UDMAENV 0x74 +#define BK3710_IORDYTMP 0x78 + +static struct scsi_host_template pata_bk3710_sht = { + ATA_BMDMA_SHT(DRV_NAME), +}; + +static unsigned int ideclk_period; /* in nanoseconds */ + +struct pata_bk3710_udmatiming { + unsigned int rptime; /* tRP -- Ready to pause time (nsec) */ + unsigned int cycletime; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */ + /* tENV is always a minimum of 20 nsec */ +}; + +static const struct pata_bk3710_udmatiming pata_bk3710_udmatimings[6] = { + { 160, 240 / 2 }, /* UDMA Mode 0 */ + { 125, 160 / 2 }, /* UDMA Mode 1 */ + { 100, 120 / 2 }, /* UDMA Mode 2 */ + { 100, 90 / 2 }, /* UDMA Mode 3 */ + { 100, 60 / 2 }, /* UDMA Mode 4 */ + { 85, 40 / 2 }, /* UDMA Mode 5 */ +}; + +static void pata_bk3710_setudmamode(void __iomem *base, unsigned int dev, + unsigned int mode) +{ + u32 val32; + u16 val16; + u8 tenv, trp, t0; + + /* DMA Data Setup */ + t0 = DIV_ROUND_UP(pata_bk3710_udmatimings[mode].cycletime, + ideclk_period) - 1; + tenv = DIV_ROUND_UP(20, ideclk_period) - 1; + trp = DIV_ROUND_UP(pata_bk3710_udmatimings[mode].rptime, + ideclk_period) - 1; + + /* udmastb Ultra DMA Access Strobe Width */ + val32 = ioread32(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8)); + val32 |= t0 << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_UDMASTB); + + /* udmatrp Ultra DMA Ready to Pause Time */ + val32 = ioread32(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8)); + val32 |= trp << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_UDMATRP); + + /* udmaenv Ultra DMA envelop Time */ + val32 = ioread32(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8)); + val32 |= tenv << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_UDMAENV); + + /* Enable UDMA for Device */ + val16 = ioread16(base + BK3710_UDMACTL) | (1 << dev); + iowrite16(val16, base + BK3710_UDMACTL); +} + +static void pata_bk3710_setmwdmamode(void __iomem *base, unsigned int dev, + unsigned short min_cycle, + unsigned int mode) +{ + const struct ata_timing *t; + int cycletime; + u32 val32; + u16 val16; + u8 td, tkw, t0; + + t = ata_timing_find_mode(mode); + cycletime = max_t(int, t->cycle, min_cycle); + + /* DMA Data Setup */ + t0 = DIV_ROUND_UP(cycletime, ideclk_period); + td = DIV_ROUND_UP(t->active, ideclk_period); + tkw = t0 - td - 1; + td--; + + val32 = ioread32(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8)); + val32 |= td << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_DMASTB); + + val32 = ioread32(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= tkw << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_DMARCVR); + + /* Disable UDMA for Device */ + val16 = ioread16(base + BK3710_UDMACTL) & ~(1 << dev); + iowrite16(val16, base + BK3710_UDMACTL); +} + +static void pata_bk3710_set_dmamode(struct ata_port *ap, + struct ata_device *adev) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.bmdma_addr; + int is_slave = adev->devno; + const u8 xferspeed = adev->dma_mode; + + if (xferspeed >= XFER_UDMA_0) + pata_bk3710_setudmamode(base, is_slave, + xferspeed - XFER_UDMA_0); + else + pata_bk3710_setmwdmamode(base, is_slave, + adev->id[ATA_ID_EIDE_DMA_MIN], + xferspeed); +} + +static void pata_bk3710_setpiomode(void __iomem *base, struct ata_device *pair, + unsigned int dev, unsigned int cycletime, + unsigned int mode) +{ + const struct ata_timing *t; + u32 val32; + u8 t2, t2i, t0; + + t = ata_timing_find_mode(XFER_PIO_0 + mode); + + /* PIO Data Setup */ + t0 = DIV_ROUND_UP(cycletime, ideclk_period); + t2 = DIV_ROUND_UP(t->active, ideclk_period); + + t2i = t0 - t2 - 1; + t2--; + + val32 = ioread32(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8)); + val32 |= t2 << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_DATSTB); + + val32 = ioread32(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= t2i << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_DATRCVR); + + /* FIXME: this is broken also in the old driver */ + if (pair) { + u8 mode2 = pair->pio_mode - XFER_PIO_0; + + if (mode2 < mode) + mode = mode2; + } + + /* TASKFILE Setup */ + t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period); + t2 = DIV_ROUND_UP(t->act8b, ideclk_period); + + t2i = t0 - t2 - 1; + t2--; + + val32 = ioread32(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8)); + val32 |= t2 << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_REGSTB); + + val32 = ioread32(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= t2i << (dev ? 8 : 0); + iowrite32(val32, base + BK3710_REGRCVR); +} + +static void pata_bk3710_set_piomode(struct ata_port *ap, + struct ata_device *adev) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.bmdma_addr; + struct ata_device *pair = ata_dev_pair(adev); + const struct ata_timing *t = ata_timing_find_mode(adev->pio_mode); + const u16 *id = adev->id; + unsigned int cycle_time = 0; + int is_slave = adev->devno; + const u8 pio = adev->pio_mode - XFER_PIO_0; + + if (id[ATA_ID_FIELD_VALID] & 2) { + if (ata_id_has_iordy(id)) + cycle_time = id[ATA_ID_EIDE_PIO_IORDY]; + else + cycle_time = id[ATA_ID_EIDE_PIO]; + + /* conservative "downgrade" for all pre-ATA2 drives */ + if (pio < 3 && cycle_time < t->cycle) + cycle_time = 0; /* use standard timing */ + } + + if (!cycle_time) + cycle_time = t->cycle; + + pata_bk3710_setpiomode(base, pair, is_slave, cycle_time, pio); +} + +static void pata_bk3710_chipinit(void __iomem *base) +{ + /* + * REVISIT: the ATA reset signal needs to be managed through a + * GPIO, which means it should come from platform_data. Until + * we get and use such information, we have to trust that things + * have been reset before we get here. + */ + + /* + * Program the IDETIMP Register Value based on the following assumptions + * + * (ATA_IDETIMP_IDEEN , ENABLE ) | + * (ATA_IDETIMP_PREPOST1 , DISABLE) | + * (ATA_IDETIMP_PREPOST0 , DISABLE) | + * + * DM6446 silicon rev 2.1 and earlier have no observed net benefit + * from enabling prefetch/postwrite. + */ + iowrite16(BIT(15), base + BK3710_IDETIMP); + + /* + * UDMACTL Ultra-ATA DMA Control + * (ATA_UDMACTL_UDMAP1 , 0 ) | + * (ATA_UDMACTL_UDMAP0 , 0 ) + * + */ + iowrite16(0, base + BK3710_UDMACTL); + + /* + * MISCCTL Miscellaneous Conrol Register + * (ATA_MISCCTL_HWNHLD1P , 1 cycle) + * (ATA_MISCCTL_HWNHLD0P , 1 cycle) + * (ATA_MISCCTL_TIMORIDE , 1) + */ + iowrite32(0x001, base + BK3710_MISCCTL); + + /* + * IORDYTMP IORDY Timer for Primary Register + * (ATA_IORDYTMP_IORDYTMP , DISABLE) + */ + iowrite32(0, base + BK3710_IORDYTMP); + + /* + * Configure BMISP Register + * (ATA_BMISP_DMAEN1 , DISABLE ) | + * (ATA_BMISP_DMAEN0 , DISABLE ) | + * (ATA_BMISP_IORDYINT , CLEAR) | + * (ATA_BMISP_INTRSTAT , CLEAR) | + * (ATA_BMISP_DMAERROR , CLEAR) + */ + iowrite16(0xE, base + BK3710_BMISP); + + pata_bk3710_setpiomode(base, NULL, 0, 600, 0); + pata_bk3710_setpiomode(base, NULL, 1, 600, 0); +} + +static struct ata_port_operations pata_bk3710_ports_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = ata_cable_80wire, + + .set_piomode = pata_bk3710_set_piomode, + .set_dmamode = pata_bk3710_set_dmamode, +}; + +static int __init pata_bk3710_probe(struct platform_device *pdev) +{ + struct clk *clk; + struct resource *mem; + struct ata_host *host; + struct ata_port *ap; + void __iomem *base; + unsigned long rate; + int irq; + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) + return -ENODEV; + + clk_enable(clk); + rate = clk_get_rate(clk); + if (!rate) + return -EINVAL; + + /* NOTE: round *down* to meet minimum timings; we count in clocks */ + ideclk_period = 1000000000UL / rate; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + pr_err(DRV_NAME ": failed to get IRQ resource\n"); + return irq; + } + + base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* configure the Palmchip controller */ + pata_bk3710_chipinit(base); + + /* allocate host */ + host = ata_host_alloc(&pdev->dev, 1); + if (!host) + return -ENOMEM; + ap = host->ports[0]; + + ap->ops = &pata_bk3710_ports_ops; + ap->pio_mask = ATA_PIO4; + ap->mwdma_mask = ATA_MWDMA2; + ap->udma_mask = rate < 100000000 ? ATA_UDMA4 : ATA_UDMA5; + ap->flags |= ATA_FLAG_SLAVE_POSS; + + ap->ioaddr.data_addr = base + BK3710_TF_OFFSET; + ap->ioaddr.error_addr = base + BK3710_TF_OFFSET + 1; + ap->ioaddr.feature_addr = base + BK3710_TF_OFFSET + 1; + ap->ioaddr.nsect_addr = base + BK3710_TF_OFFSET + 2; + ap->ioaddr.lbal_addr = base + BK3710_TF_OFFSET + 3; + ap->ioaddr.lbam_addr = base + BK3710_TF_OFFSET + 4; + ap->ioaddr.lbah_addr = base + BK3710_TF_OFFSET + 5; + ap->ioaddr.device_addr = base + BK3710_TF_OFFSET + 6; + ap->ioaddr.status_addr = base + BK3710_TF_OFFSET + 7; + ap->ioaddr.command_addr = base + BK3710_TF_OFFSET + 7; + + ap->ioaddr.altstatus_addr = base + BK3710_CTL_OFFSET; + ap->ioaddr.ctl_addr = base + BK3710_CTL_OFFSET; + + ap->ioaddr.bmdma_addr = base; + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", + (unsigned long)base + BK3710_TF_OFFSET, + (unsigned long)base + BK3710_CTL_OFFSET); + + /* activate */ + return ata_host_activate(host, irq, ata_sff_interrupt, 0, + &pata_bk3710_sht); +} + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:palm_bk3710"); + +static struct platform_driver pata_bk3710_driver = { + .driver = { + .name = "palm_bk3710", + }, +}; + +static int __init pata_bk3710_init(void) +{ + return platform_driver_probe(&pata_bk3710_driver, pata_bk3710_probe); +} + +module_init(pata_bk3710_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a1fbf55c4d3a..4882f06d12df 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -19,6 +19,7 @@ #include <linux/device.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/kthread.h> #include <linux/wait.h> @@ -356,6 +357,10 @@ re_probe: if (ret) goto pinctrl_bind_failed; + ret = dma_configure(dev); + if (ret) + goto dma_failed; + if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev)); @@ -417,6 +422,8 @@ re_probe: goto done; probe_failed: + dma_deconfigure(dev); +dma_failed: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DRIVER_NOT_BOUND, dev); @@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent) drv->remove(dev); device_links_driver_cleanup(dev); + dma_deconfigure(dev); + devres_release_all(dev); dev->driver = NULL; dev_set_drvdata(dev, NULL); diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 51b7061ff7c0..f3deb6af42ad 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -7,9 +7,11 @@ * This file is released under the GPLv2. */ +#include <linux/acpi.h> #include <linux/dma-mapping.h> #include <linux/export.h> #include <linux/gfp.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/vmalloc.h> @@ -340,3 +342,42 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) vunmap(cpu_addr); } #endif + +/* + * Common configuration to enable DMA API use for a device + */ +#include <linux/pci.h> + +int dma_configure(struct device *dev) +{ + struct device *bridge = NULL, *dma_dev = dev; + enum dev_dma_attr attr; + int ret = 0; + + if (dev_is_pci(dev)) { + bridge = pci_get_host_bridge_device(to_pci_dev(dev)); + dma_dev = bridge; + if (IS_ENABLED(CONFIG_OF) && dma_dev->parent && + dma_dev->parent->of_node) + dma_dev = dma_dev->parent; + } + + if (dma_dev->of_node) { + ret = of_dma_configure(dev, dma_dev->of_node); + } else if (has_acpi_companion(dma_dev)) { + attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode)); + if (attr != DEV_DMA_NOT_SUPPORTED) + ret = acpi_dma_configure(dev, attr); + } + + if (bridge) + pci_put_host_bridge_device(bridge); + + return ret; +} + +void dma_deconfigure(struct device *dev) +{ + of_dma_deconfigure(dev); + acpi_dma_deconfigure(dev); +} diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index ad196427b4f2..da49a8383dc3 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1636,8 +1636,6 @@ static struct generic_pm_domain *genpd_xlate_simple( struct of_phandle_args *genpdspec, void *data) { - if (genpdspec->args_count != 0) - return ERR_PTR(-EINVAL); return data; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9faee1c893e5..e987a6f55d36 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1091,11 +1091,6 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (async_error) goto Complete; - if (pm_wakeup_pending()) { - async_error = -EBUSY; - goto Complete; - } - if (dev->power.syscore || dev->power.direct_complete) goto Complete; diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 136854970489..f62082fdd670 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -28,8 +28,8 @@ bool events_check_enabled __read_mostly; /* First wakeup IRQ seen by the kernel in the last cycle. */ unsigned int pm_wakeup_irq __read_mostly; -/* If set and the system is suspending, terminate the suspend. */ -static bool pm_abort_suspend __read_mostly; +/* If greater than 0 and the system is suspending, terminate the suspend. */ +static atomic_t pm_abort_suspend __read_mostly; /* * Combined counters of registered wakeup events and wakeup events in progress. @@ -512,12 +512,13 @@ static bool wakeup_source_not_registered(struct wakeup_source *ws) /** * wakup_source_activate - Mark given wakeup source as active. * @ws: Wakeup source to handle. + * @hard: If set, abort suspends in progress and wake up from suspend-to-idle. * * Update the @ws' statistics and, if @ws has just been activated, notify the PM * core of the event by incrementing the counter of of wakeup events being * processed. */ -static void wakeup_source_activate(struct wakeup_source *ws) +static void wakeup_source_activate(struct wakeup_source *ws, bool hard) { unsigned int cec; @@ -525,11 +526,8 @@ static void wakeup_source_activate(struct wakeup_source *ws) "unregistered wakeup source\n")) return; - /* - * active wakeup source should bring the system - * out of PM_SUSPEND_FREEZE state - */ - freeze_wake(); + if (hard) + pm_system_wakeup(); ws->active = true; ws->active_count++; @@ -546,8 +544,9 @@ static void wakeup_source_activate(struct wakeup_source *ws) /** * wakeup_source_report_event - Report wakeup event using the given source. * @ws: Wakeup source to report the event for. + * @hard: If set, abort suspends in progress and wake up from suspend-to-idle. */ -static void wakeup_source_report_event(struct wakeup_source *ws) +static void wakeup_source_report_event(struct wakeup_source *ws, bool hard) { ws->event_count++; /* This is racy, but the counter is approximate anyway. */ @@ -555,7 +554,7 @@ static void wakeup_source_report_event(struct wakeup_source *ws) ws->wakeup_count++; if (!ws->active) - wakeup_source_activate(ws); + wakeup_source_activate(ws, hard); } /** @@ -573,7 +572,7 @@ void __pm_stay_awake(struct wakeup_source *ws) spin_lock_irqsave(&ws->lock, flags); - wakeup_source_report_event(ws); + wakeup_source_report_event(ws, false); del_timer(&ws->timer); ws->timer_expires = 0; @@ -739,9 +738,10 @@ static void pm_wakeup_timer_fn(unsigned long data) } /** - * __pm_wakeup_event - Notify the PM core of a wakeup event. + * pm_wakeup_ws_event - Notify the PM core of a wakeup event. * @ws: Wakeup source object associated with the event source. * @msec: Anticipated event processing time (in milliseconds). + * @hard: If set, abort suspends in progress and wake up from suspend-to-idle. * * Notify the PM core of a wakeup event whose source is @ws that will take * approximately @msec milliseconds to be processed by the kernel. If @ws is @@ -750,7 +750,7 @@ static void pm_wakeup_timer_fn(unsigned long data) * * It is safe to call this function from interrupt context. */ -void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) +void pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard) { unsigned long flags; unsigned long expires; @@ -760,7 +760,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) spin_lock_irqsave(&ws->lock, flags); - wakeup_source_report_event(ws); + wakeup_source_report_event(ws, hard); if (!msec) { wakeup_source_deactivate(ws); @@ -779,17 +779,17 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) unlock: spin_unlock_irqrestore(&ws->lock, flags); } -EXPORT_SYMBOL_GPL(__pm_wakeup_event); - +EXPORT_SYMBOL_GPL(pm_wakeup_ws_event); /** * pm_wakeup_event - Notify the PM core of a wakeup event. * @dev: Device the wakeup event is related to. * @msec: Anticipated event processing time (in milliseconds). + * @hard: If set, abort suspends in progress and wake up from suspend-to-idle. * - * Call __pm_wakeup_event() for the @dev's wakeup source object. + * Call pm_wakeup_ws_event() for the @dev's wakeup source object. */ -void pm_wakeup_event(struct device *dev, unsigned int msec) +void pm_wakeup_dev_event(struct device *dev, unsigned int msec, bool hard) { unsigned long flags; @@ -797,10 +797,10 @@ void pm_wakeup_event(struct device *dev, unsigned int msec) return; spin_lock_irqsave(&dev->power.lock, flags); - __pm_wakeup_event(dev->power.wakeup, msec); + pm_wakeup_ws_event(dev->power.wakeup, msec, hard); spin_unlock_irqrestore(&dev->power.lock, flags); } -EXPORT_SYMBOL_GPL(pm_wakeup_event); +EXPORT_SYMBOL_GPL(pm_wakeup_dev_event); void pm_print_active_wakeup_sources(void) { @@ -856,20 +856,26 @@ bool pm_wakeup_pending(void) pm_print_active_wakeup_sources(); } - return ret || pm_abort_suspend; + return ret || atomic_read(&pm_abort_suspend) > 0; } void pm_system_wakeup(void) { - pm_abort_suspend = true; + atomic_inc(&pm_abort_suspend); freeze_wake(); } EXPORT_SYMBOL_GPL(pm_system_wakeup); -void pm_wakeup_clear(void) +void pm_system_cancel_wakeup(void) +{ + atomic_dec(&pm_abort_suspend); +} + +void pm_wakeup_clear(bool reset) { - pm_abort_suspend = false; pm_wakeup_irq = 0; + if (reset) + atomic_set(&pm_abort_suspend, 0); } void pm_system_irq_wakeup(unsigned int irq_number) diff --git a/drivers/base/soc.c b/drivers/base/soc.c index dc26e5949a32..909dedae4c4e 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -109,15 +109,18 @@ static void soc_release(struct device *dev) kfree(soc_dev); } +static struct soc_device_attribute *early_soc_dev_attr; + struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr) { struct soc_device *soc_dev; int ret; if (!soc_bus_type.p) { - ret = bus_register(&soc_bus_type); - if (ret) - goto out1; + if (early_soc_dev_attr) + return ERR_PTR(-EBUSY); + early_soc_dev_attr = soc_dev_attr; + return NULL; } soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL); @@ -159,45 +162,53 @@ void soc_device_unregister(struct soc_device *soc_dev) ida_simple_remove(&soc_ida, soc_dev->soc_dev_num); device_unregister(&soc_dev->dev); + early_soc_dev_attr = NULL; } static int __init soc_bus_register(void) { - if (soc_bus_type.p) - return 0; + int ret; - return bus_register(&soc_bus_type); + ret = bus_register(&soc_bus_type); + if (ret) + return ret; + + if (early_soc_dev_attr) + return PTR_ERR(soc_device_register(early_soc_dev_attr)); + + return 0; } core_initcall(soc_bus_register); -static int soc_device_match_one(struct device *dev, void *arg) +static int soc_device_match_attr(const struct soc_device_attribute *attr, + const struct soc_device_attribute *match) { - struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); - const struct soc_device_attribute *match = arg; - if (match->machine && - (!soc_dev->attr->machine || - !glob_match(match->machine, soc_dev->attr->machine))) + (!attr->machine || !glob_match(match->machine, attr->machine))) return 0; if (match->family && - (!soc_dev->attr->family || - !glob_match(match->family, soc_dev->attr->family))) + (!attr->family || !glob_match(match->family, attr->family))) return 0; if (match->revision && - (!soc_dev->attr->revision || - !glob_match(match->revision, soc_dev->attr->revision))) + (!attr->revision || !glob_match(match->revision, attr->revision))) return 0; if (match->soc_id && - (!soc_dev->attr->soc_id || - !glob_match(match->soc_id, soc_dev->attr->soc_id))) + (!attr->soc_id || !glob_match(match->soc_id, attr->soc_id))) return 0; return 1; } +static int soc_device_match_one(struct device *dev, void *arg) +{ + struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); + + return soc_device_match_attr(soc_dev->attr, arg); +} + /* * soc_device_match - identify the SoC in the machine * @matches: zero-terminated array of possible matches @@ -230,6 +241,11 @@ const struct soc_device_attribute *soc_device_match( break; ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches, soc_device_match_one); + if (ret < 0 && early_soc_dev_attr) + ret = soc_device_match_attr(early_soc_dev_attr, + matches); + if (ret < 0) + return NULL; if (!ret) matches++; else diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 26812c1ed0cf..454bf9c34882 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -387,6 +387,7 @@ struct rbd_device { struct rw_semaphore lock_rwsem; enum rbd_lock_state lock_state; + char lock_cookie[32]; struct rbd_client_id owner_cid; struct work_struct acquired_lock_work; struct work_struct released_lock_work; @@ -477,13 +478,6 @@ static int minor_to_rbd_dev_id(int minor) return minor >> RBD_SINGLE_MAJOR_PART_SHIFT; } -static bool rbd_is_lock_supported(struct rbd_device *rbd_dev) -{ - return (rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK) && - rbd_dev->spec->snap_id == CEPH_NOSNAP && - !rbd_dev->mapping.read_only; -} - static bool __rbd_is_lock_owner(struct rbd_device *rbd_dev) { return rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED || @@ -731,7 +725,7 @@ static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts) kref_init(&rbdc->kref); INIT_LIST_HEAD(&rbdc->node); - rbdc->client = ceph_create_client(ceph_opts, rbdc, 0, 0); + rbdc->client = ceph_create_client(ceph_opts, rbdc); if (IS_ERR(rbdc->client)) goto out_rbdc; ceph_opts = NULL; /* Now rbdc->client is responsible for ceph_opts */ @@ -804,6 +798,7 @@ enum { Opt_read_only, Opt_read_write, Opt_lock_on_read, + Opt_exclusive, Opt_err }; @@ -816,6 +811,7 @@ static match_table_t rbd_opts_tokens = { {Opt_read_write, "read_write"}, {Opt_read_write, "rw"}, /* Alternate spelling */ {Opt_lock_on_read, "lock_on_read"}, + {Opt_exclusive, "exclusive"}, {Opt_err, NULL} }; @@ -823,11 +819,13 @@ struct rbd_options { int queue_depth; bool read_only; bool lock_on_read; + bool exclusive; }; #define RBD_QUEUE_DEPTH_DEFAULT BLKDEV_MAX_RQ #define RBD_READ_ONLY_DEFAULT false #define RBD_LOCK_ON_READ_DEFAULT false +#define RBD_EXCLUSIVE_DEFAULT false static int parse_rbd_opts_token(char *c, void *private) { @@ -866,6 +864,9 @@ static int parse_rbd_opts_token(char *c, void *private) case Opt_lock_on_read: rbd_opts->lock_on_read = true; break; + case Opt_exclusive: + rbd_opts->exclusive = true; + break; default: /* libceph prints "bad option" msg */ return -EINVAL; @@ -3079,7 +3080,8 @@ static int rbd_lock(struct rbd_device *rbd_dev) char cookie[32]; int ret; - WARN_ON(__rbd_is_lock_owner(rbd_dev)); + WARN_ON(__rbd_is_lock_owner(rbd_dev) || + rbd_dev->lock_cookie[0] != '\0'); format_lock_cookie(rbd_dev, cookie); ret = ceph_cls_lock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc, @@ -3089,6 +3091,7 @@ static int rbd_lock(struct rbd_device *rbd_dev) return ret; rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED; + strcpy(rbd_dev->lock_cookie, cookie); rbd_set_owner_cid(rbd_dev, &cid); queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work); return 0; @@ -3097,27 +3100,24 @@ static int rbd_lock(struct rbd_device *rbd_dev) /* * lock_rwsem must be held for write */ -static int rbd_unlock(struct rbd_device *rbd_dev) +static void rbd_unlock(struct rbd_device *rbd_dev) { struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; - char cookie[32]; int ret; - WARN_ON(!__rbd_is_lock_owner(rbd_dev)); - - rbd_dev->lock_state = RBD_LOCK_STATE_UNLOCKED; + WARN_ON(!__rbd_is_lock_owner(rbd_dev) || + rbd_dev->lock_cookie[0] == '\0'); - format_lock_cookie(rbd_dev, cookie); ret = ceph_cls_unlock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc, - RBD_LOCK_NAME, cookie); - if (ret && ret != -ENOENT) { - rbd_warn(rbd_dev, "cls_unlock failed: %d", ret); - return ret; - } + RBD_LOCK_NAME, rbd_dev->lock_cookie); + if (ret && ret != -ENOENT) + rbd_warn(rbd_dev, "failed to unlock: %d", ret); + /* treat errors as the image is unlocked */ + rbd_dev->lock_state = RBD_LOCK_STATE_UNLOCKED; + rbd_dev->lock_cookie[0] = '\0'; rbd_set_owner_cid(rbd_dev, &rbd_empty_cid); queue_work(rbd_dev->task_wq, &rbd_dev->released_lock_work); - return 0; } static int __rbd_notify_op_lock(struct rbd_device *rbd_dev, @@ -3447,6 +3447,18 @@ again: ret = rbd_request_lock(rbd_dev); if (ret == -ETIMEDOUT) { goto again; /* treat this as a dead client */ + } else if (ret == -EROFS) { + rbd_warn(rbd_dev, "peer will not release lock"); + /* + * If this is rbd_add_acquire_lock(), we want to fail + * immediately -- reuse BLACKLISTED flag. Otherwise we + * want to block. + */ + if (!(rbd_dev->disk->flags & GENHD_FL_UP)) { + set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags); + /* wake "rbd map --exclusive" process */ + wake_requests(rbd_dev, false); + } } else if (ret < 0) { rbd_warn(rbd_dev, "error requesting lock: %d", ret); mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, @@ -3490,16 +3502,15 @@ static bool rbd_release_lock(struct rbd_device *rbd_dev) if (rbd_dev->lock_state != RBD_LOCK_STATE_RELEASING) return false; - if (!rbd_unlock(rbd_dev)) - /* - * Give others a chance to grab the lock - we would re-acquire - * almost immediately if we got new IO during ceph_osdc_sync() - * otherwise. We need to ack our own notifications, so this - * lock_dwork will be requeued from rbd_wait_state_locked() - * after wake_requests() in rbd_handle_released_lock(). - */ - cancel_delayed_work(&rbd_dev->lock_dwork); - + rbd_unlock(rbd_dev); + /* + * Give others a chance to grab the lock - we would re-acquire + * almost immediately if we got new IO during ceph_osdc_sync() + * otherwise. We need to ack our own notifications, so this + * lock_dwork will be requeued from rbd_wait_state_locked() + * after wake_requests() in rbd_handle_released_lock(). + */ + cancel_delayed_work(&rbd_dev->lock_dwork); return true; } @@ -3580,12 +3591,16 @@ static void rbd_handle_released_lock(struct rbd_device *rbd_dev, u8 struct_v, up_read(&rbd_dev->lock_rwsem); } -static bool rbd_handle_request_lock(struct rbd_device *rbd_dev, u8 struct_v, - void **p) +/* + * Returns result for ResponseMessage to be encoded (<= 0), or 1 if no + * ResponseMessage is needed. + */ +static int rbd_handle_request_lock(struct rbd_device *rbd_dev, u8 struct_v, + void **p) { struct rbd_client_id my_cid = rbd_get_cid(rbd_dev); struct rbd_client_id cid = { 0 }; - bool need_to_send; + int result = 1; if (struct_v >= 2) { cid.gid = ceph_decode_64(p); @@ -3595,19 +3610,36 @@ static bool rbd_handle_request_lock(struct rbd_device *rbd_dev, u8 struct_v, dout("%s rbd_dev %p cid %llu-%llu\n", __func__, rbd_dev, cid.gid, cid.handle); if (rbd_cid_equal(&cid, &my_cid)) - return false; + return result; down_read(&rbd_dev->lock_rwsem); - need_to_send = __rbd_is_lock_owner(rbd_dev); - if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) { - if (!rbd_cid_equal(&rbd_dev->owner_cid, &rbd_empty_cid)) { - dout("%s rbd_dev %p queueing unlock_work\n", __func__, - rbd_dev); - queue_work(rbd_dev->task_wq, &rbd_dev->unlock_work); + if (__rbd_is_lock_owner(rbd_dev)) { + if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED && + rbd_cid_equal(&rbd_dev->owner_cid, &rbd_empty_cid)) + goto out_unlock; + + /* + * encode ResponseMessage(0) so the peer can detect + * a missing owner + */ + result = 0; + + if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) { + if (!rbd_dev->opts->exclusive) { + dout("%s rbd_dev %p queueing unlock_work\n", + __func__, rbd_dev); + queue_work(rbd_dev->task_wq, + &rbd_dev->unlock_work); + } else { + /* refuse to release the lock */ + result = -EROFS; + } } } + +out_unlock: up_read(&rbd_dev->lock_rwsem); - return need_to_send; + return result; } static void __rbd_acknowledge_notify(struct rbd_device *rbd_dev, @@ -3690,13 +3722,10 @@ static void rbd_watch_cb(void *arg, u64 notify_id, u64 cookie, rbd_acknowledge_notify(rbd_dev, notify_id, cookie); break; case RBD_NOTIFY_OP_REQUEST_LOCK: - if (rbd_handle_request_lock(rbd_dev, struct_v, &p)) - /* - * send ResponseMessage(0) back so the client - * can detect a missing owner - */ + ret = rbd_handle_request_lock(rbd_dev, struct_v, &p); + if (ret <= 0) rbd_acknowledge_notify_result(rbd_dev, notify_id, - cookie, 0); + cookie, ret); else rbd_acknowledge_notify(rbd_dev, notify_id, cookie); break; @@ -3821,24 +3850,51 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev) ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); } +/* + * lock_rwsem must be held for write + */ +static void rbd_reacquire_lock(struct rbd_device *rbd_dev) +{ + struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; + char cookie[32]; + int ret; + + WARN_ON(rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED); + + format_lock_cookie(rbd_dev, cookie); + ret = ceph_cls_set_cookie(osdc, &rbd_dev->header_oid, + &rbd_dev->header_oloc, RBD_LOCK_NAME, + CEPH_CLS_LOCK_EXCLUSIVE, rbd_dev->lock_cookie, + RBD_LOCK_TAG, cookie); + if (ret) { + if (ret != -EOPNOTSUPP) + rbd_warn(rbd_dev, "failed to update lock cookie: %d", + ret); + + /* + * Lock cookie cannot be updated on older OSDs, so do + * a manual release and queue an acquire. + */ + if (rbd_release_lock(rbd_dev)) + queue_delayed_work(rbd_dev->task_wq, + &rbd_dev->lock_dwork, 0); + } else { + strcpy(rbd_dev->lock_cookie, cookie); + } +} + static void rbd_reregister_watch(struct work_struct *work) { struct rbd_device *rbd_dev = container_of(to_delayed_work(work), struct rbd_device, watch_dwork); - bool was_lock_owner = false; - bool need_to_wake = false; int ret; dout("%s rbd_dev %p\n", __func__, rbd_dev); - down_write(&rbd_dev->lock_rwsem); - if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) - was_lock_owner = rbd_release_lock(rbd_dev); - mutex_lock(&rbd_dev->watch_mutex); if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR) { mutex_unlock(&rbd_dev->watch_mutex); - goto out; + return; } ret = __rbd_register_watch(rbd_dev); @@ -3846,36 +3902,28 @@ static void rbd_reregister_watch(struct work_struct *work) rbd_warn(rbd_dev, "failed to reregister watch: %d", ret); if (ret == -EBLACKLISTED || ret == -ENOENT) { set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags); - need_to_wake = true; + wake_requests(rbd_dev, true); } else { queue_delayed_work(rbd_dev->task_wq, &rbd_dev->watch_dwork, RBD_RETRY_DELAY); } mutex_unlock(&rbd_dev->watch_mutex); - goto out; + return; } - need_to_wake = true; rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED; rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id; mutex_unlock(&rbd_dev->watch_mutex); + down_write(&rbd_dev->lock_rwsem); + if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) + rbd_reacquire_lock(rbd_dev); + up_write(&rbd_dev->lock_rwsem); + ret = rbd_dev_refresh(rbd_dev); if (ret) rbd_warn(rbd_dev, "reregisteration refresh failed: %d", ret); - - if (was_lock_owner) { - ret = rbd_try_lock(rbd_dev); - if (ret) - rbd_warn(rbd_dev, "reregisteration lock failed: %d", - ret); - } - -out: - up_write(&rbd_dev->lock_rwsem); - if (need_to_wake) - wake_requests(rbd_dev, true); } /* @@ -4034,10 +4082,6 @@ static void rbd_queue_workfn(struct work_struct *work) if (op_type != OBJ_OP_READ) { snapc = rbd_dev->header.snapc; ceph_get_snap_context(snapc); - must_be_locked = rbd_is_lock_supported(rbd_dev); - } else { - must_be_locked = rbd_dev->opts->lock_on_read && - rbd_is_lock_supported(rbd_dev); } up_read(&rbd_dev->header_rwsem); @@ -4048,14 +4092,20 @@ static void rbd_queue_workfn(struct work_struct *work) goto err_rq; } + must_be_locked = + (rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK) && + (op_type != OBJ_OP_READ || rbd_dev->opts->lock_on_read); if (must_be_locked) { down_read(&rbd_dev->lock_rwsem); if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED && - !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) + !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) { + if (rbd_dev->opts->exclusive) { + rbd_warn(rbd_dev, "exclusive lock required"); + result = -EROFS; + goto err_unlock; + } rbd_wait_state_locked(rbd_dev); - - WARN_ON((rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) ^ - !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)); + } if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) { result = -EBLACKLISTED; goto err_unlock; @@ -4114,19 +4164,10 @@ static int rbd_queue_rq(struct blk_mq_hw_ctx *hctx, static void rbd_free_disk(struct rbd_device *rbd_dev) { - struct gendisk *disk = rbd_dev->disk; - - if (!disk) - return; - + blk_cleanup_queue(rbd_dev->disk->queue); + blk_mq_free_tag_set(&rbd_dev->tag_set); + put_disk(rbd_dev->disk); rbd_dev->disk = NULL; - if (disk->flags & GENHD_FL_UP) { - del_gendisk(disk); - if (disk->queue) - blk_cleanup_queue(disk->queue); - blk_mq_free_tag_set(&rbd_dev->tag_set); - } - put_disk(disk); } static int rbd_obj_read_sync(struct rbd_device *rbd_dev, @@ -4383,8 +4424,12 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC)) q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES; + /* + * disk_release() expects a queue ref from add_disk() and will + * put it. Hold an extra ref until add_disk() is called. + */ + WARN_ON(!blk_get_queue(q)); disk->queue = q; - q->queuedata = rbd_dev; rbd_dev->disk = disk; @@ -5624,6 +5669,7 @@ static int rbd_add_parse_args(const char *buf, rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; rbd_opts->queue_depth = RBD_QUEUE_DEPTH_DEFAULT; rbd_opts->lock_on_read = RBD_LOCK_ON_READ_DEFAULT; + rbd_opts->exclusive = RBD_EXCLUSIVE_DEFAULT; copts = ceph_parse_options(options, mon_addrs, mon_addrs + mon_addrs_size - 1, @@ -5682,6 +5728,33 @@ again: return ret; } +static void rbd_dev_image_unlock(struct rbd_device *rbd_dev) +{ + down_write(&rbd_dev->lock_rwsem); + if (__rbd_is_lock_owner(rbd_dev)) + rbd_unlock(rbd_dev); + up_write(&rbd_dev->lock_rwsem); +} + +static int rbd_add_acquire_lock(struct rbd_device *rbd_dev) +{ + if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK)) { + rbd_warn(rbd_dev, "exclusive-lock feature is not enabled"); + return -EINVAL; + } + + /* FIXME: "rbd map --exclusive" should be in interruptible */ + down_read(&rbd_dev->lock_rwsem); + rbd_wait_state_locked(rbd_dev); + up_read(&rbd_dev->lock_rwsem); + if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) { + rbd_warn(rbd_dev, "failed to acquire exclusive lock"); + return -EROFS; + } + + return 0; +} + /* * An rbd format 2 image has a unique identifier, distinct from the * name given to it by the user. Internally, that identifier is @@ -5873,6 +5946,15 @@ out_err: return ret; } +static void rbd_dev_device_release(struct rbd_device *rbd_dev) +{ + clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); + rbd_dev_mapping_clear(rbd_dev); + rbd_free_disk(rbd_dev); + if (!single_major) + unregister_blkdev(rbd_dev->major, rbd_dev->name); +} + /* * rbd_dev->header_rwsem must be locked for write and will be unlocked * upon return. @@ -5908,26 +5990,13 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE); set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only); - dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id); - ret = device_add(&rbd_dev->dev); + ret = dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id); if (ret) goto err_out_mapping; - /* Everything's ready. Announce the disk to the world. */ - set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); up_write(&rbd_dev->header_rwsem); - - spin_lock(&rbd_dev_list_lock); - list_add_tail(&rbd_dev->node, &rbd_dev_list); - spin_unlock(&rbd_dev_list_lock); - - add_disk(rbd_dev->disk); - pr_info("%s: capacity %llu features 0x%llx\n", rbd_dev->disk->disk_name, - (unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT, - rbd_dev->header.features); - - return ret; + return 0; err_out_mapping: rbd_dev_mapping_clear(rbd_dev); @@ -5962,11 +6031,11 @@ static int rbd_dev_header_name(struct rbd_device *rbd_dev) static void rbd_dev_image_release(struct rbd_device *rbd_dev) { rbd_dev_unprobe(rbd_dev); + if (rbd_dev->opts) + rbd_unregister_watch(rbd_dev); rbd_dev->image_format = 0; kfree(rbd_dev->spec->image_id); rbd_dev->spec->image_id = NULL; - - rbd_dev_destroy(rbd_dev); } /* @@ -6126,22 +6195,43 @@ static ssize_t do_rbd_add(struct bus_type *bus, rbd_dev->mapping.read_only = read_only; rc = rbd_dev_device_setup(rbd_dev); - if (rc) { - /* - * rbd_unregister_watch() can't be moved into - * rbd_dev_image_release() without refactoring, see - * commit 1f3ef78861ac. - */ - rbd_unregister_watch(rbd_dev); - rbd_dev_image_release(rbd_dev); - goto out; + if (rc) + goto err_out_image_probe; + + if (rbd_dev->opts->exclusive) { + rc = rbd_add_acquire_lock(rbd_dev); + if (rc) + goto err_out_device_setup; } + /* Everything's ready. Announce the disk to the world. */ + + rc = device_add(&rbd_dev->dev); + if (rc) + goto err_out_image_lock; + + add_disk(rbd_dev->disk); + /* see rbd_init_disk() */ + blk_put_queue(rbd_dev->disk->queue); + + spin_lock(&rbd_dev_list_lock); + list_add_tail(&rbd_dev->node, &rbd_dev_list); + spin_unlock(&rbd_dev_list_lock); + + pr_info("%s: capacity %llu features 0x%llx\n", rbd_dev->disk->disk_name, + (unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT, + rbd_dev->header.features); rc = count; out: module_put(THIS_MODULE); return rc; +err_out_image_lock: + rbd_dev_image_unlock(rbd_dev); +err_out_device_setup: + rbd_dev_device_release(rbd_dev); +err_out_image_probe: + rbd_dev_image_release(rbd_dev); err_out_rbd_dev: rbd_dev_destroy(rbd_dev); err_out_client: @@ -6169,21 +6259,6 @@ static ssize_t rbd_add_single_major(struct bus_type *bus, return do_rbd_add(bus, buf, count); } -static void rbd_dev_device_release(struct rbd_device *rbd_dev) -{ - rbd_free_disk(rbd_dev); - - spin_lock(&rbd_dev_list_lock); - list_del_init(&rbd_dev->node); - spin_unlock(&rbd_dev_list_lock); - - clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); - device_del(&rbd_dev->dev); - rbd_dev_mapping_clear(rbd_dev); - if (!single_major) - unregister_blkdev(rbd_dev->major, rbd_dev->name); -} - static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) { while (rbd_dev->parent) { @@ -6201,6 +6276,7 @@ static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) } rbd_assert(second); rbd_dev_image_release(second); + rbd_dev_destroy(second); first->parent = NULL; first->parent_overlap = 0; @@ -6269,21 +6345,16 @@ static ssize_t do_rbd_remove(struct bus_type *bus, blk_set_queue_dying(rbd_dev->disk->queue); } - down_write(&rbd_dev->lock_rwsem); - if (__rbd_is_lock_owner(rbd_dev)) - rbd_unlock(rbd_dev); - up_write(&rbd_dev->lock_rwsem); - rbd_unregister_watch(rbd_dev); + del_gendisk(rbd_dev->disk); + spin_lock(&rbd_dev_list_lock); + list_del_init(&rbd_dev->node); + spin_unlock(&rbd_dev_list_lock); + device_del(&rbd_dev->dev); - /* - * Don't free anything from rbd_dev->disk until after all - * notifies are completely processed. Otherwise - * rbd_bus_del_dev() will race with rbd_watch_cb(), resulting - * in a potential use after free of rbd_dev->disk or rbd_dev. - */ + rbd_dev_image_unlock(rbd_dev); rbd_dev_device_release(rbd_dev); rbd_dev_image_release(rbd_dev); - + rbd_dev_destroy(rbd_dev); return count; } diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index cbd62e46bb5b..945aefa4d251 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -177,7 +177,7 @@ /* CLKID_FCLK_DIV4 */ #define CLKID_FCLK_DIV5 7 #define CLKID_FCLK_DIV7 8 -#define CLKID_GP0_PLL 9 +/* CLKID_GP0_PLL */ #define CLKID_MPEG_SEL 10 #define CLKID_MPEG_DIV 11 /* CLKID_CLK81 */ @@ -206,16 +206,16 @@ #define CLKID_I2S_SPDIF 35 /* CLKID_ETH */ #define CLKID_DEMUX 37 -#define CLKID_AIU_GLUE 38 +/* CLKID_AIU_GLUE */ #define CLKID_IEC958 39 -#define CLKID_I2S_OUT 40 +/* CLKID_I2S_OUT */ #define CLKID_AMCLK 41 #define CLKID_AIFIFO2 42 #define CLKID_MIXER 43 -#define CLKID_MIXER_IFACE 44 +/* CLKID_MIXER_IFACE */ #define CLKID_ADC 45 #define CLKID_BLKMV 46 -#define CLKID_AIU 47 +/* CLKID_AIU */ #define CLKID_UART1 48 #define CLKID_G2D 49 /* CLKID_USB0 */ @@ -248,7 +248,7 @@ /* CLKID_GCLK_VENCI_INT0 */ #define CLKID_GCLK_VENCI_INT 78 #define CLKID_DAC_CLK 79 -#define CLKID_AOCLK_GATE 80 +/* CLKID_AOCLK_GATE */ #define CLKID_IEC958_GATE 81 #define CLKID_ENC480P 82 #define CLKID_RNG1 83 @@ -268,8 +268,15 @@ /* CLKID_SAR_ADC_CLK */ /* CLKID_SAR_ADC_SEL */ #define CLKID_SAR_ADC_DIV 99 +/* CLKID_MALI_0_SEL */ +#define CLKID_MALI_0_DIV 101 +/* CLKID_MALI_0 */ +/* CLKID_MALI_1_SEL */ +#define CLKID_MALI_1_DIV 104 +/* CLKID_MALI_1 */ +/* CLKID_MALI */ -#define NR_CLKS 100 +#define NR_CLKS 107 /* include the CLKIDs that have been made part of the stable DT binding */ #include <dt-bindings/clock/gxbb-clkc.h> diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig index a6da2aa09f83..8aa875f25239 100644 --- a/drivers/clk/versatile/Kconfig +++ b/drivers/clk/versatile/Kconfig @@ -1,3 +1,6 @@ +config ICST + bool + config COMMON_CLK_VERSATILE bool "Clock driver for ARM Reference designs" depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \ diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index 8ff03744fe98..794130402c8d 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile @@ -1,5 +1,5 @@ # Makefile for Versatile-specific clocks -obj-$(CONFIG_ICST) += clk-icst.o clk-versatile.o +obj-$(CONFIG_ICST) += icst.o clk-icst.o clk-versatile.o obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o obj-$(CONFIG_CLK_SP810) += clk-sp810.o diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 4faa94440779..09fbe66f1f11 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -22,6 +22,7 @@ #include <linux/regmap.h> #include <linux/mfd/syscon.h> +#include "icst.h" #include "clk-icst.h" /* Magic unlocking token used on all Versatile boards */ diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h index 04e6f0aef588..5add02ebec5d 100644 --- a/drivers/clk/versatile/clk-icst.h +++ b/drivers/clk/versatile/clk-icst.h @@ -1,5 +1,3 @@ -#include <asm/hardware/icst.h> - /** * struct clk_icst_desc - descriptor for the ICST VCO * @params: ICST parameters diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index 74c3216dbb00..401558bfc409 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c @@ -12,6 +12,7 @@ #include <linux/io.h> #include <linux/platform_data/clk-integrator.h> +#include "icst.h" #include "clk-icst.h" #define IMPD1_OSC1 0x00 diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c index c56efc70ac16..6fdfee3232f4 100644 --- a/drivers/clk/versatile/clk-realview.c +++ b/drivers/clk/versatile/clk-realview.c @@ -11,6 +11,7 @@ #include <linux/io.h> #include <linux/clk-provider.h> +#include "icst.h" #include "clk-icst.h" #define REALVIEW_SYS_OSC0_OFFSET 0x0C diff --git a/drivers/clk/versatile/clk-versatile.c b/drivers/clk/versatile/clk-versatile.c index a89a927567e0..d6960de64d4a 100644 --- a/drivers/clk/versatile/clk-versatile.c +++ b/drivers/clk/versatile/clk-versatile.c @@ -12,6 +12,7 @@ #include <linux/of.h> #include <linux/of_address.h> +#include "icst.h" #include "clk-icst.h" #define INTEGRATOR_HDR_LOCK_OFFSET 0x14 diff --git a/arch/arm/common/icst.c b/drivers/clk/versatile/icst.c index d7ed252708c5..de2af63a3aad 100644 --- a/arch/arm/common/icst.c +++ b/drivers/clk/versatile/icst.c @@ -17,7 +17,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <asm/div64.h> -#include <asm/hardware/icst.h> +#include "icst.h" /* * Divisors for each OD setting. diff --git a/arch/arm/include/asm/hardware/icst.h b/drivers/clk/versatile/icst.h index 794220b087d2..7519bba03b04 100644 --- a/arch/arm/include/asm/hardware/icst.h +++ b/drivers/clk/versatile/icst.h @@ -1,6 +1,4 @@ /* - * arch/arm/include/asm/hardware/icst.h - * * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify @@ -11,8 +9,8 @@ * clock generators. See http://www.idt.com/ for more information * on these devices. */ -#ifndef ASMARM_HARDWARE_ICST_H -#define ASMARM_HARDWARE_ICST_H +#ifndef ICST_H +#define ICST_H struct icst_params { unsigned long ref; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 548b90be7685..2706be7ed334 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -111,7 +111,8 @@ void cpuidle_use_deepest_state(bool enable) preempt_disable(); dev = cpuidle_get_device(); - dev->use_deepest_state = enable; + if (dev) + dev->use_deepest_state = enable; preempt_enable(); } diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d01d59812cf3..24e8597b2c3e 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -514,12 +514,12 @@ config TIMB_DMA Enable support for the Timberdale FPGA DMA engine. config TI_CPPI41 - tristate "AM33xx CPPI41 DMA support" - depends on ARCH_OMAP + tristate "CPPI 4.1 DMA support" + depends on (ARCH_OMAP || ARCH_DAVINCI_DA8XX) select DMA_ENGINE help The Communications Port Programming Interface (CPPI) 4.1 DMA engine - is currently used by the USB driver on AM335x platforms. + is currently used by the USB driver on AM335x and DA8xx platforms. config TI_DMA_CROSSBAR bool @@ -608,6 +608,7 @@ config ASYNC_TX_DMA config DMATEST tristate "DMA Test client" depends on DMA_ENGINE + select DMA_ENGINE_RAID help Simple DMA test client. Say N unless you're debugging a DMA Device driver. diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 0b7c6ce629a6..6bb8813ca275 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -106,6 +106,7 @@ struct pl08x_driver_data; /** * struct vendor_data - vendor-specific config parameters for PL08x derivatives + * @config_offset: offset to the configuration register * @channels: the number of channels available in this variant * @signals: the number of request signals available from the hardware * @dualmaster: whether this version supports dual AHB masters or not. @@ -145,6 +146,8 @@ struct pl08x_bus_data { /** * struct pl08x_phy_chan - holder for the physical channels * @id: physical index to this channel + * @base: memory base address for this physical channel + * @reg_config: configuration address for this physical channel * @lock: a lock to use when altering an instance of this struct * @serving: the virtual channel currently being served by this physical * channel @@ -203,7 +206,7 @@ struct pl08x_txd { }; /** - * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel + * enum pl08x_dma_chan_state - holds the PL08x specific virtual channel * states * @PL08X_CHAN_IDLE: the channel is idle * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport @@ -226,9 +229,8 @@ enum pl08x_dma_chan_state { * @phychan: the physical channel utilized by this channel, if there is one * @name: name of channel * @cd: channel platform data - * @runtime_addr: address for RX/TX according to the runtime config + * @cfg: slave configuration * @at: active transaction on this channel - * @lock: a lock for this channel data * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc * @slave: whether this channel is a device (slave) or for memcpy @@ -262,7 +264,7 @@ struct pl08x_dma_chan { * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI * fetches * @mem_buses: set to indicate memory transfers on AHB2. - * @lock: a spinlock for this struct + * @lli_words: how many words are used in each LLI item for this variant */ struct pl08x_driver_data { struct dma_device slave; @@ -417,7 +419,7 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan) /* Enable the DMA channel */ /* Do not access config register until channel shows as disabled */ - while (readl(pl08x->base + PL080_EN_CHAN) & (1 << phychan->id)) + while (readl(pl08x->base + PL080_EN_CHAN) & BIT(phychan->id)) cpu_relax(); /* Do not access config register until channel shows as inactive */ @@ -484,8 +486,8 @@ static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x, writel(val, ch->reg_config); - writel(1 << ch->id, pl08x->base + PL080_ERR_CLEAR); - writel(1 << ch->id, pl08x->base + PL080_TC_CLEAR); + writel(BIT(ch->id), pl08x->base + PL080_ERR_CLEAR); + writel(BIT(ch->id), pl08x->base + PL080_TC_CLEAR); } static inline u32 get_bytes_in_cctl(u32 cctl) @@ -1834,7 +1836,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev) return IRQ_NONE; for (i = 0; i < pl08x->vd->channels; i++) { - if (((1 << i) & err) || ((1 << i) & tc)) { + if ((BIT(i) & err) || (BIT(i) & tc)) { /* Locate physical channel */ struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i]; struct pl08x_dma_chan *plchan = phychan->serving; @@ -1872,7 +1874,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev) } spin_unlock(&plchan->vc.lock); - mask |= (1 << i); + mask |= BIT(i); } } diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index d74cee077842..f7e965f63274 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -68,7 +68,6 @@ #define QMGR_MEMCTRL_IDX_SH 16 #define QMGR_MEMCTRL_DESC_SH 8 -#define QMGR_NUM_PEND 5 #define QMGR_PEND(x) (0x90 + (x) * 4) #define QMGR_PENDING_SLOT_Q(x) (x / 32) @@ -131,7 +130,6 @@ struct cppi41_dd { u32 first_td_desc; struct cppi41_channel *chan_busy[ALLOC_DECS_NUM]; - void __iomem *usbss_mem; void __iomem *ctrl_mem; void __iomem *sched_mem; void __iomem *qmgr_mem; @@ -139,6 +137,10 @@ struct cppi41_dd { const struct chan_queues *queues_rx; const struct chan_queues *queues_tx; struct chan_queues td_queue; + u16 first_completion_queue; + u16 qmgr_num_pend; + u32 n_chans; + u8 platform; struct list_head pending; /* Pending queued transfers */ spinlock_t lock; /* Lock for pending list */ @@ -149,8 +151,7 @@ struct cppi41_dd { bool is_suspended; }; -#define FIST_COMPLETION_QUEUE 93 -static struct chan_queues usb_queues_tx[] = { +static struct chan_queues am335x_usb_queues_tx[] = { /* USB0 ENDP 1 */ [ 0] = { .submit = 32, .complete = 93}, [ 1] = { .submit = 34, .complete = 94}, @@ -186,7 +187,7 @@ static struct chan_queues usb_queues_tx[] = { [29] = { .submit = 90, .complete = 139}, }; -static const struct chan_queues usb_queues_rx[] = { +static const struct chan_queues am335x_usb_queues_rx[] = { /* USB0 ENDP 1 */ [ 0] = { .submit = 1, .complete = 109}, [ 1] = { .submit = 2, .complete = 110}, @@ -222,11 +223,26 @@ static const struct chan_queues usb_queues_rx[] = { [29] = { .submit = 30, .complete = 155}, }; +static const struct chan_queues da8xx_usb_queues_tx[] = { + [0] = { .submit = 16, .complete = 24}, + [1] = { .submit = 18, .complete = 24}, + [2] = { .submit = 20, .complete = 24}, + [3] = { .submit = 22, .complete = 24}, +}; + +static const struct chan_queues da8xx_usb_queues_rx[] = { + [0] = { .submit = 1, .complete = 26}, + [1] = { .submit = 3, .complete = 26}, + [2] = { .submit = 5, .complete = 26}, + [3] = { .submit = 7, .complete = 26}, +}; + struct cppi_glue_infos { - irqreturn_t (*isr)(int irq, void *data); const struct chan_queues *queues_rx; const struct chan_queues *queues_tx; struct chan_queues td_queue; + u16 first_completion_queue; + u16 qmgr_num_pend; }; static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c) @@ -285,19 +301,21 @@ static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num) static irqreturn_t cppi41_irq(int irq, void *data) { struct cppi41_dd *cdd = data; + u16 first_completion_queue = cdd->first_completion_queue; + u16 qmgr_num_pend = cdd->qmgr_num_pend; struct cppi41_channel *c; int i; - for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND; + for (i = QMGR_PENDING_SLOT_Q(first_completion_queue); i < qmgr_num_pend; i++) { u32 val; u32 q_num; val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i)); - if (i == QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE) && val) { + if (i == QMGR_PENDING_SLOT_Q(first_completion_queue) && val) { u32 mask; /* set corresponding bit for completetion Q 93 */ - mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE); + mask = 1 << QMGR_PENDING_BIT_Q(first_completion_queue); /* not set all bits for queues less than Q 93 */ mask--; /* now invert and keep only Q 93+ set */ @@ -402,11 +420,9 @@ static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan, struct cppi41_channel *c = to_cpp41_chan(chan); enum dma_status ret; - /* lock */ ret = dma_cookie_status(chan, cookie, txstate); - if (txstate && ret == DMA_COMPLETE) - txstate->residue = c->residue; - /* unlock */ + + dma_set_residue(txstate, c->residue); return ret; } @@ -630,7 +646,7 @@ static int cppi41_tear_down_chan(struct cppi41_channel *c) if (!c->is_tx) { reg |= GCR_STARV_RETRY; reg |= GCR_DESC_TYPE_HOST; - reg |= c->q_comp_num; + reg |= cdd->td_queue.complete; } reg |= GCR_TEARDOWN; cppi_writel(reg, c->gcr_reg); @@ -641,7 +657,7 @@ static int cppi41_tear_down_chan(struct cppi41_channel *c) if (!c->td_seen || !c->td_desc_seen) { desc_phys = cppi41_pop_desc(cdd, cdd->td_queue.complete); - if (!desc_phys) + if (!desc_phys && c->is_tx) desc_phys = cppi41_pop_desc(cdd, c->q_comp_num); if (desc_phys == c->desc_phys) { @@ -723,39 +739,24 @@ static int cppi41_stop_chan(struct dma_chan *chan) return 0; } -static void cleanup_chans(struct cppi41_dd *cdd) -{ - while (!list_empty(&cdd->ddev.channels)) { - struct cppi41_channel *cchan; - - cchan = list_first_entry(&cdd->ddev.channels, - struct cppi41_channel, chan.device_node); - list_del(&cchan->chan.device_node); - kfree(cchan); - } -} - static int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd) { - struct cppi41_channel *cchan; + struct cppi41_channel *cchan, *chans; int i; - int ret; - u32 n_chans; + u32 n_chans = cdd->n_chans; - ret = of_property_read_u32(dev->of_node, "#dma-channels", - &n_chans); - if (ret) - return ret; /* * The channels can only be used as TX or as RX. So we add twice * that much dma channels because USB can only do RX or TX. */ n_chans *= 2; + chans = devm_kcalloc(dev, n_chans, sizeof(*chans), GFP_KERNEL); + if (!chans) + return -ENOMEM; + for (i = 0; i < n_chans; i++) { - cchan = kzalloc(sizeof(*cchan), GFP_KERNEL); - if (!cchan) - goto err; + cchan = &chans[i]; cchan->cdd = cdd; if (i & 1) { @@ -775,9 +776,6 @@ static int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd) cdd->first_td_desc = n_chans; return 0; -err: - cleanup_chans(cdd); - return -ENOMEM; } static void purge_descs(struct device *dev, struct cppi41_dd *cdd) @@ -859,7 +857,7 @@ static void init_sched(struct cppi41_dd *cdd) word = 0; cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); - for (ch = 0; ch < 15 * 2; ch += 2) { + for (ch = 0; ch < cdd->n_chans; ch += 2) { reg = SCHED_ENTRY0_CHAN(ch); reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX; @@ -869,7 +867,7 @@ static void init_sched(struct cppi41_dd *cdd) cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word)); word++; } - reg = 15 * 2 * 2 - 1; + reg = cdd->n_chans * 2 - 1; reg |= DMA_SCHED_CTRL_EN; cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL); } @@ -885,7 +883,7 @@ static int init_cppi41(struct device *dev, struct cppi41_dd *cdd) return -ENOMEM; cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE); - cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE); + cppi_writel(TOTAL_DESCS_NUM, cdd->qmgr_mem + QMGR_LRAM_SIZE); cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); ret = init_descs(dev, cdd); @@ -894,6 +892,7 @@ static int init_cppi41(struct device *dev, struct cppi41_dd *cdd) cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ); init_sched(cdd); + return 0; err_td: deinit_cppi41(dev, cdd); @@ -933,8 +932,9 @@ static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param) else queues = cdd->queues_rx; - BUILD_BUG_ON(ARRAY_SIZE(usb_queues_rx) != ARRAY_SIZE(usb_queues_tx)); - if (WARN_ON(cchan->port_num > ARRAY_SIZE(usb_queues_rx))) + BUILD_BUG_ON(ARRAY_SIZE(am335x_usb_queues_rx) != + ARRAY_SIZE(am335x_usb_queues_tx)); + if (WARN_ON(cchan->port_num > ARRAY_SIZE(am335x_usb_queues_rx))) return false; cchan->q_num = queues[cchan->port_num].submit; @@ -962,15 +962,25 @@ static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec, &dma_spec->args[0]); } -static const struct cppi_glue_infos usb_infos = { - .isr = cppi41_irq, - .queues_rx = usb_queues_rx, - .queues_tx = usb_queues_tx, +static const struct cppi_glue_infos am335x_usb_infos = { + .queues_rx = am335x_usb_queues_rx, + .queues_tx = am335x_usb_queues_tx, .td_queue = { .submit = 31, .complete = 0 }, + .first_completion_queue = 93, + .qmgr_num_pend = 5, +}; + +static const struct cppi_glue_infos da8xx_usb_infos = { + .queues_rx = da8xx_usb_queues_rx, + .queues_tx = da8xx_usb_queues_tx, + .td_queue = { .submit = 31, .complete = 0 }, + .first_completion_queue = 24, + .qmgr_num_pend = 2, }; static const struct of_device_id cppi41_dma_ids[] = { - { .compatible = "ti,am3359-cppi41", .data = &usb_infos}, + { .compatible = "ti,am3359-cppi41", .data = &am335x_usb_infos}, + { .compatible = "ti,da830-cppi41", .data = &da8xx_usb_infos}, {}, }; MODULE_DEVICE_TABLE(of, cppi41_dma_ids); @@ -995,6 +1005,8 @@ static int cppi41_dma_probe(struct platform_device *pdev) struct cppi41_dd *cdd; struct device *dev = &pdev->dev; const struct cppi_glue_infos *glue_info; + struct resource *mem; + int index; int irq; int ret; @@ -1021,19 +1033,31 @@ static int cppi41_dma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&cdd->ddev.channels); cpp41_dma_info.dma_cap = cdd->ddev.cap_mask; - cdd->usbss_mem = of_iomap(dev->of_node, 0); - cdd->ctrl_mem = of_iomap(dev->of_node, 1); - cdd->sched_mem = of_iomap(dev->of_node, 2); - cdd->qmgr_mem = of_iomap(dev->of_node, 3); + index = of_property_match_string(dev->of_node, + "reg-names", "controller"); + if (index < 0) + return index; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, index); + cdd->ctrl_mem = devm_ioremap_resource(dev, mem); + if (IS_ERR(cdd->ctrl_mem)) + return PTR_ERR(cdd->ctrl_mem); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, index + 1); + cdd->sched_mem = devm_ioremap_resource(dev, mem); + if (IS_ERR(cdd->sched_mem)) + return PTR_ERR(cdd->sched_mem); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, index + 2); + cdd->qmgr_mem = devm_ioremap_resource(dev, mem); + if (IS_ERR(cdd->qmgr_mem)) + return PTR_ERR(cdd->qmgr_mem); + spin_lock_init(&cdd->lock); INIT_LIST_HEAD(&cdd->pending); platform_set_drvdata(pdev, cdd); - if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem || - !cdd->qmgr_mem) - return -ENXIO; - pm_runtime_enable(dev); pm_runtime_set_autosuspend_delay(dev, 100); pm_runtime_use_autosuspend(dev); @@ -1044,6 +1068,13 @@ static int cppi41_dma_probe(struct platform_device *pdev) cdd->queues_rx = glue_info->queues_rx; cdd->queues_tx = glue_info->queues_tx; cdd->td_queue = glue_info->td_queue; + cdd->qmgr_num_pend = glue_info->qmgr_num_pend; + cdd->first_completion_queue = glue_info->first_completion_queue; + + ret = of_property_read_u32(dev->of_node, + "#dma-channels", &cdd->n_chans); + if (ret) + goto err_get_n_chans; ret = init_cppi41(dev, cdd); if (ret) @@ -1056,18 +1087,18 @@ static int cppi41_dma_probe(struct platform_device *pdev) irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) { ret = -EINVAL; - goto err_irq; + goto err_chans; } - ret = devm_request_irq(&pdev->dev, irq, glue_info->isr, IRQF_SHARED, + ret = devm_request_irq(&pdev->dev, irq, cppi41_irq, IRQF_SHARED, dev_name(dev), cdd); if (ret) - goto err_irq; + goto err_chans; cdd->irq = irq; ret = dma_async_device_register(&cdd->ddev); if (ret) - goto err_dma_reg; + goto err_chans; ret = of_dma_controller_register(dev->of_node, cppi41_dma_xlate, &cpp41_dma_info); @@ -1080,20 +1111,14 @@ static int cppi41_dma_probe(struct platform_device *pdev) return 0; err_of: dma_async_device_unregister(&cdd->ddev); -err_dma_reg: -err_irq: - cleanup_chans(cdd); err_chans: deinit_cppi41(dev, cdd); err_init_cppi: pm_runtime_dont_use_autosuspend(dev); +err_get_n_chans: err_get_sync: pm_runtime_put_sync(dev); pm_runtime_disable(dev); - iounmap(cdd->usbss_mem); - iounmap(cdd->ctrl_mem); - iounmap(cdd->sched_mem); - iounmap(cdd->qmgr_mem); return ret; } @@ -1110,12 +1135,7 @@ static int cppi41_dma_remove(struct platform_device *pdev) dma_async_device_unregister(&cdd->ddev); devm_free_irq(&pdev->dev, cdd->irq, cdd); - cleanup_chans(cdd); deinit_cppi41(&pdev->dev, cdd); - iounmap(cdd->usbss_mem); - iounmap(cdd->ctrl_mem); - iounmap(cdd->sched_mem); - iounmap(cdd->qmgr_mem); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 54d581d407aa..a07ef3d6b3ec 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -535,6 +535,13 @@ static int dmatest_func(void *data) total_tests++; + /* Check if buffer count fits into map count variable (u8) */ + if ((src_cnt + dst_cnt) >= 255) { + pr_err("too many buffers (%d of 255 supported)\n", + src_cnt + dst_cnt); + break; + } + if (1 << align > params->buf_size) { pr_err("%u-byte buffer too small for %d-byte alignment\n", params->buf_size, 1 << align); @@ -585,7 +592,7 @@ static int dmatest_func(void *data) for (i = 0; i < src_cnt; i++) { void *buf = thread->srcs[i]; struct page *pg = virt_to_page(buf); - unsigned pg_off = (unsigned long) buf & ~PAGE_MASK; + unsigned long pg_off = offset_in_page(buf); um->addr[i] = dma_map_page(dev->dev, pg, pg_off, um->len, DMA_TO_DEVICE); @@ -605,7 +612,7 @@ static int dmatest_func(void *data) for (i = 0; i < dst_cnt; i++) { void *buf = thread->dsts[i]; struct page *pg = virt_to_page(buf); - unsigned pg_off = (unsigned long) buf & ~PAGE_MASK; + unsigned long pg_off = offset_in_page(buf); dsts[i] = dma_map_page(dev->dev, pg, pg_off, um->len, DMA_BIDIRECTIONAL); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index d1651a50c349..085993cb2ccc 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -937,6 +937,21 @@ static int sdma_disable_channel(struct dma_chan *chan) return 0; } +static int sdma_disable_channel_with_delay(struct dma_chan *chan) +{ + sdma_disable_channel(chan); + + /* + * According to NXP R&D team a delay of one BD SDMA cost time + * (maximum is 1ms) should be added after disable of the channel + * bit, to ensure SDMA core has really been stopped after SDMA + * clients call .device_terminate_all. + */ + mdelay(1); + + return 0; +} + static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) { struct sdma_engine *sdma = sdmac->sdma; @@ -1828,11 +1843,11 @@ static int sdma_probe(struct platform_device *pdev) sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg; sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; sdma->dma_device.device_config = sdma_config; - sdma->dma_device.device_terminate_all = sdma_disable_channel; + sdma->dma_device.device_terminate_all = sdma_disable_channel_with_delay; sdma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); sdma->dma_device.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); sdma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; sdma->dma_device.device_issue_pending = sdma_issue_pending; sdma->dma_device.dev->dma_parms = &sdma->dma_parms; dma_set_max_seg_size(sdma->dma_device.dev, 65535); diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index cc5259b881d4..6ad4384b3fa8 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -760,9 +760,7 @@ ioat_init_channel(struct ioatdma_device *ioat_dma, dma_cookie_init(&ioat_chan->dma_chan); list_add_tail(&ioat_chan->dma_chan.device_node, &dma->channels); ioat_dma->idx[idx] = ioat_chan; - init_timer(&ioat_chan->timer); - ioat_chan->timer.function = ioat_timer_event; - ioat_chan->timer.data = data; + setup_timer(&ioat_chan->timer, ioat_timer_event, data); tasklet_init(&ioat_chan->cleanup_task, ioat_cleanup_event, data); } diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 0cb951b743a6..25bc5b103aa2 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -960,7 +960,7 @@ static int mv_chan_memcpy_self_test(struct mv_xor_chan *mv_chan) } src_dma = dma_map_page(dma_chan->device->dev, virt_to_page(src), - (size_t)src & ~PAGE_MASK, PAGE_SIZE, + offset_in_page(src), PAGE_SIZE, DMA_TO_DEVICE); unmap->addr[0] = src_dma; @@ -972,7 +972,7 @@ static int mv_chan_memcpy_self_test(struct mv_xor_chan *mv_chan) unmap->to_cnt = 1; dest_dma = dma_map_page(dma_chan->device->dev, virt_to_page(dest), - (size_t)dest & ~PAGE_MASK, PAGE_SIZE, + offset_in_page(dest), PAGE_SIZE, DMA_FROM_DEVICE); unmap->addr[1] = dest_dma; @@ -1580,11 +1580,6 @@ static int mv_xor_probe(struct platform_device *pdev) int irq; cd = &pdata->channels[i]; - if (!cd) { - ret = -ENODEV; - goto err_channel_add; - } - irq = platform_get_irq(pdev, i); if (irq < 0) { ret = irq; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index f37f4978dabb..8b0da7fa520d 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -22,7 +22,6 @@ #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/amba/bus.h> -#include <linux/amba/pl330.h> #include <linux/scatterlist.h> #include <linux/of.h> #include <linux/of_dma.h> @@ -2077,18 +2076,6 @@ static void pl330_tasklet(unsigned long data) } } -bool pl330_filter(struct dma_chan *chan, void *param) -{ - u8 *peri_id; - - if (chan->device->dev->driver != &pl330_driver.drv) - return false; - - peri_id = chan->private; - return *peri_id == (unsigned long)param; -} -EXPORT_SYMBOL(pl330_filter); - static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { @@ -2833,7 +2820,6 @@ static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume); static int pl330_probe(struct amba_device *adev, const struct amba_id *id) { - struct dma_pl330_platdata *pdat; struct pl330_config *pcfg; struct pl330_dmac *pl330; struct dma_pl330_chan *pch, *_p; @@ -2843,8 +2829,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) int num_chan; struct device_node *np = adev->dev.of_node; - pdat = dev_get_platdata(&adev->dev); - ret = dma_set_mask_and_coherent(&adev->dev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -2857,7 +2841,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pd = &pl330->ddma; pd->dev = &adev->dev; - pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0; + pl330->mcbufsz = 0; /* get quirk */ for (i = 0; i < ARRAY_SIZE(of_quirks); i++) @@ -2901,10 +2885,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) INIT_LIST_HEAD(&pd->channels); /* Initialize channel parameters */ - if (pdat) - num_chan = max_t(int, pdat->nr_valid_peri, pcfg->num_chan); - else - num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan); + num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan); pl330->num_peripherals = num_chan; @@ -2916,11 +2897,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) for (i = 0; i < num_chan; i++) { pch = &pl330->peripherals[i]; - if (!adev->dev.of_node) - pch->chan.private = pdat ? &pdat->peri_id[i] : NULL; - else - pch->chan.private = adev->dev.of_node; + pch->chan.private = adev->dev.of_node; INIT_LIST_HEAD(&pch->submitted_list); INIT_LIST_HEAD(&pch->work_list); INIT_LIST_HEAD(&pch->completed_list); @@ -2933,15 +2911,11 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) list_add_tail(&pch->chan.device_node, &pd->channels); } - if (pdat) { - pd->cap_mask = pdat->cap_mask; - } else { - dma_cap_set(DMA_MEMCPY, pd->cap_mask); - if (pcfg->num_peri) { - dma_cap_set(DMA_SLAVE, pd->cap_mask); - dma_cap_set(DMA_CYCLIC, pd->cap_mask); - dma_cap_set(DMA_PRIVATE, pd->cap_mask); - } + dma_cap_set(DMA_MEMCPY, pd->cap_mask); + if (pcfg->num_peri) { + dma_cap_set(DMA_SLAVE, pd->cap_mask); + dma_cap_set(DMA_CYCLIC, pd->cap_mask); + dma_cap_set(DMA_PRIVATE, pd->cap_mask); } pd->device_alloc_chan_resources = pl330_alloc_chan_resources; diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 3c982c96b4b7..5072a7d306d4 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -865,6 +865,20 @@ bailout: return rc; } +static void hidma_shutdown(struct platform_device *pdev) +{ + struct hidma_dev *dmadev = platform_get_drvdata(pdev); + + dev_info(dmadev->ddev.dev, "HI-DMA engine shutdown\n"); + + pm_runtime_get_sync(dmadev->ddev.dev); + if (hidma_ll_disable(dmadev->lldev)) + dev_warn(dmadev->ddev.dev, "channel did not stop\n"); + pm_runtime_mark_last_busy(dmadev->ddev.dev); + pm_runtime_put_autosuspend(dmadev->ddev.dev); + +} + static int hidma_remove(struct platform_device *pdev) { struct hidma_dev *dmadev = platform_get_drvdata(pdev); @@ -908,6 +922,7 @@ MODULE_DEVICE_TABLE(of, hidma_match); static struct platform_driver hidma_driver = { .probe = hidma_probe, .remove = hidma_remove, + .shutdown = hidma_shutdown, .driver = { .name = "hidma", .of_match_table = hidma_match, diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 6645bdf0d151..1530a661518d 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -499,6 +499,9 @@ int hidma_ll_enable(struct hidma_lldev *lldev) lldev->trch_state = HIDMA_CH_ENABLED; lldev->evch_state = HIDMA_CH_ENABLED; + /* enable irqs */ + writel(ENABLE_IRQS, lldev->evca + HIDMA_EVCA_IRQ_EN_REG); + return 0; } @@ -596,6 +599,9 @@ int hidma_ll_disable(struct hidma_lldev *lldev) lldev->trch_state = HIDMA_CH_SUSPENDED; lldev->evch_state = HIDMA_CH_SUSPENDED; + + /* disable interrupts */ + writel(0, lldev->evca + HIDMA_EVCA_IRQ_EN_REG); return 0; } diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 48b22d5c8602..db41795fe42a 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -344,13 +344,19 @@ static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan) rcar_dmac_chan_write(chan, RCAR_DMARS, chan->mid_rid); if (desc->hwdescs.use) { - struct rcar_dmac_xfer_chunk *chunk; + struct rcar_dmac_xfer_chunk *chunk = + list_first_entry(&desc->chunks, + struct rcar_dmac_xfer_chunk, node); dev_dbg(chan->chan.device->dev, "chan%u: queue desc %p: %u@%pad\n", chan->index, desc, desc->nchunks, &desc->hwdescs.dma); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + rcar_dmac_chan_write(chan, RCAR_DMAFIXSAR, + chunk->src_addr >> 32); + rcar_dmac_chan_write(chan, RCAR_DMAFIXDAR, + chunk->dst_addr >> 32); rcar_dmac_chan_write(chan, RCAR_DMAFIXDPBASE, desc->hwdescs.dma >> 32); #endif @@ -368,8 +374,6 @@ static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan) * should. Initialize it manually with the destination address * of the first chunk. */ - chunk = list_first_entry(&desc->chunks, - struct rcar_dmac_xfer_chunk, node); rcar_dmac_chan_write(chan, RCAR_DMADAR, chunk->dst_addr & 0xffffffff); @@ -855,8 +859,12 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, unsigned int nchunks = 0; unsigned int max_chunk_size; unsigned int full_size = 0; - bool highmem = false; + bool cross_boundary = false; unsigned int i; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + u32 high_dev_addr; + u32 high_mem_addr; +#endif desc = rcar_dmac_desc_get(chan); if (!desc) @@ -882,6 +890,16 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, full_size += len; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (i == 0) { + high_dev_addr = dev_addr >> 32; + high_mem_addr = mem_addr >> 32; + } + + if ((dev_addr >> 32 != high_dev_addr) || + (mem_addr >> 32 != high_mem_addr)) + cross_boundary = true; +#endif while (len) { unsigned int size = min(len, max_chunk_size); @@ -890,18 +908,14 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, * Prevent individual transfers from crossing 4GB * boundaries. */ - if (dev_addr >> 32 != (dev_addr + size - 1) >> 32) + if (dev_addr >> 32 != (dev_addr + size - 1) >> 32) { size = ALIGN(dev_addr, 1ULL << 32) - dev_addr; - if (mem_addr >> 32 != (mem_addr + size - 1) >> 32) + cross_boundary = true; + } + if (mem_addr >> 32 != (mem_addr + size - 1) >> 32) { size = ALIGN(mem_addr, 1ULL << 32) - mem_addr; - - /* - * Check if either of the source or destination address - * can't be expressed in 32 bits. If so we can't use - * hardware descriptor lists. - */ - if (dev_addr >> 32 || mem_addr >> 32) - highmem = true; + cross_boundary = true; + } #endif chunk = rcar_dmac_xfer_chunk_get(chan); @@ -943,13 +957,11 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, * Use hardware descriptor lists if possible when more than one chunk * needs to be transferred (otherwise they don't make much sense). * - * The highmem check currently covers the whole transfer. As an - * optimization we could use descriptor lists for consecutive lowmem - * chunks and direct manual mode for highmem chunks. Whether the - * performance improvement would be significant enough compared to the - * additional complexity remains to be investigated. + * Source/Destination address should be located in same 4GiB region + * in the 40bit address space when it uses Hardware descriptor, + * and cross_boundary is checking it. */ - desc->hwdescs.use = !highmem && nchunks > 1; + desc->hwdescs.use = !cross_boundary && nchunks > 1; if (desc->hwdescs.use) { if (rcar_dmac_fill_hwdesc(chan, desc) < 0) desc->hwdescs.use = false; diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 49f86cabcfec..786fc8fcc38e 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -1008,7 +1008,7 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, c = dma_get_slave_channel(&chan->vchan.chan); if (!c) { - dev_err(dev, "No more channel avalaible\n"); + dev_err(dev, "No more channels available\n"); return NULL; } diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c index 57aa227bfadb..f4ed3f17607c 100644 --- a/drivers/dma/sun4i-dma.c +++ b/drivers/dma/sun4i-dma.c @@ -238,7 +238,7 @@ static struct sun4i_dma_pchan *find_and_use_pchan(struct sun4i_dma_dev *priv, } spin_lock_irqsave(&priv->lock, flags); - for_each_clear_bit_from(i, &priv->pchans_used, max) { + for_each_clear_bit_from(i, priv->pchans_used, max) { pchan = &pchans[i]; pchan->vchan = vchan; set_bit(i, priv->pchans_used); diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c index e47fc9b0944f..545e97279083 100644 --- a/drivers/dma/virt-dma.c +++ b/drivers/dma/virt-dma.c @@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(vchan_find_desc); static void vchan_complete(unsigned long arg) { struct virt_dma_chan *vc = (struct virt_dma_chan *)arg; - struct virt_dma_desc *vd; + struct virt_dma_desc *vd, *_vd; struct dmaengine_desc_callback cb; LIST_HEAD(head); @@ -103,8 +103,7 @@ static void vchan_complete(unsigned long arg) dmaengine_desc_callback_invoke(&cb, NULL); - while (!list_empty(&head)) { - vd = list_first_entry(&head, struct virt_dma_desc, node); + list_for_each_entry_safe(vd, _vd, &head, node) { dmaengine_desc_get_callback(&vd->tx, &cb); list_del(&vd->node); @@ -119,9 +118,9 @@ static void vchan_complete(unsigned long arg) void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head) { - while (!list_empty(head)) { - struct virt_dma_desc *vd = list_first_entry(head, - struct virt_dma_desc, node); + struct virt_dma_desc *vd, *_vd; + + list_for_each_entry_safe(vd, _vd, head, node) { if (dmaengine_desc_test_reuse(&vd->tx)) { list_move_tail(&vd->node, &vc->desc_allocated); } else { diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 8288fe4d17c3..8cf87b1a284b 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -331,6 +331,7 @@ struct xilinx_dma_tx_descriptor { * @seg_v: Statically allocated segments base * @cyclic_seg_v: Statically allocated segment base for cyclic transfers * @start_transfer: Differentiate b/w DMA IP's transfer + * @stop_transfer: Differentiate b/w DMA IP's quiesce */ struct xilinx_dma_chan { struct xilinx_dma_device *xdev; @@ -361,6 +362,7 @@ struct xilinx_dma_chan { struct xilinx_axidma_tx_segment *seg_v; struct xilinx_axidma_tx_segment *cyclic_seg_v; void (*start_transfer)(struct xilinx_dma_chan *chan); + int (*stop_transfer)(struct xilinx_dma_chan *chan); u16 tdest; }; @@ -946,26 +948,32 @@ static bool xilinx_dma_is_idle(struct xilinx_dma_chan *chan) } /** - * xilinx_dma_halt - Halt DMA channel + * xilinx_dma_stop_transfer - Halt DMA channel * @chan: Driver specific DMA channel */ -static void xilinx_dma_halt(struct xilinx_dma_chan *chan) +static int xilinx_dma_stop_transfer(struct xilinx_dma_chan *chan) { - int err; u32 val; dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP); /* Wait for the hardware to halt */ - err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val, - (val & XILINX_DMA_DMASR_HALTED), 0, - XILINX_DMA_LOOP_COUNT); + return xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val, + val & XILINX_DMA_DMASR_HALTED, 0, + XILINX_DMA_LOOP_COUNT); +} - if (err) { - dev_err(chan->dev, "Cannot stop channel %p: %x\n", - chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR)); - chan->err = true; - } +/** + * xilinx_cdma_stop_transfer - Wait for the current transfer to complete + * @chan: Driver specific DMA channel + */ +static int xilinx_cdma_stop_transfer(struct xilinx_dma_chan *chan) +{ + u32 val; + + return xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val, + val & XILINX_DMA_DMASR_IDLE, 0, + XILINX_DMA_LOOP_COUNT); } /** @@ -1653,7 +1661,7 @@ xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst, { struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); struct xilinx_dma_tx_descriptor *desc; - struct xilinx_cdma_tx_segment *segment, *prev; + struct xilinx_cdma_tx_segment *segment; struct xilinx_cdma_desc_hw *hw; if (!len || len > XILINX_DMA_MAX_TRANS_LEN) @@ -1680,21 +1688,11 @@ xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst, hw->dest_addr_msb = upper_32_bits(dma_dst); } - /* Fill the previous next descriptor with current */ - prev = list_last_entry(&desc->segments, - struct xilinx_cdma_tx_segment, node); - prev->hw.next_desc = segment->phys; - /* Insert the segment into the descriptor segments list. */ list_add_tail(&segment->node, &desc->segments); - prev = segment; - - /* Link the last hardware descriptor with the first. */ - segment = list_first_entry(&desc->segments, - struct xilinx_cdma_tx_segment, node); desc->async_tx.phys = segment->phys; - prev->hw.next_desc = segment->phys; + hw->next_desc = segment->phys; return &desc->async_tx; @@ -2003,12 +2001,17 @@ static int xilinx_dma_terminate_all(struct dma_chan *dchan) { struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); u32 reg; + int err; if (chan->cyclic) xilinx_dma_chan_reset(chan); - /* Halt the DMA engine */ - xilinx_dma_halt(chan); + err = chan->stop_transfer(chan); + if (err) { + dev_err(chan->dev, "Cannot stop channel %p: %x\n", + chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR)); + chan->err = true; + } /* Remove and free all of the descriptors in the lists */ xilinx_dma_free_descriptors(chan); @@ -2397,12 +2400,16 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, return err; } - if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) + if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { chan->start_transfer = xilinx_dma_start_transfer; - else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) + chan->stop_transfer = xilinx_dma_stop_transfer; + } else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) { chan->start_transfer = xilinx_cdma_start_transfer; - else + chan->stop_transfer = xilinx_cdma_stop_transfer; + } else { chan->start_transfer = xilinx_vdma_start_transfer; + chan->stop_transfer = xilinx_dma_stop_transfer; + } /* Initialize the tasklet */ tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet, diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 9ad0b1934be9..f6cfc31d34c7 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -538,7 +538,7 @@ static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len, msg->tx_len = tx_len; msg->rx_buf = rx_buf; msg->rx_len = rx_len; - init_completion(&msg->done); + reinit_completion(&msg->done); ret = mbox_send_message(scpi_chan->chan, msg); if (ret < 0 || !rx_buf) @@ -872,8 +872,11 @@ static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch) return -ENOMEM; ch->xfers = xfers; - for (i = 0; i < MAX_SCPI_XFERS; i++, xfers++) + for (i = 0; i < MAX_SCPI_XFERS; i++, xfers++) { + init_completion(&xfers->done); list_add_tail(&xfers->node, &ch->xfers_list); + } + return 0; } diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index b0d254930ed3..ff204421117b 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -127,6 +127,7 @@ EXPORT_SYMBOL(meson_sm_call); * meson_sm_call_read - retrieve data from secure-monitor * * @buffer: Buffer to store the retrieved data + * @bsize: Size of the buffer * @cmd_index: Index of the SMC32 function ID * @arg0: SMC32 Argument 0 * @arg1: SMC32 Argument 1 @@ -135,11 +136,14 @@ EXPORT_SYMBOL(meson_sm_call); * @arg4: SMC32 Argument 4 * * Return: size of read data on success, a negative value on error + * When 0 is returned there is no guarantee about the amount of + * data read and bsize bytes are copied in buffer. */ -int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0, - u32 arg1, u32 arg2, u32 arg3, u32 arg4) +int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index, + u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { u32 size; + int ret; if (!fw.chip) return -ENOENT; @@ -147,16 +151,24 @@ int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0, if (!fw.chip->cmd_shmem_out_base) return -EINVAL; + if (bsize > fw.chip->shmem_size) + return -EINVAL; + if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) return -EINVAL; - if (!size || size > fw.chip->shmem_size) + if (size > bsize) return -EINVAL; + ret = size; + + if (!size) + size = bsize; + if (buffer) memcpy(buffer, fw.sm_shmem_out_base, size); - return size; + return ret; } EXPORT_SYMBOL(meson_sm_call_read); diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 8ad226c60374..93e3b96b6dfa 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -578,3 +578,21 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) return ret ? : le32_to_cpu(scm_ret); } + +int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, + u32 spare) +{ + return -ENODEV; +} + +int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, + size_t *size) +{ + return -ENODEV; +} + +int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, + u32 spare) +{ + return -ENODEV; +} diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index c9332590e8c6..6e6d561708e2 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -381,3 +381,61 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) return ret ? : res.a1; } + +int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = device_id; + desc.args[1] = spare; + desc.arginfo = QCOM_SCM_ARGS(2); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG, + &desc, &res); + + return ret ? : res.a1; +} + +int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, + size_t *size) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = spare; + desc.arginfo = QCOM_SCM_ARGS(1); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, + QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, &desc, &res); + + if (size) + *size = res.a1; + + return ret ? : res.a2; +} + +int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, + u32 spare) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = addr; + desc.args[1] = size; + desc.args[2] = spare; + desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, + QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, + QCOM_SCM_IOMMU_SECURE_PTBL_INIT, &desc, &res); + + /* the pg table has been initialized already, ignore the error */ + if (ret == -EPERM) + ret = 0; + + return ret; +} diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d987bcc7489d..bb16510d75ba 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -315,6 +315,24 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = { .deassert = qcom_scm_pas_reset_deassert, }; +int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) +{ + return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare); +} +EXPORT_SYMBOL(qcom_scm_restore_sec_cfg); + +int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) +{ + return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size); +} +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size); + +int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) +{ + return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare); +} +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init); + /** * qcom_scm_is_available() - Checks if SCM is available */ diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 6a0f15469344..9bea691f30fb 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -85,4 +85,15 @@ static inline int qcom_scm_remap_error(int err) return -EINVAL; } +#define QCOM_SCM_SVC_MP 0xc +#define QCOM_SCM_RESTORE_SEC_CFG 2 +extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, + u32 spare); +#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3 +#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4 +extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, + size_t *size); +extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, + u32 size, u32 spare); + #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 532a577ff7a1..b6ac3df18b58 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4789,7 +4789,7 @@ i915_gem_load_init(struct drm_i915_private *dev_priv) dev_priv->requests = KMEM_CACHE(drm_i915_gem_request, SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | - SLAB_DESTROY_BY_RCU); + SLAB_TYPESAFE_BY_RCU); if (!dev_priv->requests) goto err_vmas; diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h index a211c53c813f..129c58bb4805 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.h +++ b/drivers/gpu/drm/i915/i915_gem_request.h @@ -521,7 +521,7 @@ static inline struct drm_i915_gem_request * __i915_gem_active_get_rcu(const struct i915_gem_active *active) { /* Performing a lockless retrieval of the active request is super - * tricky. SLAB_DESTROY_BY_RCU merely guarantees that the backing + * tricky. SLAB_TYPESAFE_BY_RCU merely guarantees that the backing * slab of request objects will not be freed whilst we hold the * RCU read lock. It does not guarantee that the request itself * will not be freed and then *reused*. Viz, diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 6a8258eacdcb..9f24c5da3f8d 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -174,7 +174,7 @@ struct drm_i915_private *mock_gem_device(void) i915->requests = KMEM_CACHE(mock_request, SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | - SLAB_DESTROY_BY_RCU); + SLAB_TYPESAFE_BY_RCU); if (!i915->requests) goto err_vmas; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 5a4eb6b6bd92..f2acd4b6bf01 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -157,6 +157,8 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "AMDI0010", ACCESS_INTR_MASK }, { "AMDI0510", 0 }, { "APMC0D0F", 0 }, + { "HISI02A1", 0 }, + { "HISI02A2", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 45b3f41a43d4..323af721f8cb 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -107,7 +107,7 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) if (cmd->tf_flags & IDE_TFLAG_DYN) kfree(orig_cmd); - else + else if (cmd != orig_cmd) memcpy(orig_cmd, cmd, sizeof(*cmd)); } } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index a74ae8df4bb8..023562565d11 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1183,9 +1183,7 @@ static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) spin_lock_init(&hwif->lock); - init_timer(&hwif->timer); - hwif->timer.function = &ide_timer_expiry; - hwif->timer.data = (unsigned long)hwif; + setup_timer(&hwif->timer, &ide_timer_expiry, (unsigned long)hwif); init_completion(&hwif->gendev_rel_comp); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 5805b041dd0f..216d7ec88c0c 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -1097,6 +1097,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = { ICPU(INTEL_FAM6_XEON_PHI_KNL, idle_cpu_knl), ICPU(INTEL_FAM6_XEON_PHI_KNM, idle_cpu_knl), ICPU(INTEL_FAM6_ATOM_GOLDMONT, idle_cpu_bxt), + ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, idle_cpu_bxt), ICPU(INTEL_FAM6_ATOM_DENVERTON, idle_cpu_dnv), {} }; @@ -1309,6 +1310,7 @@ static void intel_idle_state_table_update(void) ivt_idle_state_table_update(); break; case INTEL_FAM6_ATOM_GOLDMONT: + case INTEL_FAM6_ATOM_GEMINI_LAKE: bxt_idle_state_table_update(); break; case INTEL_FAM6_SKYLAKE_DESKTOP: diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index ef11e770f822..6a72095d6c7a 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -35,6 +35,7 @@ #include <rdma/ib_user_verbs.h> #include <linux/netdevice.h> #include <linux/iommu.h> +#include <linux/pci.h> #include <net/addrconf.h> #include <linux/qed/qede_roce.h> #include <linux/qed/qed_chain.h> diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index f1e66efea98a..1d940a2885c9 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -512,7 +512,7 @@ static int qibfs_fill_super(struct super_block *sb, void *data, int silent) unsigned long flags; int ret; - static struct tree_descr files[] = { + static const struct tree_descr files[] = { [2] = {"driver_stats", &driver_ops[0], S_IRUGO}, [3] = {"driver_stats_names", &driver_ops[1], S_IRUGO}, {""}, diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index 063343909b0d..6629c472eafd 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -696,9 +696,9 @@ out_clear_state: out_unregister: mmu_notifier_unregister(&pasid_state->mn, mm); + mmput(mm); out_free: - mmput(mm); free_pasid_state(pasid_state); out: diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 591bb96047c9..380969aa60d5 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -554,9 +554,14 @@ struct arm_smmu_s2_cfg { }; struct arm_smmu_strtab_ent { - bool valid; - - bool bypass; /* Overrides s1/s2 config */ + /* + * An STE is "assigned" if the master emitting the corresponding SID + * is attached to a domain. The behaviour of an unassigned STE is + * determined by the disable_bypass parameter, whereas an assigned + * STE behaves according to s1_cfg/s2_cfg, which themselves are + * configured according to the domain type. + */ + bool assigned; struct arm_smmu_s1_cfg *s1_cfg; struct arm_smmu_s2_cfg *s2_cfg; }; @@ -632,6 +637,7 @@ enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_S1 = 0, ARM_SMMU_DOMAIN_S2, ARM_SMMU_DOMAIN_NESTED, + ARM_SMMU_DOMAIN_BYPASS, }; struct arm_smmu_domain { @@ -1005,9 +1011,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, * This is hideously complicated, but we only really care about * three cases at the moment: * - * 1. Invalid (all zero) -> bypass (init) - * 2. Bypass -> translation (attach) - * 3. Translation -> bypass (detach) + * 1. Invalid (all zero) -> bypass/fault (init) + * 2. Bypass/fault -> translation/bypass (attach) + * 3. Translation/bypass -> bypass/fault (detach) * * Given that we can't update the STE atomically and the SMMU * doesn't read the thing in a defined order, that leaves us @@ -1046,11 +1052,15 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, } /* Nuke the existing STE_0 value, as we're going to rewrite it */ - val = ste->valid ? STRTAB_STE_0_V : 0; + val = STRTAB_STE_0_V; + + /* Bypass/fault */ + if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) { + if (!ste->assigned && disable_bypass) + val |= STRTAB_STE_0_CFG_ABORT; + else + val |= STRTAB_STE_0_CFG_BYPASS; - if (ste->bypass) { - val |= disable_bypass ? STRTAB_STE_0_CFG_ABORT - : STRTAB_STE_0_CFG_BYPASS; dst[0] = cpu_to_le64(val); dst[1] = cpu_to_le64(STRTAB_STE_1_SHCFG_INCOMING << STRTAB_STE_1_SHCFG_SHIFT); @@ -1111,10 +1121,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent) { unsigned int i; - struct arm_smmu_strtab_ent ste = { - .valid = true, - .bypass = true, - }; + struct arm_smmu_strtab_ent ste = { .assigned = false }; for (i = 0; i < nent; ++i) { arm_smmu_write_strtab_ent(NULL, -1, strtab, &ste); @@ -1378,7 +1385,9 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) { struct arm_smmu_domain *smmu_domain; - if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) + if (type != IOMMU_DOMAIN_UNMANAGED && + type != IOMMU_DOMAIN_DMA && + type != IOMMU_DOMAIN_IDENTITY) return NULL; /* @@ -1509,6 +1518,11 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; + if (domain->type == IOMMU_DOMAIN_IDENTITY) { + smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS; + return 0; + } + /* Restrict the stage to what we can actually support */ if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1)) smmu_domain->stage = ARM_SMMU_DOMAIN_S2; @@ -1579,7 +1593,7 @@ static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid) return step; } -static int arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec) +static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec) { int i; struct arm_smmu_master_data *master = fwspec->iommu_priv; @@ -1591,17 +1605,14 @@ static int arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec) arm_smmu_write_strtab_ent(smmu, sid, step, &master->ste); } - - return 0; } static void arm_smmu_detach_dev(struct device *dev) { struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv; - master->ste.bypass = true; - if (arm_smmu_install_ste_for_dev(dev->iommu_fwspec) < 0) - dev_warn(dev, "failed to install bypass STE\n"); + master->ste.assigned = false; + arm_smmu_install_ste_for_dev(dev->iommu_fwspec); } static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) @@ -1620,7 +1631,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) ste = &master->ste; /* Already attached to a different domain? */ - if (!ste->bypass) + if (ste->assigned) arm_smmu_detach_dev(dev); mutex_lock(&smmu_domain->init_mutex); @@ -1641,10 +1652,12 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) goto out_unlock; } - ste->bypass = false; - ste->valid = true; + ste->assigned = true; - if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { + if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS) { + ste->s1_cfg = NULL; + ste->s2_cfg = NULL; + } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { ste->s1_cfg = &smmu_domain->s1_cfg; ste->s2_cfg = NULL; arm_smmu_write_ctx_desc(smmu, ste->s1_cfg); @@ -1653,10 +1666,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) ste->s2_cfg = &smmu_domain->s2_cfg; } - ret = arm_smmu_install_ste_for_dev(dev->iommu_fwspec); - if (ret < 0) - ste->valid = false; - + arm_smmu_install_ste_for_dev(dev->iommu_fwspec); out_unlock: mutex_unlock(&smmu_domain->init_mutex); return ret; @@ -1704,6 +1714,9 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; + if (domain->type == IOMMU_DOMAIN_IDENTITY) + return iova; + if (!ops) return 0; @@ -1807,7 +1820,7 @@ static void arm_smmu_remove_device(struct device *dev) master = fwspec->iommu_priv; smmu = master->smmu; - if (master && master->ste.valid) + if (master && master->ste.assigned) arm_smmu_detach_dev(dev); iommu_group_remove_device(dev); iommu_device_unlink(&smmu->iommu, dev); @@ -1837,6 +1850,9 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + if (domain->type != IOMMU_DOMAIN_UNMANAGED) + return -EINVAL; + switch (attr) { case DOMAIN_ATTR_NESTING: *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); @@ -1852,6 +1868,9 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, int ret = 0; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + if (domain->type != IOMMU_DOMAIN_UNMANAGED) + return -EINVAL; + mutex_lock(&smmu_domain->init_mutex); switch (attr) { @@ -1893,6 +1912,8 @@ static void arm_smmu_get_resv_regions(struct device *dev, return; list_add_tail(®ion->list, head); + + iommu_dma_get_resv_regions(dev, head); } static void arm_smmu_put_resv_regions(struct device *dev, @@ -2761,51 +2782,9 @@ static struct platform_driver arm_smmu_driver = { .probe = arm_smmu_device_probe, .remove = arm_smmu_device_remove, }; +module_platform_driver(arm_smmu_driver); -static int __init arm_smmu_init(void) -{ - static bool registered; - int ret = 0; - - if (!registered) { - ret = platform_driver_register(&arm_smmu_driver); - registered = !ret; - } - return ret; -} - -static void __exit arm_smmu_exit(void) -{ - return platform_driver_unregister(&arm_smmu_driver); -} - -subsys_initcall(arm_smmu_init); -module_exit(arm_smmu_exit); - -static int __init arm_smmu_of_init(struct device_node *np) -{ - int ret = arm_smmu_init(); - - if (ret) - return ret; - - if (!of_platform_device_create(np, NULL, platform_bus_type.dev_root)) - return -ENODEV; - - return 0; -} -IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init); - -#ifdef CONFIG_ACPI -static int __init acpi_smmu_v3_init(struct acpi_table_header *table) -{ - if (iort_node_match(ACPI_IORT_NODE_SMMU_V3)) - return arm_smmu_init(); - - return 0; -} -IORT_ACPI_DECLARE(arm_smmu_v3, ACPI_SIG_IORT, acpi_smmu_v3_init); -#endif +IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", NULL); MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations"); MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>"); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index b493c99e17f7..7ec30b08b3bd 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -162,6 +162,7 @@ #define ARM_SMMU_GR0_sTLBGSTATUS 0x74 #define sTLBGSTATUS_GSACTIVE (1 << 0) #define TLB_LOOP_TIMEOUT 1000000 /* 1s! */ +#define TLB_SPIN_COUNT 10 /* Stream mapping registers */ #define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2)) @@ -216,8 +217,7 @@ enum arm_smmu_s2cr_privcfg { #define CBA2R_VMID_MASK 0xffff /* Translation context bank */ -#define ARM_SMMU_CB_BASE(smmu) ((smmu)->base + ((smmu)->size >> 1)) -#define ARM_SMMU_CB(smmu, n) ((n) * (1 << (smmu)->pgshift)) +#define ARM_SMMU_CB(smmu, n) ((smmu)->cb_base + ((n) << (smmu)->pgshift)) #define ARM_SMMU_CB_SCTLR 0x0 #define ARM_SMMU_CB_ACTLR 0x4 @@ -238,6 +238,8 @@ enum arm_smmu_s2cr_privcfg { #define ARM_SMMU_CB_S1_TLBIVAL 0x620 #define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 #define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 +#define ARM_SMMU_CB_TLBSYNC 0x7f0 +#define ARM_SMMU_CB_TLBSTATUS 0x7f4 #define ARM_SMMU_CB_ATS1PR 0x800 #define ARM_SMMU_CB_ATSR 0x8f0 @@ -344,7 +346,7 @@ struct arm_smmu_device { struct device *dev; void __iomem *base; - unsigned long size; + void __iomem *cb_base; unsigned long pgshift; #define ARM_SMMU_FEAT_COHERENT_WALK (1 << 0) @@ -404,18 +406,20 @@ enum arm_smmu_context_fmt { struct arm_smmu_cfg { u8 cbndx; u8 irptndx; + union { + u16 asid; + u16 vmid; + }; u32 cbar; enum arm_smmu_context_fmt fmt; }; #define INVALID_IRPTNDX 0xff -#define ARM_SMMU_CB_ASID(smmu, cfg) ((u16)(smmu)->cavium_id_base + (cfg)->cbndx) -#define ARM_SMMU_CB_VMID(smmu, cfg) ((u16)(smmu)->cavium_id_base + (cfg)->cbndx + 1) - enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_S1 = 0, ARM_SMMU_DOMAIN_S2, ARM_SMMU_DOMAIN_NESTED, + ARM_SMMU_DOMAIN_BYPASS, }; struct arm_smmu_domain { @@ -569,49 +573,67 @@ static void __arm_smmu_free_bitmap(unsigned long *map, int idx) } /* Wait for any pending TLB invalidations to complete */ -static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu) +static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, + void __iomem *sync, void __iomem *status) { - int count = 0; - void __iomem *gr0_base = ARM_SMMU_GR0(smmu); - - writel_relaxed(0, gr0_base + ARM_SMMU_GR0_sTLBGSYNC); - while (readl_relaxed(gr0_base + ARM_SMMU_GR0_sTLBGSTATUS) - & sTLBGSTATUS_GSACTIVE) { - cpu_relax(); - if (++count == TLB_LOOP_TIMEOUT) { - dev_err_ratelimited(smmu->dev, - "TLB sync timed out -- SMMU may be deadlocked\n"); - return; + unsigned int spin_cnt, delay; + + writel_relaxed(0, sync); + for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) { + for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) { + if (!(readl_relaxed(status) & sTLBGSTATUS_GSACTIVE)) + return; + cpu_relax(); } - udelay(1); + udelay(delay); } + dev_err_ratelimited(smmu->dev, + "TLB sync timed out -- SMMU may be deadlocked\n"); } -static void arm_smmu_tlb_sync(void *cookie) +static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu) +{ + void __iomem *base = ARM_SMMU_GR0(smmu); + + __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC, + base + ARM_SMMU_GR0_sTLBGSTATUS); +} + +static void arm_smmu_tlb_sync_context(void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; - __arm_smmu_tlb_sync(smmu_domain->smmu); + struct arm_smmu_device *smmu = smmu_domain->smmu; + void __iomem *base = ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx); + + __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC, + base + ARM_SMMU_CB_TLBSTATUS); } -static void arm_smmu_tlb_inv_context(void *cookie) +static void arm_smmu_tlb_sync_vmid(void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + + arm_smmu_tlb_sync_global(smmu_domain->smmu); +} + +static void arm_smmu_tlb_inv_context_s1(void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - struct arm_smmu_device *smmu = smmu_domain->smmu; - bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; - void __iomem *base; + void __iomem *base = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx); - if (stage1) { - base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); - writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg), - base + ARM_SMMU_CB_S1_TLBIASID); - } else { - base = ARM_SMMU_GR0(smmu); - writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), - base + ARM_SMMU_GR0_TLBIVMID); - } + writel_relaxed(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID); + arm_smmu_tlb_sync_context(cookie); +} + +static void arm_smmu_tlb_inv_context_s2(void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + struct arm_smmu_device *smmu = smmu_domain->smmu; + void __iomem *base = ARM_SMMU_GR0(smmu); - __arm_smmu_tlb_sync(smmu); + writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID); + arm_smmu_tlb_sync_global(smmu); } static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, @@ -619,31 +641,28 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, { struct arm_smmu_domain *smmu_domain = cookie; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - struct arm_smmu_device *smmu = smmu_domain->smmu; bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; - void __iomem *reg; + void __iomem *reg = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx); if (stage1) { - reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA; if (cfg->fmt != ARM_SMMU_CTX_FMT_AARCH64) { iova &= ~12UL; - iova |= ARM_SMMU_CB_ASID(smmu, cfg); + iova |= cfg->asid; do { writel_relaxed(iova, reg); iova += granule; } while (size -= granule); } else { iova >>= 12; - iova |= (u64)ARM_SMMU_CB_ASID(smmu, cfg) << 48; + iova |= (u64)cfg->asid << 48; do { writeq_relaxed(iova, reg); iova += granule >> 12; } while (size -= granule); } - } else if (smmu->version == ARM_SMMU_V2) { - reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + } else { reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L : ARM_SMMU_CB_S2_TLBIIPAS2; iova >>= 12; @@ -651,16 +670,40 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, smmu_write_atomic_lq(iova, reg); iova += granule >> 12; } while (size -= granule); - } else { - reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID; - writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), reg); } } -static const struct iommu_gather_ops arm_smmu_gather_ops = { - .tlb_flush_all = arm_smmu_tlb_inv_context, +/* + * On MMU-401 at least, the cost of firing off multiple TLBIVMIDs appears + * almost negligible, but the benefit of getting the first one in as far ahead + * of the sync as possible is significant, hence we don't just make this a + * no-op and set .tlb_sync to arm_smmu_inv_context_s2() as you might think. + */ +static void arm_smmu_tlb_inv_vmid_nosync(unsigned long iova, size_t size, + size_t granule, bool leaf, void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + void __iomem *base = ARM_SMMU_GR0(smmu_domain->smmu); + + writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID); +} + +static const struct iommu_gather_ops arm_smmu_s1_tlb_ops = { + .tlb_flush_all = arm_smmu_tlb_inv_context_s1, .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, - .tlb_sync = arm_smmu_tlb_sync, + .tlb_sync = arm_smmu_tlb_sync_context, +}; + +static const struct iommu_gather_ops arm_smmu_s2_tlb_ops_v2 = { + .tlb_flush_all = arm_smmu_tlb_inv_context_s2, + .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, + .tlb_sync = arm_smmu_tlb_sync_context, +}; + +static const struct iommu_gather_ops arm_smmu_s2_tlb_ops_v1 = { + .tlb_flush_all = arm_smmu_tlb_inv_context_s2, + .tlb_add_flush = arm_smmu_tlb_inv_vmid_nosync, + .tlb_sync = arm_smmu_tlb_sync_vmid, }; static irqreturn_t arm_smmu_context_fault(int irq, void *dev) @@ -673,7 +716,7 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) struct arm_smmu_device *smmu = smmu_domain->smmu; void __iomem *cb_base; - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); if (!(fsr & FSR_FAULT)) @@ -726,7 +769,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, gr1_base = ARM_SMMU_GR1(smmu); stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); if (smmu->version > ARM_SMMU_V1) { if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) @@ -735,7 +778,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, reg = CBA2R_RW64_32BIT; /* 16-bit VMIDs live in CBA2R */ if (smmu->features & ARM_SMMU_FEAT_VMID16) - reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBA2R_VMID_SHIFT; + reg |= cfg->vmid << CBA2R_VMID_SHIFT; writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); } @@ -754,34 +797,15 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); } else if (!(smmu->features & ARM_SMMU_FEAT_VMID16)) { /* 8-bit VMIDs live in CBAR */ - reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBAR_VMID_SHIFT; + reg |= cfg->vmid << CBAR_VMID_SHIFT; } writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx)); - /* TTBRs */ - if (stage1) { - u16 asid = ARM_SMMU_CB_ASID(smmu, cfg); - - if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { - reg = pgtbl_cfg->arm_v7s_cfg.ttbr[0]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0); - reg = pgtbl_cfg->arm_v7s_cfg.ttbr[1]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1); - writel_relaxed(asid, cb_base + ARM_SMMU_CB_CONTEXTIDR); - } else { - reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; - reg64 |= (u64)asid << TTBRn_ASID_SHIFT; - writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0); - reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; - reg64 |= (u64)asid << TTBRn_ASID_SHIFT; - writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR1); - } - } else { - reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; - writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0); - } - - /* TTBCR */ + /* + * TTBCR + * We must write this before the TTBRs, since it determines the + * access behaviour of some fields (in particular, ASID[15:8]). + */ if (stage1) { if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { reg = pgtbl_cfg->arm_v7s_cfg.tcr; @@ -800,6 +824,27 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, } writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); + /* TTBRs */ + if (stage1) { + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { + reg = pgtbl_cfg->arm_v7s_cfg.ttbr[0]; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0); + reg = pgtbl_cfg->arm_v7s_cfg.ttbr[1]; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1); + writel_relaxed(cfg->asid, cb_base + ARM_SMMU_CB_CONTEXTIDR); + } else { + reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; + reg64 |= (u64)cfg->asid << TTBRn_ASID_SHIFT; + writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0); + reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; + reg64 |= (u64)cfg->asid << TTBRn_ASID_SHIFT; + writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR1); + } + } else { + reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; + writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0); + } + /* MAIRs (stage-1 only) */ if (stage1) { if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { @@ -833,11 +878,18 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, enum io_pgtable_fmt fmt; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_cfg *cfg = &smmu_domain->cfg; + const struct iommu_gather_ops *tlb_ops; mutex_lock(&smmu_domain->init_mutex); if (smmu_domain->smmu) goto out_unlock; + if (domain->type == IOMMU_DOMAIN_IDENTITY) { + smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS; + smmu_domain->smmu = smmu; + goto out_unlock; + } + /* * Mapping the requested stage onto what we support is surprisingly * complicated, mainly because the spec allows S1+S2 SMMUs without @@ -904,6 +956,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ias = min(ias, 32UL); oas = min(oas, 32UL); } + tlb_ops = &arm_smmu_s1_tlb_ops; break; case ARM_SMMU_DOMAIN_NESTED: /* @@ -922,12 +975,15 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ias = min(ias, 40UL); oas = min(oas, 40UL); } + if (smmu->version == ARM_SMMU_V2) + tlb_ops = &arm_smmu_s2_tlb_ops_v2; + else + tlb_ops = &arm_smmu_s2_tlb_ops_v1; break; default: ret = -EINVAL; goto out_unlock; } - ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, smmu->num_context_banks); if (ret < 0) @@ -941,11 +997,16 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, cfg->irptndx = cfg->cbndx; } + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S2) + cfg->vmid = cfg->cbndx + 1 + smmu->cavium_id_base; + else + cfg->asid = cfg->cbndx + smmu->cavium_id_base; + pgtbl_cfg = (struct io_pgtable_cfg) { .pgsize_bitmap = smmu->pgsize_bitmap, .ias = ias, .oas = oas, - .tlb = &arm_smmu_gather_ops, + .tlb = tlb_ops, .iommu_dev = smmu->dev, }; @@ -998,14 +1059,14 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) void __iomem *cb_base; int irq; - if (!smmu) + if (!smmu || domain->type == IOMMU_DOMAIN_IDENTITY) return; /* * Disable the context bank and free the page tables before freeing * it. */ - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); if (cfg->irptndx != INVALID_IRPTNDX) { @@ -1021,7 +1082,9 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) { struct arm_smmu_domain *smmu_domain; - if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) + if (type != IOMMU_DOMAIN_UNMANAGED && + type != IOMMU_DOMAIN_DMA && + type != IOMMU_DOMAIN_IDENTITY) return NULL; /* * Allocate the domain and initialise some of its data structures. @@ -1250,10 +1313,15 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain, { struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_s2cr *s2cr = smmu->s2crs; - enum arm_smmu_s2cr_type type = S2CR_TYPE_TRANS; u8 cbndx = smmu_domain->cfg.cbndx; + enum arm_smmu_s2cr_type type; int i, idx; + if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS) + type = S2CR_TYPE_BYPASS; + else + type = S2CR_TYPE_TRANS; + for_each_cfg_sme(fwspec, i, idx) { if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx) continue; @@ -1356,7 +1424,7 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, u64 phys; unsigned long va; - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); /* ATS1 registers can only be written atomically */ va = iova & ~0xfffUL; @@ -1391,6 +1459,9 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; + if (domain->type == IOMMU_DOMAIN_IDENTITY) + return iova; + if (!ops) return 0; @@ -1467,7 +1538,7 @@ static int arm_smmu_add_device(struct device *dev) } if (mask & ~smmu->smr_mask_mask) { dev_err(dev, "SMR mask 0x%x out of range for SMMU (0x%x)\n", - sid, smmu->smr_mask_mask); + mask, smmu->smr_mask_mask); goto out_free; } } @@ -1549,6 +1620,9 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + if (domain->type != IOMMU_DOMAIN_UNMANAGED) + return -EINVAL; + switch (attr) { case DOMAIN_ATTR_NESTING: *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); @@ -1564,6 +1638,9 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, int ret = 0; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + if (domain->type != IOMMU_DOMAIN_UNMANAGED) + return -EINVAL; + mutex_lock(&smmu_domain->init_mutex); switch (attr) { @@ -1590,13 +1667,15 @@ out_unlock: static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args) { - u32 fwid = 0; + u32 mask, fwid = 0; if (args->args_count > 0) fwid |= (u16)args->args[0]; if (args->args_count > 1) fwid |= (u16)args->args[1] << SMR_MASK_SHIFT; + else if (!of_property_read_u32(args->np, "stream-match-mask", &mask)) + fwid |= (u16)mask << SMR_MASK_SHIFT; return iommu_fwspec_add_ids(dev, &fwid, 1); } @@ -1613,6 +1692,8 @@ static void arm_smmu_get_resv_regions(struct device *dev, return; list_add_tail(®ion->list, head); + + iommu_dma_get_resv_regions(dev, head); } static void arm_smmu_put_resv_regions(struct device *dev, @@ -1683,7 +1764,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) /* Make sure all context banks are disabled and clear CB_FSR */ for (i = 0; i < smmu->num_context_banks; ++i) { - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, i); + cb_base = ARM_SMMU_CB(smmu, i); writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); writel_relaxed(FSR_FAULT, cb_base + ARM_SMMU_CB_FSR); /* @@ -1729,7 +1810,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) reg |= sCR0_EXIDENABLE; /* Push the button */ - __arm_smmu_tlb_sync(smmu); + arm_smmu_tlb_sync_global(smmu); writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); } @@ -1863,11 +1944,11 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) /* Check for size mismatch of SMMU address space from mapped region */ size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1); - size *= 2 << smmu->pgshift; - if (smmu->size != size) + size <<= smmu->pgshift; + if (smmu->cb_base != gr0_base + size) dev_warn(smmu->dev, - "SMMU address space size (0x%lx) differs from mapped region size (0x%lx)!\n", - size, smmu->size); + "SMMU address space size (0x%lx) differs from mapped region size (0x%tx)!\n", + size * 2, (smmu->cb_base - gr0_base) * 2); smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & ID1_NUMS2CB_MASK; smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK; @@ -1887,6 +1968,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) atomic_add_return(smmu->num_context_banks, &cavium_smmu_context_count); smmu->cavium_id_base -= smmu->num_context_banks; + dev_notice(smmu->dev, "\tenabling workaround for Cavium erratum 27704\n"); } /* ID2 */ @@ -2075,6 +2157,23 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev, return 0; } +static void arm_smmu_bus_init(void) +{ + /* Oh, for a proper bus abstraction */ + if (!iommu_present(&platform_bus_type)) + bus_set_iommu(&platform_bus_type, &arm_smmu_ops); +#ifdef CONFIG_ARM_AMBA + if (!iommu_present(&amba_bustype)) + bus_set_iommu(&amba_bustype, &arm_smmu_ops); +#endif +#ifdef CONFIG_PCI + if (!iommu_present(&pci_bus_type)) { + pci_request_acs(); + bus_set_iommu(&pci_bus_type, &arm_smmu_ops); + } +#endif +} + static int arm_smmu_device_probe(struct platform_device *pdev) { struct resource *res; @@ -2103,7 +2202,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) smmu->base = devm_ioremap_resource(dev, res); if (IS_ERR(smmu->base)) return PTR_ERR(smmu->base); - smmu->size = resource_size(res); + smmu->cb_base = smmu->base + resource_size(res) / 2; num_irqs = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) { @@ -2180,21 +2279,30 @@ static int arm_smmu_device_probe(struct platform_device *pdev) arm_smmu_device_reset(smmu); arm_smmu_test_smr_masks(smmu); - /* Oh, for a proper bus abstraction */ - if (!iommu_present(&platform_bus_type)) - bus_set_iommu(&platform_bus_type, &arm_smmu_ops); -#ifdef CONFIG_ARM_AMBA - if (!iommu_present(&amba_bustype)) - bus_set_iommu(&amba_bustype, &arm_smmu_ops); -#endif -#ifdef CONFIG_PCI - if (!iommu_present(&pci_bus_type)) { - pci_request_acs(); - bus_set_iommu(&pci_bus_type, &arm_smmu_ops); - } -#endif + /* + * For ACPI and generic DT bindings, an SMMU will be probed before + * any device which might need it, so we want the bus ops in place + * ready to handle default domain setup as soon as any SMMU exists. + */ + if (!using_legacy_binding) + arm_smmu_bus_init(); + + return 0; +} + +/* + * With the legacy DT binding in play, though, we have no guarantees about + * probe order, but then we're also not doing default domains, so we can + * delay setting bus ops until we're sure every possible SMMU is ready, + * and that way ensure that no add_device() calls get missed. + */ +static int arm_smmu_legacy_bus_init(void) +{ + if (using_legacy_binding) + arm_smmu_bus_init(); return 0; } +device_initcall_sync(arm_smmu_legacy_bus_init); static int arm_smmu_device_remove(struct platform_device *pdev) { @@ -2219,56 +2327,14 @@ static struct platform_driver arm_smmu_driver = { .probe = arm_smmu_device_probe, .remove = arm_smmu_device_remove, }; - -static int __init arm_smmu_init(void) -{ - static bool registered; - int ret = 0; - - if (!registered) { - ret = platform_driver_register(&arm_smmu_driver); - registered = !ret; - } - return ret; -} - -static void __exit arm_smmu_exit(void) -{ - return platform_driver_unregister(&arm_smmu_driver); -} - -subsys_initcall(arm_smmu_init); -module_exit(arm_smmu_exit); - -static int __init arm_smmu_of_init(struct device_node *np) -{ - int ret = arm_smmu_init(); - - if (ret) - return ret; - - if (!of_platform_device_create(np, NULL, platform_bus_type.dev_root)) - return -ENODEV; - - return 0; -} -IOMMU_OF_DECLARE(arm_smmuv1, "arm,smmu-v1", arm_smmu_of_init); -IOMMU_OF_DECLARE(arm_smmuv2, "arm,smmu-v2", arm_smmu_of_init); -IOMMU_OF_DECLARE(arm_mmu400, "arm,mmu-400", arm_smmu_of_init); -IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init); -IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init); -IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init); - -#ifdef CONFIG_ACPI -static int __init arm_smmu_acpi_init(struct acpi_table_header *table) -{ - if (iort_node_match(ACPI_IORT_NODE_SMMU)) - return arm_smmu_init(); - - return 0; -} -IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init); -#endif +module_platform_driver(arm_smmu_driver); + +IOMMU_OF_DECLARE(arm_smmuv1, "arm,smmu-v1", NULL); +IOMMU_OF_DECLARE(arm_smmuv2, "arm,smmu-v2", NULL); +IOMMU_OF_DECLARE(arm_mmu400, "arm,mmu-400", NULL); +IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", NULL); +IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", NULL); +IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", NULL); MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>"); diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 48d36ce59efb..8348f366ddd1 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -61,15 +61,6 @@ static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) return PAGE_SIZE; } -static inline struct iova_domain *cookie_iovad(struct iommu_domain *domain) -{ - struct iommu_dma_cookie *cookie = domain->iova_cookie; - - if (cookie->type == IOMMU_DMA_IOVA_COOKIE) - return &cookie->iovad; - return NULL; -} - static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type) { struct iommu_dma_cookie *cookie; @@ -167,22 +158,99 @@ void iommu_put_dma_cookie(struct iommu_domain *domain) } EXPORT_SYMBOL(iommu_put_dma_cookie); -static void iova_reserve_pci_windows(struct pci_dev *dev, - struct iova_domain *iovad) +/** + * iommu_dma_get_resv_regions - Reserved region driver helper + * @dev: Device from iommu_get_resv_regions() + * @list: Reserved region list from iommu_get_resv_regions() + * + * IOMMU drivers can use this to implement their .get_resv_regions callback + * for general non-IOMMU-specific reservations. Currently, this covers host + * bridge windows for PCI devices. + */ +void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) { - struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); + struct pci_host_bridge *bridge; struct resource_entry *window; - unsigned long lo, hi; + if (!dev_is_pci(dev)) + return; + + bridge = pci_find_host_bridge(to_pci_dev(dev)->bus); resource_list_for_each_entry(window, &bridge->windows) { - if (resource_type(window->res) != IORESOURCE_MEM && - resource_type(window->res) != IORESOURCE_IO) + struct iommu_resv_region *region; + phys_addr_t start; + size_t length; + + if (resource_type(window->res) != IORESOURCE_MEM) + continue; + + start = window->res->start - window->offset; + length = window->res->end - window->res->start + 1; + region = iommu_alloc_resv_region(start, length, 0, + IOMMU_RESV_RESERVED); + if (!region) + return; + + list_add_tail(®ion->list, list); + } +} +EXPORT_SYMBOL(iommu_dma_get_resv_regions); + +static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie, + phys_addr_t start, phys_addr_t end) +{ + struct iova_domain *iovad = &cookie->iovad; + struct iommu_dma_msi_page *msi_page; + int i, num_pages; + + start -= iova_offset(iovad, start); + num_pages = iova_align(iovad, end - start) >> iova_shift(iovad); + + msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL); + if (!msi_page) + return -ENOMEM; + + for (i = 0; i < num_pages; i++) { + msi_page[i].phys = start; + msi_page[i].iova = start; + INIT_LIST_HEAD(&msi_page[i].list); + list_add(&msi_page[i].list, &cookie->msi_page_list); + start += iovad->granule; + } + + return 0; +} + +static int iova_reserve_iommu_regions(struct device *dev, + struct iommu_domain *domain) +{ + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; + struct iommu_resv_region *region; + LIST_HEAD(resv_regions); + int ret = 0; + + iommu_get_resv_regions(dev, &resv_regions); + list_for_each_entry(region, &resv_regions, list) { + unsigned long lo, hi; + + /* We ARE the software that manages these! */ + if (region->type == IOMMU_RESV_SW_MSI) continue; - lo = iova_pfn(iovad, window->res->start - window->offset); - hi = iova_pfn(iovad, window->res->end - window->offset); + lo = iova_pfn(iovad, region->start); + hi = iova_pfn(iovad, region->start + region->length - 1); reserve_iova(iovad, lo, hi); + + if (region->type == IOMMU_RESV_MSI) + ret = cookie_init_hw_msi_region(cookie, region->start, + region->start + region->length); + if (ret) + break; } + iommu_put_resv_regions(dev, &resv_regions); + + return ret; } /** @@ -203,7 +271,6 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; unsigned long order, base_pfn, end_pfn; - bool pci = dev && dev_is_pci(dev); if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE) return -EINVAL; @@ -233,7 +300,7 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, * leave the cache limit at the top of their range to save an rb_last() * traversal on every allocation. */ - if (pci) + if (dev && dev_is_pci(dev)) end_pfn &= DMA_BIT_MASK(32) >> order; /* start_pfn is always nonzero for an already-initialised domain */ @@ -248,12 +315,15 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, * area cache limit down for the benefit of the smaller one. */ iovad->dma_32bit_pfn = min(end_pfn, iovad->dma_32bit_pfn); - } else { - init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn); - if (pci) - iova_reserve_pci_windows(to_pci_dev(dev), iovad); + + return 0; } - return 0; + + init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn); + if (!dev) + return 0; + + return iova_reserve_iommu_regions(dev, domain); } EXPORT_SYMBOL(iommu_dma_init_domain); @@ -286,48 +356,67 @@ int dma_info_to_prot(enum dma_data_direction dir, bool coherent, } } -static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, - dma_addr_t dma_limit, struct device *dev) +static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, + size_t size, dma_addr_t dma_limit, struct device *dev) { - struct iova_domain *iovad = cookie_iovad(domain); - unsigned long shift = iova_shift(iovad); - unsigned long length = iova_align(iovad, size) >> shift; - struct iova *iova = NULL; + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; + unsigned long shift, iova_len, iova = 0; + + if (cookie->type == IOMMU_DMA_MSI_COOKIE) { + cookie->msi_iova += size; + return cookie->msi_iova - size; + } + + shift = iova_shift(iovad); + iova_len = size >> shift; + /* + * Freeing non-power-of-two-sized allocations back into the IOVA caches + * will come back to bite us badly, so we have to waste a bit of space + * rounding up anything cacheable to make sure that can't happen. The + * order of the unadjusted size will still match upon freeing. + */ + if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) + iova_len = roundup_pow_of_two(iova_len); if (domain->geometry.force_aperture) dma_limit = min(dma_limit, domain->geometry.aperture_end); /* Try to get PCI devices a SAC address */ if (dma_limit > DMA_BIT_MASK(32) && dev_is_pci(dev)) - iova = alloc_iova(iovad, length, DMA_BIT_MASK(32) >> shift, - true); - /* - * Enforce size-alignment to be safe - there could perhaps be an - * attribute to control this per-device, or at least per-domain... - */ + iova = alloc_iova_fast(iovad, iova_len, DMA_BIT_MASK(32) >> shift); + if (!iova) - iova = alloc_iova(iovad, length, dma_limit >> shift, true); + iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift); - return iova; + return (dma_addr_t)iova << shift; } -/* The IOVA allocator knows what we mapped, so just unmap whatever that was */ -static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr) +static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, + dma_addr_t iova, size_t size) { - struct iova_domain *iovad = cookie_iovad(domain); + struct iova_domain *iovad = &cookie->iovad; unsigned long shift = iova_shift(iovad); - unsigned long pfn = dma_addr >> shift; - struct iova *iova = find_iova(iovad, pfn); - size_t size; - if (WARN_ON(!iova)) - return; + /* The MSI case is only ever cleaning up its most recent allocation */ + if (cookie->type == IOMMU_DMA_MSI_COOKIE) + cookie->msi_iova -= size; + else + free_iova_fast(iovad, iova >> shift, size >> shift); +} + +static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr, + size_t size) +{ + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; + size_t iova_off = iova_offset(iovad, dma_addr); + + dma_addr -= iova_off; + size = iova_align(iovad, size + iova_off); - size = iova_size(iova) << shift; - size -= iommu_unmap(domain, pfn << shift, size); - /* ...and if we can't, then something is horribly, horribly wrong */ - WARN_ON(size > 0); - __free_iova(iovad, iova); + WARN_ON(iommu_unmap(domain, dma_addr, size) != size); + iommu_dma_free_iova(cookie, dma_addr, size); } static void __iommu_dma_free_pages(struct page **pages, int count) @@ -409,7 +498,7 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, void iommu_dma_free(struct device *dev, struct page **pages, size_t size, dma_addr_t *handle) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size); __iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT); *handle = DMA_ERROR_CODE; } @@ -437,11 +526,11 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, void (*flush_page)(struct device *, const void *, phys_addr_t)) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct iova_domain *iovad = cookie_iovad(domain); - struct iova *iova; + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; struct page **pages; struct sg_table sgt; - dma_addr_t dma_addr; + dma_addr_t iova; unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap; *handle = DMA_ERROR_CODE; @@ -461,11 +550,11 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, if (!pages) return NULL; - iova = __alloc_iova(domain, size, dev->coherent_dma_mask, dev); + size = iova_align(iovad, size); + iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev); if (!iova) goto out_free_pages; - size = iova_align(iovad, size); if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL)) goto out_free_iova; @@ -481,19 +570,18 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, sg_miter_stop(&miter); } - dma_addr = iova_dma_addr(iovad, iova); - if (iommu_map_sg(domain, dma_addr, sgt.sgl, sgt.orig_nents, prot) + if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot) < size) goto out_free_sg; - *handle = dma_addr; + *handle = iova; sg_free_table(&sgt); return pages; out_free_sg: sg_free_table(&sgt); out_free_iova: - __free_iova(iovad, iova); + iommu_dma_free_iova(cookie, iova, size); out_free_pages: __iommu_dma_free_pages(pages, count); return NULL; @@ -527,22 +615,22 @@ int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma) static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, size_t size, int prot) { - dma_addr_t dma_addr; struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct iova_domain *iovad = cookie_iovad(domain); + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; size_t iova_off = iova_offset(iovad, phys); - size_t len = iova_align(iovad, size + iova_off); - struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev), dev); + dma_addr_t iova; + size = iova_align(iovad, size + iova_off); + iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev); if (!iova) return DMA_ERROR_CODE; - dma_addr = iova_dma_addr(iovad, iova); - if (iommu_map(domain, dma_addr, phys - iova_off, len, prot)) { - __free_iova(iovad, iova); + if (iommu_map(domain, iova, phys - iova_off, size, prot)) { + iommu_dma_free_iova(cookie, iova, size); return DMA_ERROR_CODE; } - return dma_addr + iova_off; + return iova + iova_off; } dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, @@ -554,7 +642,7 @@ dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size); } /* @@ -643,10 +731,10 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int prot) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct iova_domain *iovad = cookie_iovad(domain); - struct iova *iova; + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; struct scatterlist *s, *prev = NULL; - dma_addr_t dma_addr; + dma_addr_t iova; size_t iova_len = 0; unsigned long mask = dma_get_seg_boundary(dev); int i; @@ -690,7 +778,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, prev = s; } - iova = __alloc_iova(domain, iova_len, dma_get_mask(dev), dev); + iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev); if (!iova) goto out_restore_sg; @@ -698,14 +786,13 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, * We'll leave any physical concatenation to the IOMMU driver's * implementation - it knows better than we do. */ - dma_addr = iova_dma_addr(iovad, iova); - if (iommu_map_sg(domain, dma_addr, sg, nents, prot) < iova_len) + if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len) goto out_free_iova; - return __finalise_sg(dev, sg, nents, dma_addr); + return __finalise_sg(dev, sg, nents, iova); out_free_iova: - __free_iova(iovad, iova); + iommu_dma_free_iova(cookie, iova, iova_len); out_restore_sg: __invalidate_sg(sg, nents); return 0; @@ -714,11 +801,21 @@ out_restore_sg: void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { + dma_addr_t start, end; + struct scatterlist *tmp; + int i; /* * The scatterlist segments are mapped into a single * contiguous IOVA allocation, so this is incredibly easy. */ - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg)); + start = sg_dma_address(sg); + for_each_sg(sg_next(sg), tmp, nents - 1, i) { + if (sg_dma_len(tmp) == 0) + break; + sg = tmp; + } + end = sg_dma_address(sg) + sg_dma_len(sg); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), start, end - start); } dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, @@ -731,7 +828,7 @@ dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size); } int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) @@ -744,8 +841,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, { struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iommu_dma_msi_page *msi_page; - struct iova_domain *iovad = cookie_iovad(domain); - struct iova *iova; + dma_addr_t iova; int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; size_t size = cookie_msi_granule(cookie); @@ -758,29 +854,16 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, if (!msi_page) return NULL; - msi_page->phys = msi_addr; - if (iovad) { - iova = __alloc_iova(domain, size, dma_get_mask(dev), dev); - if (!iova) - goto out_free_page; - msi_page->iova = iova_dma_addr(iovad, iova); - } else { - msi_page->iova = cookie->msi_iova; - cookie->msi_iova += size; - } - - if (iommu_map(domain, msi_page->iova, msi_addr, size, prot)) - goto out_free_iova; + iova = __iommu_dma_map(dev, msi_addr, size, prot); + if (iommu_dma_mapping_error(dev, iova)) + goto out_free_page; INIT_LIST_HEAD(&msi_page->list); + msi_page->phys = msi_addr; + msi_page->iova = iova; list_add(&msi_page->list, &cookie->msi_page_list); return msi_page; -out_free_iova: - if (iovad) - __free_iova(iovad, iova); - else - cookie->msi_iova -= size; out_free_page: kfree(msi_page); return NULL; diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 36e3f430d265..cbf7763d8091 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -311,7 +311,7 @@ static int dmar_pci_bus_add_dev(struct dmar_pci_notify_info *info) ((void *)drhd) + drhd->header.length, dmaru->segment, dmaru->devices, dmaru->devices_cnt); - if (ret != 0) + if (ret) break; } if (ret >= 0) @@ -391,7 +391,7 @@ static int dmar_parse_one_drhd(struct acpi_dmar_header *header, void *arg) { struct acpi_dmar_hardware_unit *drhd; struct dmar_drhd_unit *dmaru; - int ret = 0; + int ret; drhd = (struct acpi_dmar_hardware_unit *)header; dmaru = dmar_find_dmaru(drhd); @@ -551,17 +551,16 @@ static int __init dmar_table_detect(void) status = AE_NOT_FOUND; } - return (ACPI_SUCCESS(status) ? 1 : 0); + return ACPI_SUCCESS(status) ? 0 : -ENOENT; } static int dmar_walk_remapping_entries(struct acpi_dmar_header *start, size_t len, struct dmar_res_callback *cb) { - int ret = 0; struct acpi_dmar_header *iter, *next; struct acpi_dmar_header *end = ((void *)start) + len; - for (iter = start; iter < end && ret == 0; iter = next) { + for (iter = start; iter < end; iter = next) { next = (void *)iter + iter->length; if (iter->length == 0) { /* Avoid looping forever on bad ACPI tables */ @@ -570,8 +569,7 @@ static int dmar_walk_remapping_entries(struct acpi_dmar_header *start, } else if (next > end) { /* Avoid passing table end */ pr_warn(FW_BUG "Record passes table end\n"); - ret = -EINVAL; - break; + return -EINVAL; } if (cb->print_entry) @@ -582,15 +580,19 @@ static int dmar_walk_remapping_entries(struct acpi_dmar_header *start, pr_debug("Unknown DMAR structure type %d\n", iter->type); } else if (cb->cb[iter->type]) { + int ret; + ret = cb->cb[iter->type](iter, cb->arg[iter->type]); + if (ret) + return ret; } else if (!cb->ignore_unhandled) { pr_warn("No handler for DMAR structure type %d\n", iter->type); - ret = -EINVAL; + return -EINVAL; } } - return ret; + return 0; } static inline int dmar_walk_dmar_table(struct acpi_table_dmar *dmar, @@ -607,8 +609,8 @@ static int __init parse_dmar_table(void) { struct acpi_table_dmar *dmar; - int ret = 0; int drhd_count = 0; + int ret; struct dmar_res_callback cb = { .print_entry = true, .ignore_unhandled = true, @@ -891,17 +893,17 @@ int __init detect_intel_iommu(void) down_write(&dmar_global_lock); ret = dmar_table_detect(); - if (ret) - ret = !dmar_walk_dmar_table((struct acpi_table_dmar *)dmar_tbl, - &validate_drhd_cb); - if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { + if (!ret) + ret = dmar_walk_dmar_table((struct acpi_table_dmar *)dmar_tbl, + &validate_drhd_cb); + if (!ret && !no_iommu && !iommu_detected && !dmar_disabled) { iommu_detected = 1; /* Make sure ACS will be enabled */ pci_request_acs(); } #ifdef CONFIG_X86 - if (ret) + if (!ret) x86_init.iommu.iommu_init = intel_iommu_init; #endif @@ -911,10 +913,9 @@ int __init detect_intel_iommu(void) } up_write(&dmar_global_lock); - return ret ? 1 : -ENODEV; + return ret ? ret : 1; } - static void unmap_iommu(struct intel_iommu *iommu) { iounmap(iommu->reg); diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index c01bfcdb2383..2395478dde75 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -171,6 +171,9 @@ static u32 lv2ent_offset(sysmmu_iova_t iova) #define REG_V5_PT_BASE_PFN 0x00C #define REG_V5_MMU_FLUSH_ALL 0x010 #define REG_V5_MMU_FLUSH_ENTRY 0x014 +#define REG_V5_MMU_FLUSH_RANGE 0x018 +#define REG_V5_MMU_FLUSH_START 0x020 +#define REG_V5_MMU_FLUSH_END 0x024 #define REG_V5_INT_STATUS 0x060 #define REG_V5_INT_CLEAR 0x064 #define REG_V5_FAULT_AR_VA 0x070 @@ -319,14 +322,23 @@ static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, { unsigned int i; - for (i = 0; i < num_inv; i++) { - if (MMU_MAJ_VER(data->version) < 5) + if (MMU_MAJ_VER(data->version) < 5) { + for (i = 0; i < num_inv; i++) { writel((iova & SPAGE_MASK) | 1, data->sfrbase + REG_MMU_FLUSH_ENTRY); - else + iova += SPAGE_SIZE; + } + } else { + if (num_inv == 1) { writel((iova & SPAGE_MASK) | 1, data->sfrbase + REG_V5_MMU_FLUSH_ENTRY); - iova += SPAGE_SIZE; + } else { + writel((iova & SPAGE_MASK), + data->sfrbase + REG_V5_MMU_FLUSH_START); + writel((iova & SPAGE_MASK) + (num_inv - 1) * SPAGE_SIZE, + data->sfrbase + REG_V5_MMU_FLUSH_END); + writel(1, data->sfrbase + REG_V5_MMU_FLUSH_RANGE); + } } } @@ -747,16 +759,8 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) goto err_counter; /* Workaround for System MMU v3.3 to prevent caching 1MiB mapping */ - for (i = 0; i < NUM_LV1ENTRIES; i += 8) { - domain->pgtable[i + 0] = ZERO_LV2LINK; - domain->pgtable[i + 1] = ZERO_LV2LINK; - domain->pgtable[i + 2] = ZERO_LV2LINK; - domain->pgtable[i + 3] = ZERO_LV2LINK; - domain->pgtable[i + 4] = ZERO_LV2LINK; - domain->pgtable[i + 5] = ZERO_LV2LINK; - domain->pgtable[i + 6] = ZERO_LV2LINK; - domain->pgtable[i + 7] = ZERO_LV2LINK; - } + for (i = 0; i < NUM_LV1ENTRIES; i++) + domain->pgtable[i] = ZERO_LV2LINK; handle = dma_map_single(dma_dev, domain->pgtable, LV1TABLE_SIZE, DMA_TO_DEVICE); diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h index aab723f91f12..c3434f29c967 100644 --- a/drivers/iommu/fsl_pamu.h +++ b/drivers/iommu/fsl_pamu.h @@ -20,6 +20,7 @@ #define __FSL_PAMU_H #include <linux/iommu.h> +#include <linux/pci.h> #include <asm/fsl_pamu_stash.h> diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index d412a313a372..90ab0115d78e 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -183,6 +183,7 @@ static int rwbf_quirk; * (used when kernel is launched w/ TXT) */ static int force_on = 0; +int intel_iommu_tboot_noforce; /* * 0: Present @@ -607,6 +608,10 @@ static int __init intel_iommu_setup(char *str) "Intel-IOMMU: enable pre-production PASID support\n"); intel_iommu_pasid28 = 1; iommu_identity_mapping |= IDENTMAP_GFX; + } else if (!strncmp(str, "tboot_noforce", 13)) { + printk(KERN_INFO + "Intel-IOMMU: not forcing on after tboot. This could expose security risk for tboot\n"); + intel_iommu_tboot_noforce = 1; } str += strcspn(str, ","); @@ -4730,6 +4735,15 @@ static int intel_iommu_cpu_dead(unsigned int cpu) return 0; } +static void intel_disable_iommus(void) +{ + struct intel_iommu *iommu = NULL; + struct dmar_drhd_unit *drhd; + + for_each_iommu(iommu, drhd) + iommu_disable_translation(iommu); +} + static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev) { return container_of(dev, struct intel_iommu, iommu.dev); @@ -4840,8 +4854,28 @@ int __init intel_iommu_init(void) goto out_free_dmar; } - if (no_iommu || dmar_disabled) + if (no_iommu || dmar_disabled) { + /* + * We exit the function here to ensure IOMMU's remapping and + * mempool aren't setup, which means that the IOMMU's PMRs + * won't be disabled via the call to init_dmars(). So disable + * it explicitly here. The PMRs were setup by tboot prior to + * calling SENTER, but the kernel is expected to reset/tear + * down the PMRs. + */ + if (intel_iommu_tboot_noforce) { + for_each_iommu(iommu, drhd) + iommu_disable_protect_mem_regions(iommu); + } + + /* + * Make sure the IOMMUs are switched off, even when we + * boot into a kexec kernel and the previous kernel left + * them enabled + */ + intel_disable_iommus(); goto out_free_dmar; + } if (list_empty(&dmar_rmrr_units)) pr_info("No RMRR found\n"); diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index ac596928f6b4..a190cbd76ef7 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -408,14 +408,6 @@ static int iommu_load_old_irte(struct intel_iommu *iommu) size_t size; u64 irta; - if (!is_kdump_kernel()) { - pr_warn("IRQ remapping was enabled on %s but we are not in kdump mode\n", - iommu->name); - clear_ir_pre_enabled(iommu); - iommu_disable_irq_remapping(iommu); - return -EINVAL; - } - /* Check whether the old ir-table has the same size as ours */ irta = dmar_readq(iommu->reg + DMAR_IRTA_REG); if ((irta & INTR_REMAP_TABLE_REG_SIZE_MASK) @@ -567,7 +559,12 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) init_ir_status(iommu); if (ir_pre_enabled(iommu)) { - if (iommu_load_old_irte(iommu)) + if (!is_kdump_kernel()) { + pr_warn("IRQ remapping was enabled on %s but we are not in kdump mode\n", + iommu->name); + clear_ir_pre_enabled(iommu); + iommu_disable_irq_remapping(iommu); + } else if (iommu_load_old_irte(iommu)) pr_err("Failed to copy IR table for %s from previous kernel\n", iommu->name); else diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index f9bc6ebb8140..6e5df5e0a3bd 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -74,7 +74,7 @@ /* Calculate the block/page mapping size at level l for pagetable in d. */ #define ARM_LPAE_BLOCK_SIZE(l,d) \ - (1 << (ilog2(sizeof(arm_lpae_iopte)) + \ + (1ULL << (ilog2(sizeof(arm_lpae_iopte)) + \ ((ARM_LPAE_MAX_LEVELS - (l)) * (d)->bits_per_level))) /* Page table bits */ diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3b67144dead2..cf7ca7e70777 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -36,6 +36,7 @@ static struct kset *iommu_group_kset; static DEFINE_IDA(iommu_group_ida); +static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA; struct iommu_callback_data { const struct iommu_ops *ops; @@ -112,6 +113,18 @@ static int __iommu_attach_group(struct iommu_domain *domain, static void __iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group); +static int __init iommu_set_def_domain_type(char *str) +{ + bool pt; + + if (!str || strtobool(str, &pt)) + return -EINVAL; + + iommu_def_domain_type = pt ? IOMMU_DOMAIN_IDENTITY : IOMMU_DOMAIN_DMA; + return 0; +} +early_param("iommu.passthrough", iommu_set_def_domain_type); + static ssize_t iommu_group_attr_show(struct kobject *kobj, struct attribute *__attr, char *buf) { @@ -1015,10 +1028,19 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev) * IOMMU driver. */ if (!group->default_domain) { - group->default_domain = __iommu_domain_alloc(dev->bus, - IOMMU_DOMAIN_DMA); + struct iommu_domain *dom; + + dom = __iommu_domain_alloc(dev->bus, iommu_def_domain_type); + if (!dom && iommu_def_domain_type != IOMMU_DOMAIN_DMA) { + dev_warn(dev, + "failed to allocate default IOMMU domain of type %u; falling back to IOMMU_DOMAIN_DMA", + iommu_def_domain_type); + dom = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_DMA); + } + + group->default_domain = dom; if (!group->domain) - group->domain = group->default_domain; + group->domain = dom; } ret = iommu_group_add_device(group, dev); @@ -1083,8 +1105,12 @@ static int iommu_bus_notifier(struct notifier_block *nb, * result in ADD/DEL notifiers to group->notifier */ if (action == BUS_NOTIFY_ADD_DEVICE) { - if (ops->add_device) - return ops->add_device(dev); + if (ops->add_device) { + int ret; + + ret = ops->add_device(dev); + return (ret) ? NOTIFY_DONE : NOTIFY_OK; + } } else if (action == BUS_NOTIFY_REMOVED_DEVICE) { if (ops->remove_device && dev->iommu_group) { ops->remove_device(dev); @@ -1652,6 +1678,48 @@ void iommu_domain_window_disable(struct iommu_domain *domain, u32 wnd_nr) } EXPORT_SYMBOL_GPL(iommu_domain_window_disable); +/** + * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework + * @domain: the iommu domain where the fault has happened + * @dev: the device where the fault has happened + * @iova: the faulting address + * @flags: mmu fault flags (e.g. IOMMU_FAULT_READ/IOMMU_FAULT_WRITE/...) + * + * This function should be called by the low-level IOMMU implementations + * whenever IOMMU faults happen, to allow high-level users, that are + * interested in such events, to know about them. + * + * This event may be useful for several possible use cases: + * - mere logging of the event + * - dynamic TLB/PTE loading + * - if restarting of the faulting device is required + * + * Returns 0 on success and an appropriate error code otherwise (if dynamic + * PTE/TLB loading will one day be supported, implementations will be able + * to tell whether it succeeded or not according to this return value). + * + * Specifically, -ENOSYS is returned if a fault handler isn't installed + * (though fault handlers can also return -ENOSYS, in case they want to + * elicit the default behavior of the IOMMU drivers). + */ +int report_iommu_fault(struct iommu_domain *domain, struct device *dev, + unsigned long iova, int flags) +{ + int ret = -ENOSYS; + + /* + * if upper layers showed interest and installed a fault handler, + * invoke it. + */ + if (domain->handler) + ret = domain->handler(domain, dev, iova, flags, + domain->handler_token); + + trace_io_page_fault(dev, iova, flags); + return ret; +} +EXPORT_SYMBOL_GPL(report_iommu_fault); + static int __init iommu_init(void) { iommu_group_kset = kset_create_and_add("iommu_groups", diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index e80a4105ac2a..5c88ba70e4e0 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -166,7 +166,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, break; /* found a free slot */ } adjust_limit_pfn: - limit_pfn = curr_iova->pfn_lo - 1; + limit_pfn = curr_iova->pfn_lo ? (curr_iova->pfn_lo - 1) : 0; move_left: prev = curr; curr = rb_prev(curr); diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 19e010083408..a27ef570c328 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -431,9 +431,10 @@ err_release_mapping: static int mtk_iommu_add_device(struct device *dev) { - struct iommu_group *group; struct of_phandle_args iommu_spec; struct of_phandle_iterator it; + struct mtk_iommu_data *data; + struct iommu_group *group; int err; of_for_each_phandle(&it, err, dev->of_node, "iommus", @@ -450,6 +451,9 @@ static int mtk_iommu_add_device(struct device *dev) if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) return -ENODEV; /* Not a iommu client device */ + data = dev->iommu_fwspec->iommu_priv; + iommu_device_link(&data->iommu, dev); + group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) return PTR_ERR(group); @@ -460,9 +464,14 @@ static int mtk_iommu_add_device(struct device *dev) static void mtk_iommu_remove_device(struct device *dev) { + struct mtk_iommu_data *data; + if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) return; + data = dev->iommu_fwspec->iommu_priv; + iommu_device_unlink(&data->iommu, dev); + iommu_group_remove_device(dev); iommu_fwspec_free(dev); } @@ -627,6 +636,17 @@ static int mtk_iommu_probe(struct platform_device *pdev) if (ret) return ret; + ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL, + dev_name(&pdev->dev)); + if (ret) + return ret; + + iommu_device_set_ops(&data->iommu, &mtk_iommu_ops); + + ret = iommu_device_register(&data->iommu); + if (ret) + return ret; + if (!iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, &mtk_iommu_ops); @@ -637,6 +657,9 @@ static int mtk_iommu_remove(struct platform_device *pdev) { struct mtk_iommu_data *data = platform_get_drvdata(pdev); + iommu_device_sysfs_remove(&data->iommu); + iommu_device_unregister(&data->iommu); + if (iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, NULL); diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 2683e9fc0dcf..9f44ee8ea1bc 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -96,6 +96,49 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index, } EXPORT_SYMBOL_GPL(of_get_dma_window); +static bool of_iommu_driver_present(struct device_node *np) +{ + /* + * If the IOMMU still isn't ready by the time we reach init, assume + * it never will be. We don't want to defer indefinitely, nor attempt + * to dereference __iommu_of_table after it's been freed. + */ + if (system_state > SYSTEM_BOOTING) + return false; + + return of_match_node(&__iommu_of_table, np); +} + +static const struct iommu_ops +*of_iommu_xlate(struct device *dev, struct of_phandle_args *iommu_spec) +{ + const struct iommu_ops *ops; + struct fwnode_handle *fwnode = &iommu_spec->np->fwnode; + int err; + + ops = iommu_ops_from_fwnode(fwnode); + if ((ops && !ops->of_xlate) || + (!ops && !of_iommu_driver_present(iommu_spec->np))) + return NULL; + + err = iommu_fwspec_init(dev, &iommu_spec->np->fwnode, ops); + if (err) + return ERR_PTR(err); + /* + * The otherwise-empty fwspec handily serves to indicate the specific + * IOMMU device we're waiting for, which will be useful if we ever get + * a proper probe-ordering dependency mechanism in future. + */ + if (!ops) + return ERR_PTR(-EPROBE_DEFER); + + err = ops->of_xlate(dev, iommu_spec); + if (err) + return ERR_PTR(err); + + return ops; +} + static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) { struct of_phandle_args *iommu_spec = data; @@ -105,10 +148,11 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) } static const struct iommu_ops -*of_pci_iommu_configure(struct pci_dev *pdev, struct device_node *bridge_np) +*of_pci_iommu_init(struct pci_dev *pdev, struct device_node *bridge_np) { const struct iommu_ops *ops; struct of_phandle_args iommu_spec; + int err; /* * Start by tracing the RID alias down the PCI topology as @@ -123,56 +167,76 @@ static const struct iommu_ops * bus into the system beyond, and which IOMMU it ends up at. */ iommu_spec.np = NULL; - if (of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map", - "iommu-map-mask", &iommu_spec.np, iommu_spec.args)) - return NULL; + err = of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map", + "iommu-map-mask", &iommu_spec.np, + iommu_spec.args); + if (err) + return err == -ENODEV ? NULL : ERR_PTR(err); - ops = iommu_ops_from_fwnode(&iommu_spec.np->fwnode); - if (!ops || !ops->of_xlate || - iommu_fwspec_init(&pdev->dev, &iommu_spec.np->fwnode, ops) || - ops->of_xlate(&pdev->dev, &iommu_spec)) - ops = NULL; + ops = of_iommu_xlate(&pdev->dev, &iommu_spec); of_node_put(iommu_spec.np); return ops; } -const struct iommu_ops *of_iommu_configure(struct device *dev, - struct device_node *master_np) +static const struct iommu_ops +*of_platform_iommu_init(struct device *dev, struct device_node *np) { struct of_phandle_args iommu_spec; - struct device_node *np; const struct iommu_ops *ops = NULL; int idx = 0; - if (dev_is_pci(dev)) - return of_pci_iommu_configure(to_pci_dev(dev), master_np); - /* * We don't currently walk up the tree looking for a parent IOMMU. * See the `Notes:' section of * Documentation/devicetree/bindings/iommu/iommu.txt */ - while (!of_parse_phandle_with_args(master_np, "iommus", - "#iommu-cells", idx, - &iommu_spec)) { - np = iommu_spec.np; - ops = iommu_ops_from_fwnode(&np->fwnode); - - if (!ops || !ops->of_xlate || - iommu_fwspec_init(dev, &np->fwnode, ops) || - ops->of_xlate(dev, &iommu_spec)) - goto err_put_node; - - of_node_put(np); + while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells", + idx, &iommu_spec)) { + ops = of_iommu_xlate(dev, &iommu_spec); + of_node_put(iommu_spec.np); idx++; + if (IS_ERR_OR_NULL(ops)) + break; } return ops; +} + +const struct iommu_ops *of_iommu_configure(struct device *dev, + struct device_node *master_np) +{ + const struct iommu_ops *ops; + struct iommu_fwspec *fwspec = dev->iommu_fwspec; + + if (!master_np) + return NULL; + + if (fwspec) { + if (fwspec->ops) + return fwspec->ops; + + /* In the deferred case, start again from scratch */ + iommu_fwspec_free(dev); + } -err_put_node: - of_node_put(np); - return NULL; + if (dev_is_pci(dev)) + ops = of_pci_iommu_init(to_pci_dev(dev), master_np); + else + ops = of_platform_iommu_init(dev, master_np); + /* + * If we have reason to believe the IOMMU driver missed the initial + * add_device callback for dev, replay it to get things in order. + */ + if (!IS_ERR_OR_NULL(ops) && ops->add_device && + dev->bus && !dev->iommu_group) { + int err = ops->add_device(dev); + + if (err) + ops = ERR_PTR(err); + } + + return ops; } static int __init of_iommu_init(void) @@ -183,7 +247,7 @@ static int __init of_iommu_init(void) for_each_matching_node_and_match(np, matches, &match) { const of_iommu_init_fn init_fn = match->data; - if (init_fn(np)) + if (init_fn && init_fn(np)) pr_err("Failed to initialise IOMMU %s\n", of_node_full_name(np)); } diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index e2583cce2cc1..95dfca36ccb9 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -36,28 +36,14 @@ #include "omap-iopgtable.h" #include "omap-iommu.h" +static const struct iommu_ops omap_iommu_ops; + #define to_iommu(dev) \ ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))) /* bitmap of the page sizes currently supported */ #define OMAP_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M) -/** - * struct omap_iommu_domain - omap iommu domain - * @pgtable: the page table - * @iommu_dev: an omap iommu device attached to this domain. only a single - * iommu device can be attached for now. - * @dev: Device using this domain. - * @lock: domain lock, should be taken when attaching/detaching - */ -struct omap_iommu_domain { - u32 *pgtable; - struct omap_iommu *iommu_dev; - struct device *dev; - spinlock_t lock; - struct iommu_domain domain; -}; - #define MMU_LOCK_BASE_SHIFT 10 #define MMU_LOCK_BASE_MASK (0x1f << MMU_LOCK_BASE_SHIFT) #define MMU_LOCK_BASE(x) \ @@ -818,33 +804,14 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) return IRQ_NONE; } -static int device_match_by_alias(struct device *dev, void *data) -{ - struct omap_iommu *obj = to_iommu(dev); - const char *name = data; - - pr_debug("%s: %s %s\n", __func__, obj->name, name); - - return strcmp(obj->name, name) == 0; -} - /** * omap_iommu_attach() - attach iommu device to an iommu domain - * @name: name of target omap iommu device + * @obj: target omap iommu device * @iopgd: page table **/ -static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd) +static int omap_iommu_attach(struct omap_iommu *obj, u32 *iopgd) { int err; - struct device *dev; - struct omap_iommu *obj; - - dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name, - device_match_by_alias); - if (!dev) - return ERR_PTR(-ENODEV); - - obj = to_iommu(dev); spin_lock(&obj->iommu_lock); @@ -857,11 +824,13 @@ static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd) spin_unlock(&obj->iommu_lock); dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name); - return obj; + + return 0; err_enable: spin_unlock(&obj->iommu_lock); - return ERR_PTR(err); + + return err; } /** @@ -928,28 +897,26 @@ static int omap_iommu_probe(struct platform_device *pdev) int irq; struct omap_iommu *obj; struct resource *res; - struct iommu_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *of = pdev->dev.of_node; + if (!of) { + pr_err("%s: only DT-based devices are supported\n", __func__); + return -ENODEV; + } + obj = devm_kzalloc(&pdev->dev, sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL); if (!obj) return -ENOMEM; - if (of) { - obj->name = dev_name(&pdev->dev); - obj->nr_tlb_entries = 32; - err = of_property_read_u32(of, "ti,#tlb-entries", - &obj->nr_tlb_entries); - if (err && err != -EINVAL) - return err; - if (obj->nr_tlb_entries != 32 && obj->nr_tlb_entries != 8) - return -EINVAL; - if (of_find_property(of, "ti,iommu-bus-err-back", NULL)) - obj->has_bus_err_back = MMU_GP_REG_BUS_ERR_BACK_EN; - } else { - obj->nr_tlb_entries = pdata->nr_tlb_entries; - obj->name = pdata->name; - } + obj->name = dev_name(&pdev->dev); + obj->nr_tlb_entries = 32; + err = of_property_read_u32(of, "ti,#tlb-entries", &obj->nr_tlb_entries); + if (err && err != -EINVAL) + return err; + if (obj->nr_tlb_entries != 32 && obj->nr_tlb_entries != 8) + return -EINVAL; + if (of_find_property(of, "ti,iommu-bus-err-back", NULL)) + obj->has_bus_err_back = MMU_GP_REG_BUS_ERR_BACK_EN; obj->dev = &pdev->dev; obj->ctx = (void *)obj + sizeof(*obj); @@ -976,19 +943,46 @@ static int omap_iommu_probe(struct platform_device *pdev) return err; platform_set_drvdata(pdev, obj); + obj->group = iommu_group_alloc(); + if (IS_ERR(obj->group)) + return PTR_ERR(obj->group); + + err = iommu_device_sysfs_add(&obj->iommu, obj->dev, NULL, obj->name); + if (err) + goto out_group; + + iommu_device_set_ops(&obj->iommu, &omap_iommu_ops); + + err = iommu_device_register(&obj->iommu); + if (err) + goto out_sysfs; + pm_runtime_irq_safe(obj->dev); pm_runtime_enable(obj->dev); omap_iommu_debugfs_add(obj); dev_info(&pdev->dev, "%s registered\n", obj->name); + return 0; + +out_sysfs: + iommu_device_sysfs_remove(&obj->iommu); +out_group: + iommu_group_put(obj->group); + return err; } static int omap_iommu_remove(struct platform_device *pdev) { struct omap_iommu *obj = platform_get_drvdata(pdev); + iommu_group_put(obj->group); + obj->group = NULL; + + iommu_device_sysfs_remove(&obj->iommu); + iommu_device_unregister(&obj->iommu); + omap_iommu_debugfs_remove(obj); pm_runtime_disable(obj->dev); @@ -1077,11 +1071,11 @@ static int omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); - struct omap_iommu *oiommu; struct omap_iommu_arch_data *arch_data = dev->archdata.iommu; + struct omap_iommu *oiommu; int ret = 0; - if (!arch_data || !arch_data->name) { + if (!arch_data || !arch_data->iommu_dev) { dev_err(dev, "device doesn't have an associated iommu\n"); return -EINVAL; } @@ -1095,15 +1089,16 @@ omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) goto out; } + oiommu = arch_data->iommu_dev; + /* get a handle to and enable the omap iommu */ - oiommu = omap_iommu_attach(arch_data->name, omap_domain->pgtable); - if (IS_ERR(oiommu)) { - ret = PTR_ERR(oiommu); + ret = omap_iommu_attach(oiommu, omap_domain->pgtable); + if (ret) { dev_err(dev, "can't get omap iommu: %d\n", ret); goto out; } - omap_domain->iommu_dev = arch_data->iommu_dev = oiommu; + omap_domain->iommu_dev = oiommu; omap_domain->dev = dev; oiommu->domain = domain; @@ -1116,7 +1111,6 @@ static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, struct device *dev) { struct omap_iommu *oiommu = dev_to_omap_iommu(dev); - struct omap_iommu_arch_data *arch_data = dev->archdata.iommu; /* only a single device is supported per domain for now */ if (omap_domain->iommu_dev != oiommu) { @@ -1128,7 +1122,7 @@ static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, omap_iommu_detach(oiommu); - omap_domain->iommu_dev = arch_data->iommu_dev = NULL; + omap_domain->iommu_dev = NULL; omap_domain->dev = NULL; oiommu->domain = NULL; } @@ -1232,8 +1226,11 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, static int omap_iommu_add_device(struct device *dev) { struct omap_iommu_arch_data *arch_data; + struct omap_iommu *oiommu; + struct iommu_group *group; struct device_node *np; struct platform_device *pdev; + int ret; /* * Allocate the archdata iommu structure for DT-based devices. @@ -1254,15 +1251,41 @@ static int omap_iommu_add_device(struct device *dev) return -EINVAL; } + oiommu = platform_get_drvdata(pdev); + if (!oiommu) { + of_node_put(np); + return -EINVAL; + } + arch_data = kzalloc(sizeof(*arch_data), GFP_KERNEL); if (!arch_data) { of_node_put(np); return -ENOMEM; } - arch_data->name = kstrdup(dev_name(&pdev->dev), GFP_KERNEL); + ret = iommu_device_link(&oiommu->iommu, dev); + if (ret) { + kfree(arch_data); + of_node_put(np); + return ret; + } + + arch_data->iommu_dev = oiommu; dev->archdata.iommu = arch_data; + /* + * IOMMU group initialization calls into omap_iommu_device_group, which + * needs a valid dev->archdata.iommu pointer + */ + group = iommu_group_get_for_dev(dev); + if (IS_ERR(group)) { + iommu_device_unlink(&oiommu->iommu, dev); + dev->archdata.iommu = NULL; + kfree(arch_data); + return PTR_ERR(group); + } + iommu_group_put(group); + of_node_put(np); return 0; @@ -1275,8 +1298,23 @@ static void omap_iommu_remove_device(struct device *dev) if (!dev->of_node || !arch_data) return; - kfree(arch_data->name); + iommu_device_unlink(&arch_data->iommu_dev->iommu, dev); + iommu_group_remove_device(dev); + + dev->archdata.iommu = NULL; kfree(arch_data); + +} + +static struct iommu_group *omap_iommu_device_group(struct device *dev) +{ + struct omap_iommu_arch_data *arch_data = dev->archdata.iommu; + struct iommu_group *group = NULL; + + if (arch_data->iommu_dev) + group = arch_data->iommu_dev->group; + + return group; } static const struct iommu_ops omap_iommu_ops = { @@ -1290,6 +1328,7 @@ static const struct iommu_ops omap_iommu_ops = { .iova_to_phys = omap_iommu_iova_to_phys, .add_device = omap_iommu_add_device, .remove_device = omap_iommu_remove_device, + .device_group = omap_iommu_device_group, .pgsize_bitmap = OMAP_IOMMU_PGSIZES, }; @@ -1299,6 +1338,7 @@ static int __init omap_iommu_init(void) const unsigned long flags = SLAB_HWCACHE_ALIGN; size_t align = 1 << 10; /* L2 pagetable alignement */ struct device_node *np; + int ret; np = of_find_matching_node(NULL, omap_iommu_of_match); if (!np) @@ -1312,11 +1352,25 @@ static int __init omap_iommu_init(void) return -ENOMEM; iopte_cachep = p; - bus_set_iommu(&platform_bus_type, &omap_iommu_ops); - omap_iommu_debugfs_init(); - return platform_driver_register(&omap_iommu_driver); + ret = platform_driver_register(&omap_iommu_driver); + if (ret) { + pr_err("%s: failed to register driver\n", __func__); + goto fail_driver; + } + + ret = bus_set_iommu(&platform_bus_type, &omap_iommu_ops); + if (ret) + goto fail_bus; + + return 0; + +fail_bus: + platform_driver_unregister(&omap_iommu_driver); +fail_driver: + kmem_cache_destroy(iopte_cachep); + return ret; } subsys_initcall(omap_iommu_init); /* must be ready before omap3isp is probed */ diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index 59628e5017b4..6e70515e6038 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -14,6 +14,7 @@ #define _OMAP_IOMMU_H #include <linux/bitops.h> +#include <linux/iommu.h> #define for_each_iotlb_cr(obj, n, __i, cr) \ for (__i = 0; \ @@ -27,6 +28,23 @@ struct iotlb_entry { u32 endian, elsz, mixed; }; +/** + * struct omap_iommu_domain - omap iommu domain + * @pgtable: the page table + * @iommu_dev: an omap iommu device attached to this domain. only a single + * iommu device can be attached for now. + * @dev: Device using this domain. + * @lock: domain lock, should be taken when attaching/detaching + * @domain: generic domain handle used by iommu core code + */ +struct omap_iommu_domain { + u32 *pgtable; + struct omap_iommu *iommu_dev; + struct device *dev; + spinlock_t lock; + struct iommu_domain domain; +}; + struct omap_iommu { const char *name; void __iomem *regbase; @@ -50,6 +68,22 @@ struct omap_iommu { int has_bus_err_back; u32 id; + + struct iommu_device iommu; + struct iommu_group *group; +}; + +/** + * struct omap_iommu_arch_data - omap iommu private data + * @iommu_dev: handle of the iommu device + * + * This is an omap iommu private data object, which binds an iommu user + * to its iommu device. This object should be placed at the iommu user's + * dev_archdata so generic IOMMU API can be used without having to + * utilize omap-specific plumbing anymore. + */ +struct omap_iommu_arch_data { + struct omap_iommu *iommu_dev; }; struct cr_regs { diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 9afcbf79f0b0..4ba48a26b389 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -8,6 +8,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/dma-iommu.h> +#include <linux/dma-mapping.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -90,6 +91,7 @@ struct rk_iommu { void __iomem **bases; int num_mmu; int irq; + struct iommu_device iommu; struct list_head node; /* entry in rk_iommu_domain.iommus */ struct iommu_domain *domain; /* domain to which iommu is attached */ }; @@ -1032,6 +1034,7 @@ static int rk_iommu_group_set_iommudata(struct iommu_group *group, static int rk_iommu_add_device(struct device *dev) { struct iommu_group *group; + struct rk_iommu *iommu; int ret; if (!rk_iommu_is_dev_iommu_master(dev)) @@ -1054,6 +1057,10 @@ static int rk_iommu_add_device(struct device *dev) if (ret) goto err_remove_device; + iommu = rk_iommu_from_dev(dev); + if (iommu) + iommu_device_link(&iommu->iommu, dev); + iommu_group_put(group); return 0; @@ -1067,9 +1074,15 @@ err_put_group: static void rk_iommu_remove_device(struct device *dev) { + struct rk_iommu *iommu; + if (!rk_iommu_is_dev_iommu_master(dev)) return; + iommu = rk_iommu_from_dev(dev); + if (iommu) + iommu_device_unlink(&iommu->iommu, dev); + iommu_group_remove_device(dev); } @@ -1117,7 +1130,7 @@ static int rk_iommu_probe(struct platform_device *pdev) struct rk_iommu *iommu; struct resource *res; int num_res = pdev->num_resources; - int i; + int err, i; iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL); if (!iommu) @@ -1150,11 +1163,25 @@ static int rk_iommu_probe(struct platform_device *pdev) return -ENXIO; } - return 0; + err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev)); + if (err) + return err; + + iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops); + err = iommu_device_register(&iommu->iommu); + + return err; } static int rk_iommu_remove(struct platform_device *pdev) { + struct rk_iommu *iommu = platform_get_drvdata(pdev); + + if (iommu) { + iommu_device_sysfs_remove(&iommu->iommu); + iommu_device_unregister(&iommu->iommu); + } + return 0; } diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 9305964250ac..eeb19f560a05 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -15,6 +15,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/dma-mapping.h> #include <soc/tegra/ahb.h> #include <soc/tegra/mc.h> diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index aa44e11decca..853d598937f6 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -23,6 +23,7 @@ #include <linux/of_reserved_mem.h> #include <linux/sched.h> #include <linux/sizes.h> +#include <linux/dma-mapping.h> #include "mtk_vpu.h" diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 084ecf4aa9a4..0d984a28a003 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1943,30 +1943,13 @@ static void isp_detach_iommu(struct isp_device *isp) { arm_iommu_release_mapping(isp->mapping); isp->mapping = NULL; - iommu_group_remove_device(isp->dev); } static int isp_attach_iommu(struct isp_device *isp) { struct dma_iommu_mapping *mapping; - struct iommu_group *group; int ret; - /* Create a device group and add the device to it. */ - group = iommu_group_alloc(); - if (IS_ERR(group)) { - dev_err(isp->dev, "failed to allocate IOMMU group\n"); - return PTR_ERR(group); - } - - ret = iommu_group_add_device(group, isp->dev); - iommu_group_put(group); - - if (ret < 0) { - dev_err(isp->dev, "failed to add device to IPMMU group\n"); - return ret; - } - /* * Create the ARM mapping, used by the ARM DMA mapping core to allocate * VAs. This will allocate a corresponding IOMMU domain. diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 7e6f6638433b..2f2ae609c548 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -23,7 +23,6 @@ #include <linux/clk-provider.h> #include <linux/device.h> #include <linux/io.h> -#include <linux/iommu.h> #include <linux/platform_device.h> #include <linux/wait.h> diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index c502c139d3bc..47a8103610bc 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -549,7 +549,8 @@ static int bond_fill_info(struct sk_buff *skb, targets_added = 0; for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (bond->params.arp_targets[i]) { - nla_put_be32(skb, i, bond->params.arp_targets[i]); + if (nla_put_be32(skb, i, bond->params.arp_targets[i])) + goto nla_put_failure; targets_added = 1; } } diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index f0fc4de4fc9a..a19e1781e9bb 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -256,6 +256,9 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev) return -ENOMEM; ps = devm_kzalloc(&mdiodev->dev, sizeof(*ps), GFP_KERNEL); + if (!ps) + return -ENOMEM; + ps->netdev = dev_get_by_name(&init_net, pdata->netdev); if (!ps->netdev) return -EPROBE_DEFER; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index cdb02991f249..9ee1c5016784 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -755,7 +755,7 @@ void aq_nic_get_stats(struct aq_nic_s *self, u64 *data) count = 0U; for (i = 0U, aq_vec = self->aq_vec[0]; - self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) { + aq_vec && self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) { data += count; aq_vec_get_sw_stats(aq_vec, data, &count); } @@ -959,8 +959,10 @@ void aq_nic_free_hot_resources(struct aq_nic_s *self) goto err_exit; for (i = AQ_DIMOF(self->aq_vec); i--;) { - if (self->aq_vec[i]) + if (self->aq_vec[i]) { aq_vec_free(self->aq_vec[i]); + self->aq_vec[i] = NULL; + } } err_exit:; diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index a8c2db881b75..567ee54504bc 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -838,7 +838,7 @@ static int alx_enable_msix(struct alx_priv *alx) err = pci_alloc_irq_vectors(alx->hw.pdev, num_vec, num_vec, PCI_IRQ_MSIX); - if (err) { + if (err < 0) { netdev_warn(alx->dev, "Enabling MSI-X interrupts failed!\n"); return err; } @@ -904,7 +904,7 @@ static int alx_init_intr(struct alx_priv *alx) ret = pci_alloc_irq_vectors(alx->hw.pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY); - if (ret) + if (ret < 0) return ret; alx->num_vec = 1; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b3ba66032980..b56c54d68d5e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3000,7 +3000,8 @@ static int bnxt_alloc_ntp_fltrs(struct bnxt *bp) INIT_HLIST_HEAD(&bp->ntp_fltr_hash_tbl[i]); bp->ntp_fltr_count = 0; - bp->ntp_fltr_bmap = kzalloc(BITS_TO_LONGS(BNXT_NTP_FLTR_MAX_FLTR), + bp->ntp_fltr_bmap = kcalloc(BITS_TO_LONGS(BNXT_NTP_FLTR_MAX_FLTR), + sizeof(long), GFP_KERNEL); if (!bp->ntp_fltr_bmap) diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c index 0f6811860ad5..a36e38676640 100644 --- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c +++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c @@ -2845,7 +2845,7 @@ bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver) static void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer) { - memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN); + strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN); } static void diff --git a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c index 286593922139..31032de5843b 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c +++ b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c @@ -547,8 +547,8 @@ bnad_get_strings(struct net_device *netdev, u32 stringset, u8 *string) for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) { BUG_ON(!(strlen(bnad_net_stats_strings[i]) < ETH_GSTRING_LEN)); - memcpy(string, bnad_net_stats_strings[i], - ETH_GSTRING_LEN); + strncpy(string, bnad_net_stats_strings[i], + ETH_GSTRING_LEN); string += ETH_GSTRING_LEN; } bmap = bna_tx_rid_mask(&bnad->bna); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 1d2be2dd19dd..e88c1808e46f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -108,6 +108,12 @@ enum { PAUSE_AUTONEG = 1 << 2 }; +enum { + FEC_AUTO = 1 << 0, /* IEEE 802.3 "automatic" */ + FEC_RS = 1 << 1, /* Reed-Solomon */ + FEC_BASER_RS = 1 << 2 /* BaseR/Reed-Solomon */ +}; + struct port_stats { u64 tx_octets; /* total # of octets in good frames */ u64 tx_frames; /* all good frames */ @@ -432,6 +438,9 @@ struct link_config { unsigned int speed; /* actual link speed */ unsigned char requested_fc; /* flow control user has requested */ unsigned char fc; /* actual link flow control */ + unsigned char auto_fec; /* Forward Error Correction: */ + unsigned char requested_fec; /* "automatic" (IEEE 802.3), */ + unsigned char fec; /* requested, and actual in use */ unsigned char autoneg; /* autonegotiating? */ unsigned char link_ok; /* link up? */ unsigned char link_down_rc; /* link down reason */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 0de8eb72325c..aded42b96f6d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3707,7 +3707,8 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port, struct link_config *lc) { struct fw_port_cmd c; - unsigned int fc = 0, mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO); + unsigned int mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO); + unsigned int fc = 0, fec = 0, fw_fec = 0; lc->link_ok = 0; if (lc->requested_fc & PAUSE_RX) @@ -3715,6 +3716,13 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port, if (lc->requested_fc & PAUSE_TX) fc |= FW_PORT_CAP_FC_TX; + fec = lc->requested_fec & FEC_AUTO ? lc->auto_fec : lc->requested_fec; + + if (fec & FEC_RS) + fw_fec |= FW_PORT_CAP_FEC_RS; + if (fec & FEC_BASER_RS) + fw_fec |= FW_PORT_CAP_FEC_BASER_RS; + memset(&c, 0, sizeof(c)); c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | FW_CMD_REQUEST_F | FW_CMD_EXEC_F | @@ -3725,13 +3733,15 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port, if (!(lc->supported & FW_PORT_CAP_ANEG)) { c.u.l1cfg.rcap = cpu_to_be32((lc->supported & ADVERT_MASK) | - fc); + fc | fw_fec); lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); } else if (lc->autoneg == AUTONEG_DISABLE) { - c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed | fc | mdi); + c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed | fc | + fw_fec | mdi); lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); } else - c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc | mdi); + c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc | + fw_fec | mdi); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -7407,13 +7417,26 @@ static void get_pci_mode(struct adapter *adapter, struct pci_params *p) * Initializes the SW state maintained for each link, including the link's * capabilities and default speed/flow-control/autonegotiation settings. */ -static void init_link_config(struct link_config *lc, unsigned int caps) +static void init_link_config(struct link_config *lc, unsigned int pcaps, + unsigned int acaps) { - lc->supported = caps; + lc->supported = pcaps; lc->lp_advertising = 0; lc->requested_speed = 0; lc->speed = 0; lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; + lc->auto_fec = 0; + + /* For Forward Error Control, we default to whatever the Firmware + * tells us the Link is currently advertising. + */ + if (acaps & FW_PORT_CAP_FEC_RS) + lc->auto_fec |= FEC_RS; + if (acaps & FW_PORT_CAP_FEC_BASER_RS) + lc->auto_fec |= FEC_BASER_RS; + lc->requested_fec = FEC_AUTO; + lc->fec = lc->auto_fec; + if (lc->supported & FW_PORT_CAP_ANEG) { lc->advertising = lc->supported & ADVERT_MASK; lc->autoneg = AUTONEG_ENABLE; @@ -7991,7 +8014,8 @@ int t4_init_portinfo(struct port_info *pi, int mbox, pi->port_type = FW_PORT_CMD_PTYPE_G(ret); pi->mod_type = FW_PORT_MOD_TYPE_NA; - init_link_config(&pi->link_cfg, be16_to_cpu(c.u.info.pcap)); + init_link_config(&pi->link_cfg, be16_to_cpu(c.u.info.pcap), + be16_to_cpu(c.u.info.acap)); return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 8f8c079d0d2b..251a35e9795c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -2263,9 +2263,9 @@ enum fw_port_cap { FW_PORT_CAP_ANEG = 0x0100, FW_PORT_CAP_MDIX = 0x0200, FW_PORT_CAP_MDIAUTO = 0x0400, - FW_PORT_CAP_FEC = 0x0800, - FW_PORT_CAP_TECHKR = 0x1000, - FW_PORT_CAP_TECHKX4 = 0x2000, + FW_PORT_CAP_FEC_RS = 0x0800, + FW_PORT_CAP_FEC_BASER_RS = 0x1000, + FW_PORT_CAP_FEC_RESERVED = 0x2000, FW_PORT_CAP_802_3_PAUSE = 0x4000, FW_PORT_CAP_802_3_ASM_DIR = 0x8000, }; diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 0e0fa7030565..c1af47e45d3f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1789,9 +1789,17 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, } if (err) { - if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) - mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", - vhcr->op, slave, vhcr->errno, err); + if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { + if (vhcr->op == MLX4_CMD_ALLOC_RES && + (vhcr->in_modifier & 0xff) == RES_COUNTER && + err == -EDQUOT) + mlx4_dbg(dev, + "Unable to allocate counter for slave %d (%d)\n", + slave, err); + else + mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", + vhcr->op, slave, vhcr->errno, err); + } vhcr_cmd->status = mlx4_errno_to_status(err); goto out_status; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index ffbcb27c05e5..ae5fdc2df654 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1562,6 +1562,11 @@ static int mlx4_en_flow_replace(struct net_device *dev, qpn = priv->drop_qp.qpn; else if (cmd->fs.ring_cookie & EN_ETHTOOL_QP_ATTACH) { qpn = cmd->fs.ring_cookie & (EN_ETHTOOL_QP_ATTACH - 1); + if (qpn < priv->rss_map.base_qpn || + qpn >= priv->rss_map.base_qpn + priv->rx_ring_num) { + en_warn(priv, "rxnfc: QP (0x%x) doesn't exist\n", qpn); + return -EINVAL; + } } else { if (cmd->fs.ring_cookie >= priv->rx_ring_num) { en_warn(priv, "rxnfc: RX ring (%llu) doesn't exist\n", diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index aa074e57ce06..77abd1813047 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -997,7 +997,8 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) en_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d num_frags:%d):\n", eff_mtu, priv->num_frags); for (i = 0; i < priv->num_frags; i++) { - en_err(priv, + en_dbg(DRV, + priv, " frag:%d - size:%d stride:%d\n", i, priv->frag_info[i].frag_size, diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 4aa29ee93013..07516545474f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -311,7 +311,7 @@ static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, struct mlx4_priv *priv = mlx4_priv(dev); struct resource_allocator *res_alloc = &priv->mfunc.master.res_tracker.res_alloc[res_type]; - int err = -EINVAL; + int err = -EDQUOT; int allocated, free, reserved, guaranteed, from_free; int from_rsvd; diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index b3aaa985956e..694845793af2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -1460,6 +1460,7 @@ void qed_qm_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) params.is_first_pf = p_hwfn->first_on_engine; params.num_pf_cids = iids.cids; params.num_vf_cids = iids.vf_cids; + params.num_tids = iids.tids; params.start_pq = qm_info->start_pq; params.num_pf_pqs = qm_info->num_pqs - qm_info->num_vf_pqs; params.num_vf_pqs = qm_info->num_vf_pqs; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index bb70522ad362..463927f17032 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1370,7 +1370,7 @@ qed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) NULL) + qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH, NULL); - norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, 4096); + norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, PAGE_SIZE); min_addr_reg1 = norm_regsize / 4096; pwm_regsize = db_bar_size - norm_regsize; diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index c67ff1411799..537d1236a4fe 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1093,10 +1093,12 @@ static int qed_slowpath_stop(struct qed_dev *cdev) qed_free_stream_mem(cdev); if (IS_QED_ETH_IF(cdev)) qed_sriov_disable(cdev, true); + } + + qed_nic_stop(cdev); - qed_nic_stop(cdev); + if (IS_PF(cdev)) qed_slowpath_irq_free(cdev); - } qed_disable_msix(cdev); diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c index eb5652073ca8..333876c19d7d 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c @@ -1028,11 +1028,6 @@ int qede_xdp(struct net_device *dev, struct netdev_xdp *xdp) { struct qede_dev *edev = netdev_priv(dev); - if (IS_VF(edev)) { - DP_NOTICE(edev, "VFs don't support XDP\n"); - return -EOPNOTSUPP; - } - switch (xdp->command) { case XDP_SETUP_PROG: return qede_xdp_set(edev, xdp->prog); diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index b9ba23d71c61..38b77bbfe4ee 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -563,6 +563,23 @@ static const struct net_device_ops qede_netdev_ops = { #endif }; +static const struct net_device_ops qede_netdev_vf_ops = { + .ndo_open = qede_open, + .ndo_stop = qede_close, + .ndo_start_xmit = qede_start_xmit, + .ndo_set_rx_mode = qede_set_rx_mode, + .ndo_set_mac_address = qede_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = qede_change_mtu, + .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, + .ndo_set_features = qede_set_features, + .ndo_get_stats64 = qede_get_stats64, + .ndo_udp_tunnel_add = qede_udp_tunnel_add, + .ndo_udp_tunnel_del = qede_udp_tunnel_del, + .ndo_features_check = qede_features_check, +}; + /* ------------------------------------------------------------------------- * START OF PROBE / REMOVE * ------------------------------------------------------------------------- @@ -622,7 +639,10 @@ static void qede_init_ndev(struct qede_dev *edev) ndev->watchdog_timeo = TX_TIMEOUT; - ndev->netdev_ops = &qede_netdev_ops; + if (IS_VF(edev)) + ndev->netdev_ops = &qede_netdev_vf_ops; + else + ndev->netdev_ops = &qede_netdev_ops; qede_set_ethtool_ops(ndev); @@ -1313,6 +1333,9 @@ static void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) if (fp->type & QEDE_FASTPATH_RX) qede_free_mem_rxq(edev, fp->rxq); + if (fp->type & QEDE_FASTPATH_XDP) + qede_free_mem_txq(edev, fp->xdp_tx); + if (fp->type & QEDE_FASTPATH_TX) qede_free_mem_txq(edev, fp->txq); } diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c index 829be21f97b2..28ea0af89aef 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c @@ -765,7 +765,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) sizeof(struct mpi_coredump_global_header); mpi_coredump->mpi_global_header.imageSize = sizeof(struct ql_mpi_coredump); - memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", + strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", sizeof(mpi_coredump->mpi_global_header.idString)); /* Get generic NIC reg dump */ @@ -1255,7 +1255,7 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, sizeof(struct mpi_coredump_global_header); mpi_coredump->mpi_global_header.imageSize = sizeof(struct ql_reg_dump); - memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", + strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", sizeof(mpi_coredump->mpi_global_header.idString)); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 39be96779145..22f910795be4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -70,11 +70,8 @@ static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info) return -ENODEV; } -static void stmmac_default_data(struct plat_stmmacenet_data *plat) +static void common_default_data(struct plat_stmmacenet_data *plat) { - plat->bus_id = 1; - plat->phy_addr = 0; - plat->interface = PHY_INTERFACE_MODE_GMII; plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ plat->has_gmac = 1; plat->force_sf_dma_mode = 1; @@ -82,10 +79,6 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) plat->mdio_bus_data->phy_reset = NULL; plat->mdio_bus_data->phy_mask = 0; - plat->dma_cfg->pbl = 32; - plat->dma_cfg->pblx8 = true; - /* TODO: AXI */ - /* Set default value for multicast hash bins */ plat->multicast_filter_bins = HASH_TABLE_SIZE; @@ -107,12 +100,29 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) plat->rx_queues_cfg[0].pkt_route = 0x0; } +static void stmmac_default_data(struct plat_stmmacenet_data *plat) +{ + /* Set common default data first */ + common_default_data(plat); + + plat->bus_id = 1; + plat->phy_addr = 0; + plat->interface = PHY_INTERFACE_MODE_GMII; + + plat->dma_cfg->pbl = 32; + plat->dma_cfg->pblx8 = true; + /* TODO: AXI */ +} + static int quark_default_data(struct plat_stmmacenet_data *plat, struct stmmac_pci_info *info) { struct pci_dev *pdev = info->pdev; int ret; + /* Set common default data first */ + common_default_data(plat); + /* * Refuse to load the driver and register net device if MAC controller * does not connect to any PHY interface. @@ -124,27 +134,12 @@ static int quark_default_data(struct plat_stmmacenet_data *plat, plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn); plat->phy_addr = ret; plat->interface = PHY_INTERFACE_MODE_RMII; - plat->clk_csr = 2; - plat->has_gmac = 1; - plat->force_sf_dma_mode = 1; - - plat->mdio_bus_data->phy_reset = NULL; - plat->mdio_bus_data->phy_mask = 0; plat->dma_cfg->pbl = 16; plat->dma_cfg->pblx8 = true; plat->dma_cfg->fixed_burst = 1; /* AXI (TODO) */ - /* Set default value for multicast hash bins */ - plat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat->unicast_filter_entries = 1; - - /* Set the maxmtu to a default of JUMBO_LEN */ - plat->maxmtu = JUMBO_LEN; - return 0; } diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index fa674a8bda0c..f4d7aec50479 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -287,6 +287,10 @@ struct cpsw_ss_regs { /* Bit definitions for the CPSW1_TS_SEQ_LTYPE register */ #define CPSW_V1_SEQ_ID_OFS_SHIFT 16 +#define CPSW_MAX_BLKS_TX 15 +#define CPSW_MAX_BLKS_TX_SHIFT 4 +#define CPSW_MAX_BLKS_RX 5 + struct cpsw_host_regs { u32 max_blks; u32 blk_cnt; @@ -1278,11 +1282,23 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) switch (cpsw->version) { case CPSW_VERSION_1: slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS); break; case CPSW_VERSION_2: case CPSW_VERSION_3: case CPSW_VERSION_4: slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS); break; } diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index b6891ada1d7b..7a7c5224a336 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -976,12 +976,10 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCYAMSMCS: if (netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ - if ((ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_KERNEL)) == NULL) - return -ENOBUFS; - if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs))) { - kfree(ym); - return -EFAULT; - } + ym = memdup_user(ifr->ifr_data, + sizeof(struct yamdrv_ioctl_mcs)); + if (IS_ERR(ym)) + return PTR_ERR(ym); if (ym->bitrate > YAM_MAXBITRATE) { kfree(ym); return -EINVAL; diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index 9b0d6148e994..1ce6239a4849 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -1616,17 +1616,14 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EPERM; } - image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!image || !oldimage) { - error = -ENOMEM; - goto wf_out; - } + image = memdup_user(rq->ifr_data, EEPROM_BYTES); + if (IS_ERR(image)) + return PTR_ERR(image); - error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES); - if (error) { - error = -EFAULT; - goto wf_out; + oldimage = kmalloc(EEPROM_BYTES, GFP_KERNEL); + if (!oldimage) { + kfree(image); + return -ENOMEM; } if (rrpriv->fw_running){ diff --git a/drivers/net/phy/mdio-mux-bcm-iproc.c b/drivers/net/phy/mdio-mux-bcm-iproc.c index 0a0412524cec..0a5f62e0efcc 100644 --- a/drivers/net/phy/mdio-mux-bcm-iproc.c +++ b/drivers/net/phy/mdio-mux-bcm-iproc.c @@ -203,11 +203,14 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev) &md->mux_handle, md, md->mii_bus); if (rc) { dev_info(md->dev, "mdiomux initialization failed\n"); - goto out; + goto out_register; } dev_info(md->dev, "iProc mdiomux registered\n"); return 0; + +out_register: + mdiobus_unregister(bus); out: mdiobus_free(bus); return rc; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index bb3f71f9fbde..b5cec1824a78 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1088,6 +1088,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) u16 n = 0, index, ndplen; u8 ready2send = 0; u32 delayed_ndp_size; + size_t padding_count; /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated * accordingly. Otherwise, we should check here. @@ -1244,11 +1245,13 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) * a ZLP after full sized NTBs. */ if (!(dev->driver_info->flags & FLAG_SEND_ZLP) && - skb_out->len > ctx->min_tx_pkt) - memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0, - ctx->tx_max - skb_out->len); - else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0) + skb_out->len > ctx->min_tx_pkt) { + padding_count = ctx->tx_max - skb_out->len; + memset(skb_put(skb_out, padding_count), 0, padding_count); + } else if (skb_out->len < ctx->tx_max && + (skb_out->len % dev->maxpacket) == 0) { *skb_put(skb_out, 1) = 0; /* force short packet */ + } /* set final frame length */ nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h index 649ecad6844c..eff4f464a23e 100644 --- a/drivers/net/wimax/i2400m/i2400m-usb.h +++ b/drivers/net/wimax/i2400m/i2400m-usb.h @@ -131,7 +131,7 @@ static inline int edc_inc(struct edc *edc, u16 max_err, u16 timeframe) unsigned long now; now = jiffies; - if (now - edc->timestart > timeframe) { + if (time_after(now, edc->timestart + timeframe)) { edc->errorcount = 1; edc->timestart = now; } else if (++edc->errorcount > max_err) { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 68fcbe03bce2..b3f20b3c0210 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -522,7 +522,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); rxs->enc_flags |= (rxsp->status4 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0; - rxs->enc_flags |= (rxsp->status4 & AR_2040) ? RX_ENC_FLAG_40MHZ : 0; + rxs->bw = (rxsp->status4 & AR_2040) ? RATE_INFO_BW_40 : RATE_INFO_BW_20; rxs->evm0 = rxsp->status6; rxs->evm1 = rxsp->status7; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 6128c2bb23d8..77c94f9e7b61 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -580,8 +580,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, /* directly mapped flags for ieee80211_rx_status */ rs->enc_flags |= (ads.ds_rxstatus3 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0; - rs->enc_flags |= - (ads.ds_rxstatus3 & AR_2040) ? RX_ENC_FLAG_40MHZ : 0; + rs->bw = (ads.ds_rxstatus3 & AR_2040) ? RATE_INFO_BW_40 : + RATE_INFO_BW_20; if (AR_SREV_9280_20_OR_LATER(ah)) rs->enc_flags |= (ads.ds_rxstatus3 & AR_STBC) ? diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 5d5faa3cad24..49a2ff15ddae 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -734,7 +734,9 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) if (rate_n_flags & RATE_MCS_HT_MSK) rx_status.encoding = RX_ENC_HT; if (rate_n_flags & RATE_MCS_HT40_MSK) - rx_status.enc_flags |= RX_ENC_FLAG_40MHZ; + rx_status.bw = RATE_INFO_BW_40; + else + rx_status.bw = RATE_INFO_BW_20; if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index 1ee1ba9931a7..adfd6307edca 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -889,7 +889,9 @@ static void iwlagn_rx_reply_rx(struct iwl_priv *priv, if (rate_n_flags & RATE_MCS_HT_MSK) rx_status.encoding = RX_ENC_HT; if (rate_n_flags & RATE_MCS_HT40_MSK) - rx_status.enc_flags |= RX_ENC_FLAG_40MHZ; + rx_status.bw = RATE_INFO_BW_40; + else + rx_status.bw = RATE_INFO_BW_20; if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; if (rate_n_flags & RATE_MCS_GF_MSK) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 87444af20fc5..002b25cff5b6 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1201,7 +1201,13 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, rx_status.encoding = RX_ENC_HT; } if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - rx_status.enc_flags |= RX_ENC_FLAG_40MHZ; + rx_status.bw = RATE_INFO_BW_40; + else if (info->control.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + rx_status.bw = RATE_INFO_BW_80; + else if (info->control.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) + rx_status.bw = RATE_INFO_BW_160; + else + rx_status.bw = RATE_INFO_BW_20; if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; /* TODO: simulate real signal strength (and optional packet loss) */ diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c index f207c3b10482..70bfc9839bb2 100644 --- a/drivers/nvmem/meson-efuse.c +++ b/drivers/nvmem/meson-efuse.c @@ -27,7 +27,7 @@ static int meson_efuse_read(void *context, unsigned int offset, u8 *buf = val; int ret; - ret = meson_sm_call_read(buf, SM_EFUSE_READ, offset, + ret = meson_sm_call_read(buf, bytes, SM_EFUSE_READ, offset, bytes, 0, 0, 0); if (ret < 0) return ret; diff --git a/drivers/of/device.c b/drivers/of/device.c index 6e2f9113b1b7..9416d052cb89 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -82,7 +82,7 @@ int of_device_add(struct platform_device *ofdev) * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events * to fix up DMA configuration. */ -void of_dma_configure(struct device *dev, struct device_node *np) +int of_dma_configure(struct device *dev, struct device_node *np) { u64 dma_addr, paddr, size; int ret; @@ -107,7 +107,7 @@ void of_dma_configure(struct device *dev, struct device_node *np) ret = of_dma_get_range(np, &dma_addr, &paddr, &size); if (ret < 0) { dma_addr = offset = 0; - size = dev->coherent_dma_mask + 1; + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); } else { offset = PFN_DOWN(paddr - dma_addr); @@ -123,7 +123,7 @@ void of_dma_configure(struct device *dev, struct device_node *np) if (!size) { dev_err(dev, "Adjusted size 0x%llx invalid\n", size); - return; + return -EINVAL; } dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset); } @@ -144,13 +144,30 @@ void of_dma_configure(struct device *dev, struct device_node *np) coherent ? " " : " not "); iommu = of_iommu_configure(dev, np); + if (IS_ERR(iommu)) + return PTR_ERR(iommu); + dev_dbg(dev, "device is%sbehind an iommu\n", iommu ? " " : " not "); arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent); + + return 0; } EXPORT_SYMBOL_GPL(of_dma_configure); +/** + * of_dma_deconfigure - Clean up DMA configuration + * @dev: Device for which to clean up DMA configuration + * + * Clean up all configuration performed by of_dma_configure_ops() and free all + * resources that have been allocated. + */ +void of_dma_deconfigure(struct device *dev) +{ + arch_teardown_dma_ops(dev); +} + int of_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 45b413e5a444..71fecc2debfc 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_iommu.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -158,11 +159,6 @@ struct platform_device *of_device_alloc(struct device_node *np, } EXPORT_SYMBOL(of_device_alloc); -static void of_dma_deconfigure(struct device *dev) -{ - arch_teardown_dma_ops(dev); -} - /** * of_platform_device_create_pdata - Alloc, initialize and register an of_device * @np: pointer to node to create device for @@ -191,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; - of_dma_configure(&dev->dev, dev->dev.of_node); of_msi_configure(&dev->dev, dev->dev.of_node); if (of_device_add(dev) != 0) { - of_dma_deconfigure(&dev->dev); platform_device_put(dev); goto err_clear_flag; } @@ -253,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node, dev_set_name(&dev->dev, "%s", bus_id); else of_device_make_bus_id(&dev->dev); - of_dma_configure(&dev->dev, dev->dev.of_node); /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, "arm,primecell-periphid", NULL); @@ -547,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data) amba_device_unregister(to_amba_device(dev)); #endif - of_dma_deconfigure(dev); of_node_clear_flag(dev->of_node, OF_POPULATED); of_node_clear_flag(dev->of_node, OF_POPULATED_BUS); return 0; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 01eb8038fceb..19c8950c6c38 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1914,33 +1914,6 @@ static void pci_set_msi_domain(struct pci_dev *dev) dev_set_msi_domain(&dev->dev, d); } -/** - * pci_dma_configure - Setup DMA configuration - * @dev: ptr to pci_dev struct of the PCI device - * - * Function to update PCI devices's DMA configuration using the same - * info from the OF node or ACPI node of host bridge's parent (if any). - */ -static void pci_dma_configure(struct pci_dev *dev) -{ - struct device *bridge = pci_get_host_bridge_device(dev); - - if (IS_ENABLED(CONFIG_OF) && - bridge->parent && bridge->parent->of_node) { - of_dma_configure(&dev->dev, bridge->parent->of_node); - } else if (has_acpi_companion(bridge)) { - struct acpi_device *adev = to_acpi_device_node(bridge->fwnode); - enum dev_dma_attr attr = acpi_get_dma_attr(adev); - - if (attr == DEV_DMA_NOT_SUPPORTED) - dev_warn(&dev->dev, "DMA not supported.\n"); - else - acpi_dma_configure(&dev->dev, attr); - } - - pci_put_host_bridge_device(bridge); -} - void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) { int ret; @@ -1954,7 +1927,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask = 0xffffffffull; - pci_dma_configure(dev); pci_set_dma_max_seg_size(dev, 65536); pci_set_dma_seg_boundary(dev, 0xffffffff); diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index 9a25110c4a46..9ddad0815ba9 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1164,6 +1164,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD, rapl_defaults_tng), RAPL_CPU(INTEL_FAM6_ATOM_MOOREFIELD, rapl_defaults_ann), RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_ATOM_DENVERTON, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server), diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 42e37c20b361..313c10789ca2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -293,6 +293,15 @@ config PWM_MTK_DISP To compile this driver as a module, choose M here: the module will be called pwm-mtk-disp. +config PWM_MEDIATEK + tristate "MediaTek PWM support" + depends on ARCH_MEDIATEK || COMPILE_TEST + help + Generic PWM framework driver for Mediatek ARM SoC. + + To compile this driver as a module, choose M here: the module + will be called pwm-mxs. + config PWM_MXS tristate "Freescale MXS PWM support" depends on ARCH_MXS && OF diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 346a83b00f28..93da1f79a3b8 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o obj-$(CONFIG_PWM_MESON) += pwm-meson.o +obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 999187277ea5..54c6633d9b5d 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -49,172 +49,181 @@ static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip) return container_of(chip, struct atmel_hlcdc_pwm, chip); } -static int atmel_hlcdc_pwm_config(struct pwm_chip *c, - struct pwm_device *pwm, - int duty_ns, int period_ns) +static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, + struct pwm_state *state) { struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c); struct atmel_hlcdc *hlcdc = chip->hlcdc; - struct clk *new_clk = hlcdc->slow_clk; - u64 pwmcval = duty_ns * 256; - unsigned long clk_freq; - u64 clk_period_ns; - u32 pwmcfg; - int pres; - - if (!chip->errata || !chip->errata->slow_clk_erratum) { - clk_freq = clk_get_rate(new_clk); - if (!clk_freq) - return -EINVAL; + unsigned int status; + int ret; - clk_period_ns = (u64)NSEC_PER_SEC * 256; - do_div(clk_period_ns, clk_freq); - } + if (state->enabled) { + struct clk *new_clk = hlcdc->slow_clk; + u64 pwmcval = state->duty_cycle * 256; + unsigned long clk_freq; + u64 clk_period_ns; + u32 pwmcfg; + int pres; + + if (!chip->errata || !chip->errata->slow_clk_erratum) { + clk_freq = clk_get_rate(new_clk); + if (!clk_freq) + return -EINVAL; + + clk_period_ns = (u64)NSEC_PER_SEC * 256; + do_div(clk_period_ns, clk_freq); + } + + /* Errata: cannot use slow clk on some IP revisions */ + if ((chip->errata && chip->errata->slow_clk_erratum) || + clk_period_ns > state->period) { + new_clk = hlcdc->sys_clk; + clk_freq = clk_get_rate(new_clk); + if (!clk_freq) + return -EINVAL; + + clk_period_ns = (u64)NSEC_PER_SEC * 256; + do_div(clk_period_ns, clk_freq); + } + + for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) { + /* Errata: cannot divide by 1 on some IP revisions */ + if (!pres && chip->errata && + chip->errata->div1_clk_erratum) + continue; + + if ((clk_period_ns << pres) >= state->period) + break; + } - /* Errata: cannot use slow clk on some IP revisions */ - if ((chip->errata && chip->errata->slow_clk_erratum) || - clk_period_ns > period_ns) { - new_clk = hlcdc->sys_clk; - clk_freq = clk_get_rate(new_clk); - if (!clk_freq) + if (pres > ATMEL_HLCDC_PWMPS_MAX) return -EINVAL; - clk_period_ns = (u64)NSEC_PER_SEC * 256; - do_div(clk_period_ns, clk_freq); - } + pwmcfg = ATMEL_HLCDC_PWMPS(pres); - for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) { - /* Errata: cannot divide by 1 on some IP revisions */ - if (!pres && chip->errata && chip->errata->div1_clk_erratum) - continue; + if (new_clk != chip->cur_clk) { + u32 gencfg = 0; + int ret; - if ((clk_period_ns << pres) >= period_ns) - break; - } + ret = clk_prepare_enable(new_clk); + if (ret) + return ret; - if (pres > ATMEL_HLCDC_PWMPS_MAX) - return -EINVAL; + clk_disable_unprepare(chip->cur_clk); + chip->cur_clk = new_clk; - pwmcfg = ATMEL_HLCDC_PWMPS(pres); + if (new_clk == hlcdc->sys_clk) + gencfg = ATMEL_HLCDC_CLKPWMSEL; - if (new_clk != chip->cur_clk) { - u32 gencfg = 0; - int ret; + ret = regmap_update_bits(hlcdc->regmap, + ATMEL_HLCDC_CFG(0), + ATMEL_HLCDC_CLKPWMSEL, + gencfg); + if (ret) + return ret; + } - ret = clk_prepare_enable(new_clk); - if (ret) - return ret; + do_div(pwmcval, state->period); - clk_disable_unprepare(chip->cur_clk); - chip->cur_clk = new_clk; + /* + * The PWM duty cycle is configurable from 0/256 to 255/256 of + * the period cycle. Hence we can't set a duty cycle occupying + * the whole period cycle if we're asked to. + * Set it to 255 if pwmcval is greater than 256. + */ + if (pwmcval > 255) + pwmcval = 255; - if (new_clk == hlcdc->sys_clk) - gencfg = ATMEL_HLCDC_CLKPWMSEL; + pwmcfg |= ATMEL_HLCDC_PWMCVAL(pwmcval); - ret = regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(0), - ATMEL_HLCDC_CLKPWMSEL, gencfg); + if (state->polarity == PWM_POLARITY_NORMAL) + pwmcfg |= ATMEL_HLCDC_PWMPOL; + + ret = regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6), + ATMEL_HLCDC_PWMCVAL_MASK | + ATMEL_HLCDC_PWMPS_MASK | + ATMEL_HLCDC_PWMPOL, + pwmcfg); if (ret) return ret; - } - do_div(pwmcval, period_ns); - - /* - * The PWM duty cycle is configurable from 0/256 to 255/256 of the - * period cycle. Hence we can't set a duty cycle occupying the - * whole period cycle if we're asked to. - * Set it to 255 if pwmcval is greater than 256. - */ - if (pwmcval > 255) - pwmcval = 255; - - pwmcfg |= ATMEL_HLCDC_PWMCVAL(pwmcval); + ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_EN, + ATMEL_HLCDC_PWM); + if (ret) + return ret; - return regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6), - ATMEL_HLCDC_PWMCVAL_MASK | - ATMEL_HLCDC_PWMPS_MASK, - pwmcfg); -} + ret = regmap_read_poll_timeout(hlcdc->regmap, ATMEL_HLCDC_SR, + status, + status & ATMEL_HLCDC_PWM, + 10, 0); + if (ret) + return ret; + } else { + ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_DIS, + ATMEL_HLCDC_PWM); + if (ret) + return ret; -static int atmel_hlcdc_pwm_set_polarity(struct pwm_chip *c, - struct pwm_device *pwm, - enum pwm_polarity polarity) -{ - struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c); - struct atmel_hlcdc *hlcdc = chip->hlcdc; - u32 cfg = 0; + ret = regmap_read_poll_timeout(hlcdc->regmap, ATMEL_HLCDC_SR, + status, + !(status & ATMEL_HLCDC_PWM), + 10, 0); + if (ret) + return ret; - if (polarity == PWM_POLARITY_NORMAL) - cfg = ATMEL_HLCDC_PWMPOL; + clk_disable_unprepare(chip->cur_clk); + chip->cur_clk = NULL; + } - return regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6), - ATMEL_HLCDC_PWMPOL, cfg); + return 0; } -static int atmel_hlcdc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm) -{ - struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c); - struct atmel_hlcdc *hlcdc = chip->hlcdc; - u32 status; - int ret; +static const struct pwm_ops atmel_hlcdc_pwm_ops = { + .apply = atmel_hlcdc_pwm_apply, + .owner = THIS_MODULE, +}; - ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PWM); - if (ret) - return ret; +static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_at91sam9x5_errata = { + .slow_clk_erratum = true, +}; - while (true) { - ret = regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status); - if (ret) - return ret; +static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { + .div1_clk_erratum = true, +}; - if ((status & ATMEL_HLCDC_PWM) != 0) - break; +#ifdef CONFIG_PM_SLEEP +static int atmel_hlcdc_pwm_suspend(struct device *dev) +{ + struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev); - usleep_range(1, 10); - } + /* Keep the periph clock enabled if the PWM is still running. */ + if (pwm_is_enabled(&chip->chip.pwms[0])) + clk_disable_unprepare(chip->hlcdc->periph_clk); return 0; } -static void atmel_hlcdc_pwm_disable(struct pwm_chip *c, - struct pwm_device *pwm) +static int atmel_hlcdc_pwm_resume(struct device *dev) { - struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c); - struct atmel_hlcdc *hlcdc = chip->hlcdc; - u32 status; + struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev); + struct pwm_state state; int ret; - ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PWM); - if (ret) - return; + pwm_get_state(&chip->chip.pwms[0], &state); - while (true) { - ret = regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status); + /* Re-enable the periph clock it was stopped during suspend. */ + if (!state.enabled) { + ret = clk_prepare_enable(chip->hlcdc->periph_clk); if (ret) - return; - - if ((status & ATMEL_HLCDC_PWM) == 0) - break; - - usleep_range(1, 10); + return ret; } -} - -static const struct pwm_ops atmel_hlcdc_pwm_ops = { - .config = atmel_hlcdc_pwm_config, - .set_polarity = atmel_hlcdc_pwm_set_polarity, - .enable = atmel_hlcdc_pwm_enable, - .disable = atmel_hlcdc_pwm_disable, - .owner = THIS_MODULE, -}; -static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_at91sam9x5_errata = { - .slow_clk_erratum = true, -}; + return atmel_hlcdc_pwm_apply(&chip->chip, &chip->chip.pwms[0], &state); +} +#endif -static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { - .div1_clk_erratum = true, -}; +static SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops, + atmel_hlcdc_pwm_suspend, atmel_hlcdc_pwm_resume); static const struct of_device_id atmel_hlcdc_dt_ids[] = { { @@ -305,6 +314,7 @@ static struct platform_driver atmel_hlcdc_pwm_driver = { .driver = { .name = "atmel-hlcdc-pwm", .of_match_table = atmel_hlcdc_pwm_dt_ids, + .pm = &atmel_hlcdc_pwm_pm_ops, }, .probe = atmel_hlcdc_pwm_probe, .remove = atmel_hlcdc_pwm_remove, diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 67a7023be5c2..530d7dc5f1b5 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -58,17 +58,22 @@ #define PWM_MAX_PRD 0xFFFF #define PRD_MAX_PRES 10 +struct atmel_pwm_registers { + u8 period; + u8 period_upd; + u8 duty; + u8 duty_upd; +}; + struct atmel_pwm_chip { struct pwm_chip chip; struct clk *clk; void __iomem *base; + const struct atmel_pwm_registers *regs; unsigned int updated_pwms; /* ISR is cleared when read, ensure only one thread does that */ struct mutex isr_lock; - - void (*config)(struct pwm_chip *chip, struct pwm_device *pwm, - unsigned long dty, unsigned long prd); }; static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip) @@ -105,153 +110,71 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip, writel_relaxed(val, chip->base + base + offset); } -static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) +static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip, + const struct pwm_state *state, + unsigned long *cprd, u32 *pres) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - unsigned long prd, dty; - unsigned long long div; - unsigned int pres = 0; - u32 val; - int ret; - - if (pwm_is_enabled(pwm) && (period_ns != pwm_get_period(pwm))) { - dev_err(chip->dev, "cannot change PWM period while enabled\n"); - return -EBUSY; - } + unsigned long long cycles = state->period; /* Calculate the period cycles and prescale value */ - div = (unsigned long long)clk_get_rate(atmel_pwm->clk) * period_ns; - do_div(div, NSEC_PER_SEC); + cycles *= clk_get_rate(atmel_pwm->clk); + do_div(cycles, NSEC_PER_SEC); - while (div > PWM_MAX_PRD) { - div >>= 1; - pres++; - } + for (*pres = 0; cycles > PWM_MAX_PRD; cycles >>= 1) + (*pres)++; - if (pres > PRD_MAX_PRES) { + if (*pres > PRD_MAX_PRES) { dev_err(chip->dev, "pres exceeds the maximum value\n"); return -EINVAL; } - /* Calculate the duty cycles */ - prd = div; - div *= duty_ns; - do_div(div, period_ns); - dty = prd - div; - - ret = clk_enable(atmel_pwm->clk); - if (ret) { - dev_err(chip->dev, "failed to enable PWM clock\n"); - return ret; - } - - /* It is necessary to preserve CPOL, inside CMR */ - val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); - val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); - atmel_pwm->config(chip, pwm, dty, prd); - mutex_lock(&atmel_pwm->isr_lock); - atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR); - atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm); - mutex_unlock(&atmel_pwm->isr_lock); - - clk_disable(atmel_pwm->clk); - return ret; -} - -static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm, - unsigned long dty, unsigned long prd) -{ - struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - unsigned int val; - + *cprd = cycles; - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CUPD, dty); - - val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); - val &= ~PWM_CMR_UPD_CDTY; - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); - - /* - * If the PWM channel is enabled, only update CDTY by using the update - * register, it needs to set bit 10 of CMR to 0 - */ - if (pwm_is_enabled(pwm)) - return; - /* - * If the PWM channel is disabled, write value to duty and period - * registers directly. - */ - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CDTY, dty); - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CPRD, prd); + return 0; } -static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, - unsigned long dty, unsigned long prd) +static void atmel_pwm_calculate_cdty(const struct pwm_state *state, + unsigned long cprd, unsigned long *cdty) { - struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + unsigned long long cycles = state->duty_cycle; - if (pwm_is_enabled(pwm)) { - /* - * If the PWM channel is enabled, using the duty update register - * to update the value. - */ - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTYUPD, dty); - } else { - /* - * If the PWM channel is disabled, write value to duty and - * period registers directly. - */ - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTY, dty); - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CPRD, prd); - } + cycles *= cprd; + do_div(cycles, state->period); + *cdty = cprd - cycles; } -static int atmel_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, - enum pwm_polarity polarity) +static void atmel_pwm_update_cdty(struct pwm_chip *chip, struct pwm_device *pwm, + unsigned long cdty) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); u32 val; - int ret; - - val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); - if (polarity == PWM_POLARITY_NORMAL) - val &= ~PWM_CMR_CPOL; - else - val |= PWM_CMR_CPOL; - - ret = clk_enable(atmel_pwm->clk); - if (ret) { - dev_err(chip->dev, "failed to enable PWM clock\n"); - return ret; + if (atmel_pwm->regs->duty_upd == + atmel_pwm->regs->period_upd) { + val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); + val &= ~PWM_CMR_UPD_CDTY; + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); } - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); - - clk_disable(atmel_pwm->clk); - - return 0; + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, + atmel_pwm->regs->duty_upd, cdty); } -static int atmel_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +static void atmel_pwm_set_cprd_cdty(struct pwm_chip *chip, + struct pwm_device *pwm, + unsigned long cprd, unsigned long cdty) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - int ret; - - ret = clk_enable(atmel_pwm->clk); - if (ret) { - dev_err(chip->dev, "failed to enable PWM clock\n"); - return ret; - } - atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm); - - return 0; + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, + atmel_pwm->regs->duty, cdty); + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, + atmel_pwm->regs->period, cprd); } -static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm, + bool disable_clk) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); unsigned long timeout = jiffies + 2 * HZ; @@ -282,37 +205,99 @@ static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) time_before(jiffies, timeout)) usleep_range(10, 100); - clk_disable(atmel_pwm->clk); + if (disable_clk) + clk_disable(atmel_pwm->clk); +} + +static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + struct pwm_state cstate; + unsigned long cprd, cdty; + u32 pres, val; + int ret; + + pwm_get_state(pwm, &cstate); + + if (state->enabled) { + if (cstate.enabled && + cstate.polarity == state->polarity && + cstate.period == state->period) { + cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, + atmel_pwm->regs->period); + atmel_pwm_calculate_cdty(state, cprd, &cdty); + atmel_pwm_update_cdty(chip, pwm, cdty); + return 0; + } + + ret = atmel_pwm_calculate_cprd_and_pres(chip, state, &cprd, + &pres); + if (ret) { + dev_err(chip->dev, + "failed to calculate cprd and prescaler\n"); + return ret; + } + + atmel_pwm_calculate_cdty(state, cprd, &cdty); + + if (cstate.enabled) { + atmel_pwm_disable(chip, pwm, false); + } else { + ret = clk_enable(atmel_pwm->clk); + if (ret) { + dev_err(chip->dev, "failed to enable clock\n"); + return ret; + } + } + + /* It is necessary to preserve CPOL, inside CMR */ + val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); + val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); + if (state->polarity == PWM_POLARITY_NORMAL) + val &= ~PWM_CMR_CPOL; + else + val |= PWM_CMR_CPOL; + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); + atmel_pwm_set_cprd_cdty(chip, pwm, cprd, cdty); + mutex_lock(&atmel_pwm->isr_lock); + atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR); + atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm); + mutex_unlock(&atmel_pwm->isr_lock); + atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm); + } else if (cstate.enabled) { + atmel_pwm_disable(chip, pwm, true); + } + + return 0; } static const struct pwm_ops atmel_pwm_ops = { - .config = atmel_pwm_config, - .set_polarity = atmel_pwm_set_polarity, - .enable = atmel_pwm_enable, - .disable = atmel_pwm_disable, + .apply = atmel_pwm_apply, .owner = THIS_MODULE, }; -struct atmel_pwm_data { - void (*config)(struct pwm_chip *chip, struct pwm_device *pwm, - unsigned long dty, unsigned long prd); +static const struct atmel_pwm_registers atmel_pwm_regs_v1 = { + .period = PWMV1_CPRD, + .period_upd = PWMV1_CUPD, + .duty = PWMV1_CDTY, + .duty_upd = PWMV1_CUPD, }; -static const struct atmel_pwm_data atmel_pwm_data_v1 = { - .config = atmel_pwm_config_v1, -}; - -static const struct atmel_pwm_data atmel_pwm_data_v2 = { - .config = atmel_pwm_config_v2, +static const struct atmel_pwm_registers atmel_pwm_regs_v2 = { + .period = PWMV2_CPRD, + .period_upd = PWMV2_CPRDUPD, + .duty = PWMV2_CDTY, + .duty_upd = PWMV2_CDTYUPD, }; static const struct platform_device_id atmel_pwm_devtypes[] = { { .name = "at91sam9rl-pwm", - .driver_data = (kernel_ulong_t)&atmel_pwm_data_v1, + .driver_data = (kernel_ulong_t)&atmel_pwm_regs_v1, }, { .name = "sama5d3-pwm", - .driver_data = (kernel_ulong_t)&atmel_pwm_data_v2, + .driver_data = (kernel_ulong_t)&atmel_pwm_regs_v2, }, { /* sentinel */ }, @@ -322,17 +307,20 @@ MODULE_DEVICE_TABLE(platform, atmel_pwm_devtypes); static const struct of_device_id atmel_pwm_dt_ids[] = { { .compatible = "atmel,at91sam9rl-pwm", - .data = &atmel_pwm_data_v1, + .data = &atmel_pwm_regs_v1, }, { .compatible = "atmel,sama5d3-pwm", - .data = &atmel_pwm_data_v2, + .data = &atmel_pwm_regs_v2, + }, { + .compatible = "atmel,sama5d2-pwm", + .data = &atmel_pwm_regs_v2, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); -static inline const struct atmel_pwm_data * +static inline const struct atmel_pwm_registers * atmel_pwm_get_driver_data(struct platform_device *pdev) { const struct platform_device_id *id; @@ -342,18 +330,18 @@ atmel_pwm_get_driver_data(struct platform_device *pdev) id = platform_get_device_id(pdev); - return (struct atmel_pwm_data *)id->driver_data; + return (struct atmel_pwm_registers *)id->driver_data; } static int atmel_pwm_probe(struct platform_device *pdev) { - const struct atmel_pwm_data *data; + const struct atmel_pwm_registers *regs; struct atmel_pwm_chip *atmel_pwm; struct resource *res; int ret; - data = atmel_pwm_get_driver_data(pdev); - if (!data) + regs = atmel_pwm_get_driver_data(pdev); + if (!regs) return -ENODEV; atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL); @@ -385,7 +373,7 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->chip.base = -1; atmel_pwm->chip.npwm = 4; - atmel_pwm->config = data->config; + atmel_pwm->regs = regs; atmel_pwm->updated_pwms = 0; mutex_init(&atmel_pwm->isr_lock); diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c new file mode 100644 index 000000000000..5c11bc708a3c --- /dev/null +++ b/drivers/pwm/pwm-mediatek.c @@ -0,0 +1,219 @@ +/* + * Mediatek Pulse Width Modulator driver + * + * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> +#include <linux/types.h> + +/* PWM registers and bits definitions */ +#define PWMCON 0x00 +#define PWMHDUR 0x04 +#define PWMLDUR 0x08 +#define PWMGDUR 0x0c +#define PWMWAVENUM 0x28 +#define PWMDWIDTH 0x2c +#define PWMTHRES 0x30 + +enum { + MTK_CLK_MAIN = 0, + MTK_CLK_TOP, + MTK_CLK_PWM1, + MTK_CLK_PWM2, + MTK_CLK_PWM3, + MTK_CLK_PWM4, + MTK_CLK_PWM5, + MTK_CLK_MAX, +}; + +static const char * const mtk_pwm_clk_name[] = { + "main", "top", "pwm1", "pwm2", "pwm3", "pwm4", "pwm5" +}; + +/** + * struct mtk_pwm_chip - struct representing PWM chip + * @chip: linux PWM chip representation + * @regs: base address of PWM chip + * @clks: list of clocks + */ +struct mtk_pwm_chip { + struct pwm_chip chip; + void __iomem *regs; + struct clk *clks[MTK_CLK_MAX]; +}; + +static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct mtk_pwm_chip, chip); +} + +static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, + unsigned int offset) +{ + return readl(chip->regs + 0x10 + (num * 0x40) + offset); +} + +static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, + unsigned int num, unsigned int offset, + u32 value) +{ + writel(value, chip->regs + 0x10 + (num * 0x40) + offset); +} + +static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]; + u32 resolution, clkdiv = 0; + + resolution = NSEC_PER_SEC / clk_get_rate(clk); + + while (period_ns / resolution > 8191) { + resolution *= 2; + clkdiv++; + } + + if (clkdiv > 7) + return -EINVAL; + + mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv); + mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); + mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); + + return 0; +} + +static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + u32 value; + int ret; + + ret = clk_prepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); + if (ret < 0) + return ret; + + value = readl(pc->regs); + value |= BIT(pwm->hwpwm); + writel(value, pc->regs); + + return 0; +} + +static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + u32 value; + + value = readl(pc->regs); + value &= ~BIT(pwm->hwpwm); + writel(value, pc->regs); + + clk_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); +} + +static const struct pwm_ops mtk_pwm_ops = { + .config = mtk_pwm_config, + .enable = mtk_pwm_enable, + .disable = mtk_pwm_disable, + .owner = THIS_MODULE, +}; + +static int mtk_pwm_probe(struct platform_device *pdev) +{ + struct mtk_pwm_chip *pc; + struct resource *res; + unsigned int i; + int ret; + + pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pc->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pc->regs)) + return PTR_ERR(pc->regs); + + for (i = 0; i < MTK_CLK_MAX; i++) { + pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); + if (IS_ERR(pc->clks[i])) + return PTR_ERR(pc->clks[i]); + } + + ret = clk_prepare(pc->clks[MTK_CLK_TOP]); + if (ret < 0) + return ret; + + ret = clk_prepare(pc->clks[MTK_CLK_MAIN]); + if (ret < 0) + goto disable_clk_top; + + platform_set_drvdata(pdev, pc); + + pc->chip.dev = &pdev->dev; + pc->chip.ops = &mtk_pwm_ops; + pc->chip.base = -1; + pc->chip.npwm = 5; + + ret = pwmchip_add(&pc->chip); + if (ret < 0) { + dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); + goto disable_clk_main; + } + + return 0; + +disable_clk_main: + clk_unprepare(pc->clks[MTK_CLK_MAIN]); +disable_clk_top: + clk_unprepare(pc->clks[MTK_CLK_TOP]); + + return ret; +} + +static int mtk_pwm_remove(struct platform_device *pdev) +{ + struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < pc->chip.npwm; i++) + pwm_disable(&pc->chip.pwms[i]); + + return pwmchip_remove(&pc->chip); +} + +static const struct of_device_id mtk_pwm_of_match[] = { + { .compatible = "mediatek,mt7623-pwm" }, + { } +}; +MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); + +static struct platform_driver mtk_pwm_driver = { + .driver = { + .name = "mtk-pwm", + .of_match_table = mtk_pwm_of_match, + }, + .probe = mtk_pwm_probe, + .remove = mtk_pwm_remove, +}; +module_platform_driver(mtk_pwm_driver); + +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +MODULE_ALIAS("platform:mtk-pwm"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 0cfb3571a732..5f55cfab9b1c 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -30,6 +30,7 @@ #include <linux/regmap.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/pm_runtime.h> /* * Because the PCA9685 has only one prescaler per chip, changing the period of @@ -79,7 +80,6 @@ struct pca9685 { struct pwm_chip chip; struct regmap *regmap; - int active_cnt; int duty_ns; int period_ns; #if IS_ENABLED(CONFIG_GPIOLIB) @@ -111,20 +111,10 @@ static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset) pwm_set_chip_data(pwm, (void *)1); mutex_unlock(&pca->lock); + pm_runtime_get_sync(pca->chip.dev); return 0; } -static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset) -{ - struct pca9685 *pca = gpiochip_get_data(gpio); - struct pwm_device *pwm; - - mutex_lock(&pca->lock); - pwm = &pca->chip.pwms[offset]; - pwm_set_chip_data(pwm, NULL); - mutex_unlock(&pca->lock); -} - static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm) { bool is_gpio = false; @@ -177,6 +167,19 @@ static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset, regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), on); } +static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset) +{ + struct pca9685 *pca = gpiochip_get_data(gpio); + struct pwm_device *pwm; + + pca9685_pwm_gpio_set(gpio, offset, 0); + pm_runtime_put(pca->chip.dev); + mutex_lock(&pca->lock); + pwm = &pca->chip.pwms[offset]; + pwm_set_chip_data(pwm, NULL); + mutex_unlock(&pca->lock); +} + static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { @@ -238,6 +241,16 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca) } #endif +static void pca9685_set_sleep_mode(struct pca9685 *pca, int sleep) +{ + regmap_update_bits(pca->regmap, PCA9685_MODE1, + MODE1_SLEEP, sleep ? MODE1_SLEEP : 0); + if (!sleep) { + /* Wait 500us for the oscillator to be back up */ + udelay(500); + } +} + static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { @@ -252,19 +265,20 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (prescale >= PCA9685_PRESCALE_MIN && prescale <= PCA9685_PRESCALE_MAX) { + /* + * putting the chip briefly into SLEEP mode + * at this point won't interfere with the + * pm_runtime framework, because the pm_runtime + * state is guaranteed active here. + */ /* Put chip into sleep mode */ - regmap_update_bits(pca->regmap, PCA9685_MODE1, - MODE1_SLEEP, MODE1_SLEEP); + pca9685_set_sleep_mode(pca, 1); /* Change the chip-wide output frequency */ regmap_write(pca->regmap, PCA9685_PRESCALE, prescale); /* Wake the chip up */ - regmap_update_bits(pca->regmap, PCA9685_MODE1, - MODE1_SLEEP, 0x0); - - /* Wait 500us for the oscillator to be back up */ - udelay(500); + pca9685_set_sleep_mode(pca, 0); pca->period_ns = period_ns; } else { @@ -406,21 +420,15 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) if (pca9685_pwm_is_gpio(pca, pwm)) return -EBUSY; - - if (pca->active_cnt++ == 0) - return regmap_update_bits(pca->regmap, PCA9685_MODE1, - MODE1_SLEEP, 0x0); + pm_runtime_get_sync(chip->dev); return 0; } static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { - struct pca9685 *pca = to_pca(chip); - - if (--pca->active_cnt == 0) - regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP, - MODE1_SLEEP); + pca9685_pwm_disable(chip, pwm); + pm_runtime_put(chip->dev); } static const struct pwm_ops pca9685_pwm_ops = { @@ -492,22 +500,54 @@ static int pca9685_pwm_probe(struct i2c_client *client, return ret; ret = pca9685_pwm_gpio_probe(pca); - if (ret < 0) + if (ret < 0) { pwmchip_remove(&pca->chip); + return ret; + } + + /* the chip comes out of power-up in the active state */ + pm_runtime_set_active(&client->dev); + /* + * enable will put the chip into suspend, which is what we + * want as all outputs are disabled at this point + */ + pm_runtime_enable(&client->dev); - return ret; + return 0; } static int pca9685_pwm_remove(struct i2c_client *client) { struct pca9685 *pca = i2c_get_clientdata(client); + int ret; - regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP, - MODE1_SLEEP); + ret = pwmchip_remove(&pca->chip); + if (ret) + return ret; + pm_runtime_disable(&client->dev); + return 0; +} - return pwmchip_remove(&pca->chip); +#ifdef CONFIG_PM +static int pca9685_pwm_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pca9685 *pca = i2c_get_clientdata(client); + + pca9685_set_sleep_mode(pca, 1); + return 0; } +static int pca9685_pwm_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pca9685 *pca = i2c_get_clientdata(client); + + pca9685_set_sleep_mode(pca, 0); + return 0; +} +#endif + static const struct i2c_device_id pca9685_id[] = { { "pca9685", 0 }, { /* sentinel */ }, @@ -530,11 +570,17 @@ static const struct of_device_id pca9685_dt_ids[] = { MODULE_DEVICE_TABLE(of, pca9685_dt_ids); #endif +static const struct dev_pm_ops pca9685_pwm_pm = { + SET_RUNTIME_PM_OPS(pca9685_pwm_runtime_suspend, + pca9685_pwm_runtime_resume, NULL) +}; + static struct i2c_driver pca9685_i2c_driver = { .driver = { .name = "pca9685-pwm", .acpi_match_table = ACPI_PTR(pca9685_acpi_ids), .of_match_table = of_match_ptr(pca9685_dt_ids), + .pm = &pca9685_pwm_pm, }, .probe = pca9685_pwm_probe, .remove = pca9685_pwm_remove, diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index e4647840cd6e..8c6ed556db28 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -29,6 +29,7 @@ #include <linux/of_device.h> #include <linux/pwm.h> #include <linux/platform_device.h> +#include <linux/pinctrl/consumer.h> #include <linux/slab.h> #include <linux/reset.h> @@ -49,6 +50,8 @@ struct tegra_pwm_chip { struct clk *clk; struct reset_control*rst; + unsigned long clk_rate; + void __iomem *regs; const struct tegra_pwm_soc *soc; @@ -74,8 +77,8 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); - unsigned long long c = duty_ns; - unsigned long rate, hz; + unsigned long long c = duty_ns, hz; + unsigned long rate; u32 val = 0; int err; @@ -85,8 +88,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * nearest integer during division. */ c *= (1 << PWM_DUTY_WIDTH); - c += period_ns / 2; - do_div(c, period_ns); + c = DIV_ROUND_CLOSEST_ULL(c, period_ns); val = (u32)c << PWM_DUTY_SHIFT; @@ -94,10 +96,11 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * Compute the prescaler value for which (1 << PWM_DUTY_WIDTH) * cycles at the PWM clock rate will take period_ns nanoseconds. */ - rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH; - hz = NSEC_PER_SEC / period_ns; + rate = pc->clk_rate >> PWM_DUTY_WIDTH; - rate = (rate + (hz / 2)) / hz; + /* Consider precision in PWM_SCALE_WIDTH rate calculation */ + hz = DIV_ROUND_CLOSEST_ULL(100ULL * NSEC_PER_SEC, period_ns); + rate = DIV_ROUND_CLOSEST_ULL(100ULL * rate, hz); /* * Since the actual PWM divider is the register's frequency divider @@ -198,6 +201,9 @@ static int tegra_pwm_probe(struct platform_device *pdev) if (IS_ERR(pwm->clk)) return PTR_ERR(pwm->clk); + /* Read PWM clock rate from source */ + pwm->clk_rate = clk_get_rate(pwm->clk); + pwm->rst = devm_reset_control_get(&pdev->dev, "pwm"); if (IS_ERR(pwm->rst)) { ret = PTR_ERR(pwm->rst); @@ -253,6 +259,18 @@ static int tegra_pwm_remove(struct platform_device *pdev) return pwmchip_remove(&pc->chip); } +#ifdef CONFIG_PM_SLEEP +static int tegra_pwm_suspend(struct device *dev) +{ + return pinctrl_pm_select_sleep_state(dev); +} + +static int tegra_pwm_resume(struct device *dev) +{ + return pinctrl_pm_select_default_state(dev); +} +#endif + static const struct tegra_pwm_soc tegra20_pwm_soc = { .num_channels = 4, }; @@ -269,10 +287,15 @@ static const struct of_device_id tegra_pwm_of_match[] = { MODULE_DEVICE_TABLE(of, tegra_pwm_of_match); +static const struct dev_pm_ops tegra_pwm_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_pwm_suspend, tegra_pwm_resume) +}; + static struct platform_driver tegra_pwm_driver = { .driver = { .name = "tegra-pwm", .of_match_table = tegra_pwm_of_match, + .pm = &tegra_pwm_pm_ops, }, .probe = tegra_pwm_probe, .remove = tegra_pwm_remove, diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index f4cdfe94b9ec..d21c07ccc94e 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -14,6 +14,13 @@ menuconfig RESET_CONTROLLER if RESET_CONTROLLER +config RESET_A10SR + tristate "Altera Arria10 System Resource Reset" + depends on MFD_ALTERA_A10SR + help + This option enables support for the external reset functions for + peripheral PHYs on the Altera Arria10 System Resource Chip. + config RESET_ATH79 bool "AR71xx Reset Driver" if COMPILE_TEST default ATH79 @@ -27,6 +34,13 @@ config RESET_BERLIN help This enables the reset controller driver for Marvell Berlin SoCs. +config RESET_IMX7 + bool "i.MX7 Reset Driver" if COMPILE_TEST + default SOC_IMX7D + select MFD_SYSCON + help + This enables the reset controller driver for i.MX7 SoCs. + config RESET_LPC18XX bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST default ARCH_LPC18XX diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 2cd3f6c45165..02a74db94339 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -2,8 +2,10 @@ obj-y += core.o obj-y += hisilicon/ obj-$(CONFIG_ARCH_STI) += sti/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ +obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o obj-$(CONFIG_RESET_ATH79) += reset-ath79.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o +obj-$(CONFIG_RESET_IMX7) += reset-imx7.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o @@ -15,3 +17,4 @@ obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o + diff --git a/drivers/reset/reset-a10sr.c b/drivers/reset/reset-a10sr.c new file mode 100644 index 000000000000..37496bd27fa2 --- /dev/null +++ b/drivers/reset/reset-a10sr.c @@ -0,0 +1,138 @@ +/* + * Copyright Intel Corporation (C) 2017. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + * Reset driver for Altera Arria10 MAX5 System Resource Chip + * + * Adapted from reset-socfpga.c + */ + +#include <linux/err.h> +#include <linux/mfd/altera-a10sr.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> + +#include <dt-bindings/reset/altr,rst-mgr-a10sr.h> + +struct a10sr_reset { + struct reset_controller_dev rcdev; + struct regmap *regmap; +}; + +static inline struct a10sr_reset *to_a10sr_rst(struct reset_controller_dev *rc) +{ + return container_of(rc, struct a10sr_reset, rcdev); +} + +static inline int a10sr_reset_shift(unsigned long id) +{ + switch (id) { + case A10SR_RESET_ENET_HPS: + return 1; + case A10SR_RESET_PCIE: + case A10SR_RESET_FILE: + case A10SR_RESET_BQSPI: + case A10SR_RESET_USB: + return id + 11; + default: + return -EINVAL; + } +} + +static int a10sr_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct a10sr_reset *a10r = to_a10sr_rst(rcdev); + int offset = a10sr_reset_shift(id); + u8 mask = ALTR_A10SR_REG_BIT_MASK(offset); + int index = ALTR_A10SR_HPS_RST_REG + ALTR_A10SR_REG_OFFSET(offset); + + return regmap_update_bits(a10r->regmap, index, mask, assert ? 0 : mask); +} + +static int a10sr_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return a10sr_reset_update(rcdev, id, true); +} + +static int a10sr_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return a10sr_reset_update(rcdev, id, false); +} + +static int a10sr_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + struct a10sr_reset *a10r = to_a10sr_rst(rcdev); + int offset = a10sr_reset_shift(id); + u8 mask = ALTR_A10SR_REG_BIT_MASK(offset); + int index = ALTR_A10SR_HPS_RST_REG + ALTR_A10SR_REG_OFFSET(offset); + unsigned int value; + + ret = regmap_read(a10r->regmap, index, &value); + if (ret < 0) + return ret; + + return !!(value & mask); +} + +static const struct reset_control_ops a10sr_reset_ops = { + .assert = a10sr_reset_assert, + .deassert = a10sr_reset_deassert, + .status = a10sr_reset_status, +}; + +static int a10sr_reset_probe(struct platform_device *pdev) +{ + struct altr_a10sr *a10sr = dev_get_drvdata(pdev->dev.parent); + struct a10sr_reset *a10r; + + a10r = devm_kzalloc(&pdev->dev, sizeof(struct a10sr_reset), + GFP_KERNEL); + if (!a10r) + return -ENOMEM; + + a10r->rcdev.owner = THIS_MODULE; + a10r->rcdev.nr_resets = A10SR_RESET_NUM; + a10r->rcdev.ops = &a10sr_reset_ops; + a10r->rcdev.of_node = pdev->dev.of_node; + a10r->regmap = a10sr->regmap; + + platform_set_drvdata(pdev, a10r); + + return devm_reset_controller_register(&pdev->dev, &a10r->rcdev); +} + +static const struct of_device_id a10sr_reset_of_match[] = { + { .compatible = "altr,a10sr-reset" }, + { }, +}; +MODULE_DEVICE_TABLE(of, a10sr_reset_of_match); + +static struct platform_driver a10sr_reset_driver = { + .probe = a10sr_reset_probe, + .driver = { + .name = "altr_a10sr_reset", + }, +}; +module_platform_driver(a10sr_reset_driver); + +MODULE_AUTHOR("Thor Thayer <thor.thayer@linux.intel.com>"); +MODULE_DESCRIPTION("Altera Arria10 System Resource Reset Controller Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c index 6b97631f5489..2674880e5492 100644 --- a/drivers/reset/reset-ath79.c +++ b/drivers/reset/reset-ath79.c @@ -1,4 +1,7 @@ /* + * AR71xx Reset Controller Driver + * Author: Alban Bedel + * * Copyright (C) 2015 Alban Bedel <albeu@free.fr> * * This program is free software; you can redistribute it and/or modify @@ -13,7 +16,7 @@ */ #include <linux/io.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/reboot.h> @@ -127,31 +130,17 @@ static int ath79_reset_probe(struct platform_device *pdev) return 0; } -static int ath79_reset_remove(struct platform_device *pdev) -{ - struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); - - unregister_restart_handler(&ath79_reset->restart_nb); - - return 0; -} - static const struct of_device_id ath79_reset_dt_ids[] = { { .compatible = "qca,ar7100-reset", }, { }, }; -MODULE_DEVICE_TABLE(of, ath79_reset_dt_ids); static struct platform_driver ath79_reset_driver = { .probe = ath79_reset_probe, - .remove = ath79_reset_remove, .driver = { - .name = "ath79-reset", - .of_match_table = ath79_reset_dt_ids, + .name = "ath79-reset", + .of_match_table = ath79_reset_dt_ids, + .suppress_bind_attrs = true, }, }; -module_platform_driver(ath79_reset_driver); - -MODULE_AUTHOR("Alban Bedel <albeu@free.fr>"); -MODULE_DESCRIPTION("AR71xx Reset Controller Driver"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(ath79_reset_driver); diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c new file mode 100644 index 000000000000..4db177bc89bc --- /dev/null +++ b/drivers/reset/reset-imx7.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 System Reset Controller (SRC) driver + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/regmap.h> +#include <dt-bindings/reset/imx7-reset.h> + +struct imx7_src { + struct reset_controller_dev rcdev; + struct regmap *regmap; +}; + +enum imx7_src_registers { + SRC_A7RCR0 = 0x0004, + SRC_M4RCR = 0x000c, + SRC_ERCR = 0x0014, + SRC_HSICPHY_RCR = 0x001c, + SRC_USBOPHY1_RCR = 0x0020, + SRC_USBOPHY2_RCR = 0x0024, + SRC_MIPIPHY_RCR = 0x0028, + SRC_PCIEPHY_RCR = 0x002c, + SRC_DDRC_RCR = 0x1000, +}; + +struct imx7_src_signal { + unsigned int offset, bit; +}; + +static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = { + [IMX7_RESET_A7_CORE_POR_RESET0] = { SRC_A7RCR0, BIT(0) }, + [IMX7_RESET_A7_CORE_POR_RESET1] = { SRC_A7RCR0, BIT(1) }, + [IMX7_RESET_A7_CORE_RESET0] = { SRC_A7RCR0, BIT(4) }, + [IMX7_RESET_A7_CORE_RESET1] = { SRC_A7RCR0, BIT(5) }, + [IMX7_RESET_A7_DBG_RESET0] = { SRC_A7RCR0, BIT(8) }, + [IMX7_RESET_A7_DBG_RESET1] = { SRC_A7RCR0, BIT(9) }, + [IMX7_RESET_A7_ETM_RESET0] = { SRC_A7RCR0, BIT(12) }, + [IMX7_RESET_A7_ETM_RESET1] = { SRC_A7RCR0, BIT(13) }, + [IMX7_RESET_A7_SOC_DBG_RESET] = { SRC_A7RCR0, BIT(20) }, + [IMX7_RESET_A7_L2RESET] = { SRC_A7RCR0, BIT(21) }, + [IMX7_RESET_SW_M4C_RST] = { SRC_M4RCR, BIT(1) }, + [IMX7_RESET_SW_M4P_RST] = { SRC_M4RCR, BIT(2) }, + [IMX7_RESET_EIM_RST] = { SRC_ERCR, BIT(0) }, + [IMX7_RESET_HSICPHY_PORT_RST] = { SRC_HSICPHY_RCR, BIT(1) }, + [IMX7_RESET_USBPHY1_POR] = { SRC_USBOPHY1_RCR, BIT(0) }, + [IMX7_RESET_USBPHY1_PORT_RST] = { SRC_USBOPHY1_RCR, BIT(1) }, + [IMX7_RESET_USBPHY2_POR] = { SRC_USBOPHY2_RCR, BIT(0) }, + [IMX7_RESET_USBPHY2_PORT_RST] = { SRC_USBOPHY2_RCR, BIT(1) }, + [IMX7_RESET_MIPI_PHY_MRST] = { SRC_MIPIPHY_RCR, BIT(1) }, + [IMX7_RESET_MIPI_PHY_SRST] = { SRC_MIPIPHY_RCR, BIT(2) }, + [IMX7_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR, BIT(2) | BIT(1) }, + [IMX7_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) }, + [IMX7_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) }, + [IMX7_RESET_DDRC_PRST] = { SRC_DDRC_RCR, BIT(0) }, + [IMX7_RESET_DDRC_CORE_RST] = { SRC_DDRC_RCR, BIT(1) }, +}; + +static struct imx7_src *to_imx7_src(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct imx7_src, rcdev); +} + +static int imx7_reset_set(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct imx7_src *imx7src = to_imx7_src(rcdev); + const struct imx7_src_signal *signal = &imx7_src_signals[id]; + unsigned int value = 0; + + switch (id) { + case IMX7_RESET_PCIEPHY: + /* + * wait for more than 10us to release phy g_rst and + * btnrst + */ + if (!assert) + udelay(10); + break; + + case IMX7_RESET_PCIE_CTRL_APPS_EN: + value = (assert) ? 0 : signal->bit; + break; + } + + return regmap_update_bits(imx7src->regmap, + signal->offset, signal->bit, value); +} + +static int imx7_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return imx7_reset_set(rcdev, id, true); +} + +static int imx7_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return imx7_reset_set(rcdev, id, false); +} + +static const struct reset_control_ops imx7_reset_ops = { + .assert = imx7_reset_assert, + .deassert = imx7_reset_deassert, +}; + +static int imx7_reset_probe(struct platform_device *pdev) +{ + struct imx7_src *imx7src; + struct device *dev = &pdev->dev; + struct regmap_config config = { .name = "src" }; + + imx7src = devm_kzalloc(dev, sizeof(*imx7src), GFP_KERNEL); + if (!imx7src) + return -ENOMEM; + + imx7src->regmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(imx7src->regmap)) { + dev_err(dev, "Unable to get imx7-src regmap"); + return PTR_ERR(imx7src->regmap); + } + regmap_attach_dev(dev, imx7src->regmap, &config); + + imx7src->rcdev.owner = THIS_MODULE; + imx7src->rcdev.nr_resets = IMX7_RESET_NUM; + imx7src->rcdev.ops = &imx7_reset_ops; + imx7src->rcdev.of_node = dev->of_node; + + return devm_reset_controller_register(dev, &imx7src->rcdev); +} + +static const struct of_device_id imx7_reset_dt_ids[] = { + { .compatible = "fsl,imx7d-src", }, + { /* sentinel */ }, +}; + +static struct platform_driver imx7_reset_driver = { + .probe = imx7_reset_probe, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = imx7_reset_dt_ids, + }, +}; +builtin_platform_driver(imx7_reset_driver); diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index c32f11a30c5f..a8b915eb8b58 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -1,4 +1,6 @@ /* + * Amlogic Meson Reset Controller driver + * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * @@ -53,7 +55,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <linux/err.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/io.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -95,7 +97,6 @@ static const struct of_device_id meson_reset_dt_ids[] = { { .compatible = "amlogic,meson-gxbb-reset", }, { /* sentinel */ }, }; -MODULE_DEVICE_TABLE(of, meson_reset_dt_ids); static int meson_reset_probe(struct platform_device *pdev) { @@ -128,9 +129,4 @@ static struct platform_driver meson_reset_driver = { .of_match_table = meson_reset_dt_ids, }, }; - -module_platform_driver(meson_reset_driver); - -MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); -MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver"); -MODULE_LICENSE("Dual BSD/GPL"); +builtin_platform_driver(meson_reset_driver); diff --git a/drivers/reset/reset-oxnas.c b/drivers/reset/reset-oxnas.c index 0d9036dea010..cf5b9742b86e 100644 --- a/drivers/reset/reset-oxnas.c +++ b/drivers/reset/reset-oxnas.c @@ -18,7 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/err.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> @@ -83,7 +83,6 @@ static const struct of_device_id oxnas_reset_dt_ids[] = { { .compatible = "oxsemi,ox820-reset", }, { /* sentinel */ }, }; -MODULE_DEVICE_TABLE(of, oxnas_reset_dt_ids); static int oxnas_reset_probe(struct platform_device *pdev) { @@ -123,5 +122,4 @@ static struct platform_driver oxnas_reset_driver = { .of_match_table = oxnas_reset_dt_ids, }, }; - -module_platform_driver(oxnas_reset_driver); +builtin_platform_driver(oxnas_reset_driver); diff --git a/drivers/reset/reset-pistachio.c b/drivers/reset/reset-pistachio.c index bbc4c06dd33b..11d651b44e81 100644 --- a/drivers/reset/reset-pistachio.c +++ b/drivers/reset/reset-pistachio.c @@ -10,7 +10,7 @@ * version 2, as published by the Free Software Foundation. */ -#include <linux/module.h> +#include <linux/init.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -128,7 +128,6 @@ static const struct of_device_id pistachio_reset_dt_ids[] = { { .compatible = "img,pistachio-reset", }, { /* sentinel */ }, }; -MODULE_DEVICE_TABLE(of, pistachio_reset_dt_ids); static struct platform_driver pistachio_reset_driver = { .probe = pistachio_reset_probe, @@ -137,8 +136,4 @@ static struct platform_driver pistachio_reset_driver = { .of_match_table = pistachio_reset_dt_ids, }, }; -module_platform_driver(pistachio_reset_driver); - -MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); -MODULE_DESCRIPTION("Pistacho Reset Controller Driver"); -MODULE_LICENSE("GPL v2"); +builtin_platform_driver(pistachio_reset_driver); diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index 43e4a9f39b9b..07224c019892 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -25,7 +25,8 @@ #include <linux/spinlock.h> #include <linux/types.h> -#define NR_BANKS 4 +#define BANK_INCREMENT 4 +#define NR_BANKS 8 struct socfpga_reset_data { spinlock_t lock; @@ -46,8 +47,8 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev, spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + (bank * NR_BANKS)); - writel(reg | BIT(offset), data->membase + (bank * NR_BANKS)); + reg = readl(data->membase + (bank * BANK_INCREMENT)); + writel(reg | BIT(offset), data->membase + (bank * BANK_INCREMENT)); spin_unlock_irqrestore(&data->lock, flags); return 0; @@ -67,8 +68,8 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev, spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + (bank * NR_BANKS)); - writel(reg & ~BIT(offset), data->membase + (bank * NR_BANKS)); + reg = readl(data->membase + (bank * BANK_INCREMENT)); + writel(reg & ~BIT(offset), data->membase + (bank * BANK_INCREMENT)); spin_unlock_irqrestore(&data->lock, flags); @@ -84,7 +85,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev, int offset = id % BITS_PER_LONG; u32 reg; - reg = readl(data->membase + (bank * NR_BANKS)); + reg = readl(data->membase + (bank * BANK_INCREMENT)); return !(reg & BIT(offset)); } diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c index b44f6b5f87b6..cd585cd2f04d 100644 --- a/drivers/reset/reset-sunxi.c +++ b/drivers/reset/reset-sunxi.c @@ -34,15 +34,16 @@ static int sunxi_reset_assert(struct reset_controller_dev *rcdev, struct sunxi_reset_data *data = container_of(rcdev, struct sunxi_reset_data, rcdev); - int bank = id / BITS_PER_LONG; - int offset = id % BITS_PER_LONG; + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); unsigned long flags; u32 reg; spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + (bank * 4)); - writel(reg & ~BIT(offset), data->membase + (bank * 4)); + reg = readl(data->membase + (bank * reg_width)); + writel(reg & ~BIT(offset), data->membase + (bank * reg_width)); spin_unlock_irqrestore(&data->lock, flags); @@ -55,15 +56,16 @@ static int sunxi_reset_deassert(struct reset_controller_dev *rcdev, struct sunxi_reset_data *data = container_of(rcdev, struct sunxi_reset_data, rcdev); - int bank = id / BITS_PER_LONG; - int offset = id % BITS_PER_LONG; + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); unsigned long flags; u32 reg; spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + (bank * 4)); - writel(reg | BIT(offset), data->membase + (bank * 4)); + reg = readl(data->membase + (bank * reg_width)); + writel(reg | BIT(offset), data->membase + (bank * reg_width)); spin_unlock_irqrestore(&data->lock, flags); diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index 9c11be3d3450..c4ba89832796 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -50,6 +50,15 @@ struct uniphier_reset_data { } /* System reset data */ +#define UNIPHIER_SLD3_SYS_RESET_NAND(id) \ + UNIPHIER_RESETX((id), 0x2004, 2) + +#define UNIPHIER_LD11_SYS_RESET_NAND(id) \ + UNIPHIER_RESETX((id), 0x200c, 0) + +#define UNIPHIER_LD11_SYS_RESET_EMMC(id) \ + UNIPHIER_RESETX((id), 0x200c, 2) + #define UNIPHIER_SLD3_SYS_RESET_STDMAC(id) \ UNIPHIER_RESETX((id), 0x2000, 10) @@ -65,12 +74,14 @@ struct uniphier_reset_data { #define UNIPHIER_PRO4_SYS_RESET_USB3(id, ch) \ UNIPHIER_RESETX((id), 0x2000 + 0x4 * (ch), 17) -const struct uniphier_reset_data uniphier_sld3_sys_reset_data[] = { +static const struct uniphier_reset_data uniphier_sld3_sys_reset_data[] = { + UNIPHIER_SLD3_SYS_RESET_NAND(2), UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* Ether, HSC, MIO */ UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = { +static const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = { + UNIPHIER_SLD3_SYS_RESET_NAND(2), UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, MIO, RLE */ UNIPHIER_PRO4_SYS_RESET_GIO(12), /* Ether, SATA, USB3 */ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0), @@ -78,7 +89,8 @@ const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = { UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = { +static const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = { + UNIPHIER_SLD3_SYS_RESET_NAND(2), UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC */ UNIPHIER_PRO4_SYS_RESET_GIO(12), /* PCIe, USB3 */ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0), @@ -86,7 +98,8 @@ const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = { UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = { +static const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = { + UNIPHIER_SLD3_SYS_RESET_NAND(2), UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, RLE */ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0), UNIPHIER_PRO4_SYS_RESET_USB3(15, 1), @@ -100,12 +113,16 @@ const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = { UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = { +static const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = { + UNIPHIER_LD11_SYS_RESET_NAND(2), + UNIPHIER_LD11_SYS_RESET_EMMC(4), UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC, MIO */ UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = { +static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = { + UNIPHIER_LD11_SYS_RESET_NAND(2), + UNIPHIER_LD11_SYS_RESET_EMMC(4), UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC */ UNIPHIER_LD20_SYS_RESET_GIO(12), /* PCIe, USB3 */ UNIPHIER_RESETX(16, 0x200c, 12), /* USB30-PHY0 */ @@ -134,7 +151,7 @@ const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = { #define UNIPHIER_MIO_RESET_DMAC(id) \ UNIPHIER_RESETX((id), 0x110, 17) -const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = { +static const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = { UNIPHIER_MIO_RESET_SD(0, 0), UNIPHIER_MIO_RESET_SD(1, 1), UNIPHIER_MIO_RESET_SD(2, 2), @@ -154,7 +171,7 @@ const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = { UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = { +static const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = { UNIPHIER_MIO_RESET_SD(0, 0), UNIPHIER_MIO_RESET_SD(1, 1), UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1), @@ -171,7 +188,7 @@ const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = { #define UNIPHIER_PERI_RESET_FI2C(id, ch) \ UNIPHIER_RESETX((id), 0x114, 24 + (ch)) -const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { +static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { UNIPHIER_PERI_RESET_UART(0, 0), UNIPHIER_PERI_RESET_UART(1, 1), UNIPHIER_PERI_RESET_UART(2, 2), @@ -184,7 +201,7 @@ const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { UNIPHIER_RESET_END, }; -const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = { +static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = { UNIPHIER_PERI_RESET_UART(0, 0), UNIPHIER_PERI_RESET_UART(1, 1), UNIPHIER_PERI_RESET_UART(2, 2), diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index f09023f7ab11..309643fe35f9 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -1,7 +1,9 @@ menu "SOC (System On Chip) specific Drivers" +source "drivers/soc/atmel/Kconfig" source "drivers/soc/bcm/Kconfig" source "drivers/soc/fsl/Kconfig" +source "drivers/soc/imx/Kconfig" source "drivers/soc/mediatek/Kconfig" source "drivers/soc/qcom/Kconfig" source "drivers/soc/rockchip/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 05eae52a30b4..824b44281efa 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -2,10 +2,12 @@ # Makefile for the Linux Kernel SOC specific device drivers. # +obj-$(CONFIG_ARCH_AT91) += atmel/ obj-y += bcm/ obj-$(CONFIG_ARCH_DOVE) += dove/ obj-$(CONFIG_MACH_DOVE) += dove/ obj-y += fsl/ +obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_QCOM) += qcom/ obj-$(CONFIG_ARCH_RENESAS) += renesas/ diff --git a/drivers/soc/atmel/Kconfig b/drivers/soc/atmel/Kconfig new file mode 100644 index 000000000000..6242ebb41abb --- /dev/null +++ b/drivers/soc/atmel/Kconfig @@ -0,0 +1,6 @@ +config AT91_SOC_ID + bool "SoC bus for Atmel ARM SoCs" + depends on ARCH_AT91 || COMPILE_TEST + default ARCH_AT91 + help + Include support for the SoC bus on the Atmel ARM SoCs. diff --git a/drivers/soc/atmel/Makefile b/drivers/soc/atmel/Makefile new file mode 100644 index 000000000000..2d92f32e4ea5 --- /dev/null +++ b/drivers/soc/atmel/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_AT91_SOC_ID) += soc.o diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c new file mode 100644 index 000000000000..4790094b498e --- /dev/null +++ b/drivers/soc/atmel/soc.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2015 Atmel + * + * Alexandre Belloni <alexandre.belloni@free-electrons.com + * Boris Brezillon <boris.brezillon@free-electrons.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + */ + +#define pr_fmt(fmt) "AT91: " fmt + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> + +#include "soc.h" + +#define AT91_DBGU_CIDR 0x40 +#define AT91_DBGU_EXID 0x44 +#define AT91_CHIPID_CIDR 0x00 +#define AT91_CHIPID_EXID 0x04 +#define AT91_CIDR_VERSION(x) ((x) & 0x1f) +#define AT91_CIDR_EXT BIT(31) +#define AT91_CIDR_MATCH_MASK 0x7fffffe0 + +static const struct at91_soc __initconst socs[] = { +#ifdef CONFIG_SOC_AT91RM9200 + AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"), +#endif +#ifdef CONFIG_SOC_AT91SAM9 + AT91_SOC(AT91SAM9260_CIDR_MATCH, 0, "at91sam9260", NULL), + AT91_SOC(AT91SAM9261_CIDR_MATCH, 0, "at91sam9261", NULL), + AT91_SOC(AT91SAM9263_CIDR_MATCH, 0, "at91sam9263", NULL), + AT91_SOC(AT91SAM9G20_CIDR_MATCH, 0, "at91sam9g20", NULL), + AT91_SOC(AT91SAM9RL64_CIDR_MATCH, 0, "at91sam9rl64", NULL), + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M11_EXID_MATCH, + "at91sam9m11", "at91sam9g45"), + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M10_EXID_MATCH, + "at91sam9m10", "at91sam9g45"), + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G46_EXID_MATCH, + "at91sam9g46", "at91sam9g45"), + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G45_EXID_MATCH, + "at91sam9g45", "at91sam9g45"), + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G15_EXID_MATCH, + "at91sam9g15", "at91sam9x5"), + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G35_EXID_MATCH, + "at91sam9g35", "at91sam9x5"), + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X35_EXID_MATCH, + "at91sam9x35", "at91sam9x5"), + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G25_EXID_MATCH, + "at91sam9g25", "at91sam9x5"), + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X25_EXID_MATCH, + "at91sam9x25", "at91sam9x5"), + AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN12_EXID_MATCH, + "at91sam9cn12", "at91sam9n12"), + AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9N12_EXID_MATCH, + "at91sam9n12", "at91sam9n12"), + AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN11_EXID_MATCH, + "at91sam9cn11", "at91sam9n12"), + AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), + AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), + AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), +#endif +#ifdef CONFIG_SOC_SAMA5 + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, + "sama5d21", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH, + "sama5d22", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH, + "sama5d23", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH, + "sama5d24", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH, + "sama5d24", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH, + "sama5d26", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH, + "sama5d27", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH, + "sama5d27", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, + "sama5d28", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, + "sama5d28", "sama5d2"), + AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, + "sama5d31", "sama5d3"), + AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, + "sama5d33", "sama5d3"), + AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D34_EXID_MATCH, + "sama5d34", "sama5d3"), + AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D35_EXID_MATCH, + "sama5d35", "sama5d3"), + AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D36_EXID_MATCH, + "sama5d36", "sama5d3"), + AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D41_EXID_MATCH, + "sama5d41", "sama5d4"), + AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D42_EXID_MATCH, + "sama5d42", "sama5d4"), + AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D43_EXID_MATCH, + "sama5d43", "sama5d4"), + AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D44_EXID_MATCH, + "sama5d44", "sama5d4"), +#endif + { /* sentinel */ }, +}; + +static int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid) +{ + struct device_node *np; + void __iomem *regs; + + np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-dbgu"); + if (!np) + np = of_find_compatible_node(NULL, NULL, + "atmel,at91sam9260-dbgu"); + if (!np) + return -ENODEV; + + regs = of_iomap(np, 0); + of_node_put(np); + + if (!regs) { + pr_warn("Could not map DBGU iomem range"); + return -ENXIO; + } + + *cidr = readl(regs + AT91_DBGU_CIDR); + *exid = readl(regs + AT91_DBGU_EXID); + + iounmap(regs); + + return 0; +} + +static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid) +{ + struct device_node *np; + void __iomem *regs; + + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid"); + if (!np) + return -ENODEV; + + regs = of_iomap(np, 0); + of_node_put(np); + + if (!regs) { + pr_warn("Could not map DBGU iomem range"); + return -ENXIO; + } + + *cidr = readl(regs + AT91_CHIPID_CIDR); + *exid = readl(regs + AT91_CHIPID_EXID); + + iounmap(regs); + + return 0; +} + +struct soc_device * __init at91_soc_init(const struct at91_soc *socs) +{ + struct soc_device_attribute *soc_dev_attr; + const struct at91_soc *soc; + struct soc_device *soc_dev; + u32 cidr, exid; + int ret; + + /* + * With SAMA5D2 and later SoCs, CIDR and EXID registers are no more + * in the dbgu device but in the chipid device whose purpose is only + * to expose these two registers. + */ + ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid); + if (ret) + ret = at91_get_cidr_exid_from_chipid(&cidr, &exid); + if (ret) { + if (ret == -ENODEV) + pr_warn("Could not find identification node"); + return NULL; + } + + for (soc = socs; soc->name; soc++) { + if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK)) + continue; + + if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid) + break; + } + + if (!soc->name) { + pr_warn("Could not find matching SoC description\n"); + return NULL; + } + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return NULL; + + soc_dev_attr->family = soc->family; + soc_dev_attr->soc_id = soc->name; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", + AT91_CIDR_VERSION(cidr)); + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr); + pr_warn("Could not register SoC device\n"); + return NULL; + } + + if (soc->family) + pr_info("Detected SoC family: %s\n", soc->family); + pr_info("Detected SoC: %s, revision %X\n", soc->name, + AT91_CIDR_VERSION(cidr)); + + return soc_dev; +} + +static int __init atmel_soc_device_init(void) +{ + at91_soc_init(socs); + + return 0; +} +subsys_initcall(atmel_soc_device_init); diff --git a/arch/arm/mach-at91/soc.h b/drivers/soc/atmel/soc.h index 228efded5085..228efded5085 100644 --- a/arch/arm/mach-at91/soc.h +++ b/drivers/soc/atmel/soc.h diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c index 94e7335553f4..b6195fdf0d00 100644 --- a/drivers/soc/bcm/brcmstb/common.c +++ b/drivers/soc/bcm/brcmstb/common.c @@ -41,6 +41,15 @@ bool soc_is_brcmstb(void) } static const struct of_device_id sun_top_ctrl_match[] = { + { .compatible = "brcm,bcm7125-sun-top-ctrl", }, + { .compatible = "brcm,bcm7346-sun-top-ctrl", }, + { .compatible = "brcm,bcm7358-sun-top-ctrl", }, + { .compatible = "brcm,bcm7360-sun-top-ctrl", }, + { .compatible = "brcm,bcm7362-sun-top-ctrl", }, + { .compatible = "brcm,bcm7420-sun-top-ctrl", }, + { .compatible = "brcm,bcm7425-sun-top-ctrl", }, + { .compatible = "brcm,bcm7429-sun-top-ctrl", }, + { .compatible = "brcm,bcm7425-sun-top-ctrl", }, { .compatible = "brcm,brcmstb-sun-top-ctrl", }, { } }; diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h index 22725bdc6f15..5fe9faf6232e 100644 --- a/drivers/soc/fsl/qbman/qman_priv.h +++ b/drivers/soc/fsl/qbman/qman_priv.h @@ -33,6 +33,7 @@ #include "dpaa_sys.h" #include <soc/fsl/qman.h> +#include <linux/dma-mapping.h> #include <linux/iommu.h> #if defined(CONFIG_FSL_PAMU) diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig new file mode 100644 index 000000000000..357a5d8f8da0 --- /dev/null +++ b/drivers/soc/imx/Kconfig @@ -0,0 +1,9 @@ +menu "i.MX SoC drivers" + +config IMX7_PM_DOMAINS + bool "i.MX7 PM domains" + select PM_GENERIC_DOMAINS + depends on SOC_IMX7D || (COMPILE_TEST && OF) + default y if SOC_IMX7D + +endmenu diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile new file mode 100644 index 000000000000..5b6e396c1121 --- /dev/null +++ b/drivers/soc/imx/Makefile @@ -0,0 +1,2 @@ +obj-y += gpc.o +obj-$(CONFIG_IMX7_PM_DOMAINS) += gpcv2.o diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c new file mode 100644 index 000000000000..47e7aa963dbb --- /dev/null +++ b/drivers/soc/imx/gpc.c @@ -0,0 +1,489 @@ +/* + * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de> + * Copyright 2011-2013 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#define GPC_CNTR 0x000 + +#define GPC_PGC_CTRL_OFFS 0x0 +#define GPC_PGC_PUPSCR_OFFS 0x4 +#define GPC_PGC_PDNSCR_OFFS 0x8 +#define GPC_PGC_SW2ISO_SHIFT 0x8 +#define GPC_PGC_SW_SHIFT 0x0 + +#define GPC_PGC_GPU_PDN 0x260 +#define GPC_PGC_GPU_PUPSCR 0x264 +#define GPC_PGC_GPU_PDNSCR 0x268 + +#define GPU_VPU_PUP_REQ BIT(1) +#define GPU_VPU_PDN_REQ BIT(0) + +#define GPC_CLK_MAX 6 + +#define PGC_DOMAIN_FLAG_NO_PD BIT(0) + +struct imx_pm_domain { + struct generic_pm_domain base; + struct regmap *regmap; + struct regulator *supply; + struct clk *clk[GPC_CLK_MAX]; + int num_clks; + unsigned int reg_offs; + signed char cntr_pdn_bit; + unsigned int ipg_rate_mhz; + unsigned int flags; +}; + +static inline struct imx_pm_domain * +to_imx_pm_domain(struct generic_pm_domain *genpd) +{ + return container_of(genpd, struct imx_pm_domain, base); +} + +static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd) +{ + struct imx_pm_domain *pd = to_imx_pm_domain(genpd); + int iso, iso2sw; + u32 val; + + if (pd->flags & PGC_DOMAIN_FLAG_NO_PD) + return -EBUSY; + + /* Read ISO and ISO2SW power down delays */ + regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); + iso = val & 0x3f; + iso2sw = (val >> 8) & 0x3f; + + /* Gate off domain when powered down */ + regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, + 0x1, 0x1); + + /* Request GPC to power down domain */ + val = BIT(pd->cntr_pdn_bit); + regmap_update_bits(pd->regmap, GPC_CNTR, val, val); + + /* Wait ISO + ISO2SW IPG clock cycles */ + udelay(DIV_ROUND_UP(iso + iso2sw, pd->ipg_rate_mhz)); + + if (pd->supply) + regulator_disable(pd->supply); + + return 0; +} + +static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) +{ + struct imx_pm_domain *pd = to_imx_pm_domain(genpd); + int i, ret, sw, sw2iso; + u32 val; + + if (pd->supply) { + ret = regulator_enable(pd->supply); + if (ret) { + pr_err("%s: failed to enable regulator: %d\n", + __func__, ret); + return ret; + } + } + + /* Enable reset clocks for all devices in the domain */ + for (i = 0; i < pd->num_clks; i++) + clk_prepare_enable(pd->clk[i]); + + /* Gate off domain when powered down */ + regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, + 0x1, 0x1); + + /* Read ISO and ISO2SW power up delays */ + regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); + sw = val & 0x3f; + sw2iso = (val >> 8) & 0x3f; + + /* Request GPC to power up domain */ + val = BIT(pd->cntr_pdn_bit + 1); + regmap_update_bits(pd->regmap, GPC_CNTR, val, val); + + /* Wait ISO + ISO2SW IPG clock cycles */ + udelay(DIV_ROUND_UP(sw + sw2iso, pd->ipg_rate_mhz)); + + /* Disable reset clocks for all devices in the domain */ + for (i = 0; i < pd->num_clks; i++) + clk_disable_unprepare(pd->clk[i]); + + return 0; +} + +static int imx_pgc_get_clocks(struct device *dev, struct imx_pm_domain *domain) +{ + int i, ret; + + for (i = 0; ; i++) { + struct clk *clk = of_clk_get(dev->of_node, i); + if (IS_ERR(clk)) + break; + if (i >= GPC_CLK_MAX) { + dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX); + ret = -EINVAL; + goto clk_err; + } + domain->clk[i] = clk; + } + domain->num_clks = i; + + return 0; + +clk_err: + while (i--) + clk_put(domain->clk[i]); + + return ret; +} + +static void imx_pgc_put_clocks(struct imx_pm_domain *domain) +{ + int i; + + for (i = domain->num_clks - 1; i >= 0; i--) + clk_put(domain->clk[i]); +} + +static int imx_pgc_parse_dt(struct device *dev, struct imx_pm_domain *domain) +{ + /* try to get the domain supply regulator */ + domain->supply = devm_regulator_get_optional(dev, "power"); + if (IS_ERR(domain->supply)) { + if (PTR_ERR(domain->supply) == -ENODEV) + domain->supply = NULL; + else + return PTR_ERR(domain->supply); + } + + /* try to get all clocks needed for reset propagation */ + return imx_pgc_get_clocks(dev, domain); +} + +static int imx_pgc_power_domain_probe(struct platform_device *pdev) +{ + struct imx_pm_domain *domain = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + int ret; + + /* if this PD is associated with a DT node try to parse it */ + if (dev->of_node) { + ret = imx_pgc_parse_dt(dev, domain); + if (ret) + return ret; + } + + /* initially power on the domain */ + if (domain->base.power_on) + domain->base.power_on(&domain->base); + + if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + pm_genpd_init(&domain->base, NULL, false); + ret = of_genpd_add_provider_simple(dev->of_node, &domain->base); + if (ret) + goto genpd_err; + } + + device_link_add(dev, dev->parent, DL_FLAG_AUTOREMOVE); + + return 0; + +genpd_err: + pm_genpd_remove(&domain->base); + imx_pgc_put_clocks(domain); + + return ret; +} + +static int imx_pgc_power_domain_remove(struct platform_device *pdev) +{ + struct imx_pm_domain *domain = pdev->dev.platform_data; + + if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + of_genpd_del_provider(pdev->dev.of_node); + pm_genpd_remove(&domain->base); + imx_pgc_put_clocks(domain); + } + + return 0; +} + +static const struct platform_device_id imx_pgc_power_domain_id[] = { + { "imx-pgc-power-domain"}, + { }, +}; + +static struct platform_driver imx_pgc_power_domain_driver = { + .driver = { + .name = "imx-pgc-pd", + }, + .probe = imx_pgc_power_domain_probe, + .remove = imx_pgc_power_domain_remove, + .id_table = imx_pgc_power_domain_id, +}; +builtin_platform_driver(imx_pgc_power_domain_driver) + +#define GPC_PGC_DOMAIN_ARM 0 +#define GPC_PGC_DOMAIN_PU 1 +#define GPC_PGC_DOMAIN_DISPLAY 2 + +static struct genpd_power_state imx6_pm_domain_pu_state = { + .power_off_latency_ns = 25000, + .power_on_latency_ns = 2000000, +}; + +static struct imx_pm_domain imx_gpc_domains[] = { + { + .base = { + .name = "ARM", + }, + }, { + .base = { + .name = "PU", + .power_off = imx6_pm_domain_power_off, + .power_on = imx6_pm_domain_power_on, + .states = &imx6_pm_domain_pu_state, + .state_count = 1, + }, + .reg_offs = 0x260, + .cntr_pdn_bit = 0, + }, { + .base = { + .name = "DISPLAY", + .power_off = imx6_pm_domain_power_off, + .power_on = imx6_pm_domain_power_on, + }, + .reg_offs = 0x240, + .cntr_pdn_bit = 4, + } +}; + +struct imx_gpc_dt_data { + int num_domains; + bool err009619_present; +}; + +static const struct imx_gpc_dt_data imx6q_dt_data = { + .num_domains = 2, + .err009619_present = false, +}; + +static const struct imx_gpc_dt_data imx6qp_dt_data = { + .num_domains = 2, + .err009619_present = true, +}; + +static const struct imx_gpc_dt_data imx6sl_dt_data = { + .num_domains = 3, + .err009619_present = false, +}; + +static const struct of_device_id imx_gpc_dt_ids[] = { + { .compatible = "fsl,imx6q-gpc", .data = &imx6q_dt_data }, + { .compatible = "fsl,imx6qp-gpc", .data = &imx6qp_dt_data }, + { .compatible = "fsl,imx6sl-gpc", .data = &imx6sl_dt_data }, + { } +}; + +static const struct regmap_config imx_gpc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x2ac, +}; + +static struct generic_pm_domain *imx_gpc_onecell_domains[] = { + &imx_gpc_domains[0].base, + &imx_gpc_domains[1].base, +}; + +static struct genpd_onecell_data imx_gpc_onecell_data = { + .domains = imx_gpc_onecell_domains, + .num_domains = 2, +}; + +static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap, + unsigned int num_domains) +{ + struct imx_pm_domain *domain; + int i, ret; + + for (i = 0; i < num_domains; i++) { + domain = &imx_gpc_domains[i]; + domain->regmap = regmap; + domain->ipg_rate_mhz = 66; + + if (i == 1) { + domain->supply = devm_regulator_get(dev, "pu"); + if (IS_ERR(domain->supply)) + return PTR_ERR(domain->supply);; + + ret = imx_pgc_get_clocks(dev, domain); + if (ret) + goto clk_err; + + domain->base.power_on(&domain->base); + } + } + + for (i = 0; i < num_domains; i++) + pm_genpd_init(&imx_gpc_domains[i].base, NULL, false); + + if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + ret = of_genpd_add_provider_onecell(dev->of_node, + &imx_gpc_onecell_data); + if (ret) + goto genpd_err; + } + + return 0; + +genpd_err: + for (i = 0; i < num_domains; i++) + pm_genpd_remove(&imx_gpc_domains[i].base); + imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]); +clk_err: + return ret; +} + +static int imx_gpc_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(imx_gpc_dt_ids, &pdev->dev); + const struct imx_gpc_dt_data *of_id_data = of_id->data; + struct device_node *pgc_node; + struct regmap *regmap; + struct resource *res; + void __iomem *base; + int ret; + + pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); + + /* bail out if DT too old and doesn't provide the necessary info */ + if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && + !pgc_node) + return 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, + &imx_gpc_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&pdev->dev, "failed to init regmap: %d\n", + ret); + return ret; + } + + /* Disable PU power down in normal operation if ERR009619 is present */ + if (of_id_data->err009619_present) + imx_gpc_domains[GPC_PGC_DOMAIN_PU].flags |= + PGC_DOMAIN_FLAG_NO_PD; + + if (!pgc_node) { + ret = imx_gpc_old_dt_init(&pdev->dev, regmap, + of_id_data->num_domains); + if (ret) + return ret; + } else { + struct imx_pm_domain *domain; + struct platform_device *pd_pdev; + struct device_node *np; + struct clk *ipg_clk; + unsigned int ipg_rate_mhz; + int domain_index; + + ipg_clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(ipg_clk)) + return PTR_ERR(ipg_clk); + ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000; + + for_each_child_of_node(pgc_node, np) { + ret = of_property_read_u32(np, "reg", &domain_index); + if (ret) { + of_node_put(np); + return ret; + } + if (domain_index >= of_id_data->num_domains) + continue; + + domain = &imx_gpc_domains[domain_index]; + domain->regmap = regmap; + domain->ipg_rate_mhz = ipg_rate_mhz; + + pd_pdev = platform_device_alloc("imx-pgc-power-domain", + domain_index); + if (!pd_pdev) { + of_node_put(np); + return -ENOMEM; + } + pd_pdev->dev.platform_data = domain; + pd_pdev->dev.parent = &pdev->dev; + pd_pdev->dev.of_node = np; + + ret = platform_device_add(pd_pdev); + if (ret) { + platform_device_put(pd_pdev); + of_node_put(np); + return ret; + } + } + } + + return 0; +} + +static int imx_gpc_remove(struct platform_device *pdev) +{ + int ret; + + /* + * If the old DT binding is used the toplevel driver needs to + * de-register the power domains + */ + if (!of_get_child_by_name(pdev->dev.of_node, "pgc")) { + of_genpd_del_provider(pdev->dev.of_node); + + ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base); + if (ret) + return ret; + imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]); + + ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base); + if (ret) + return ret; + } + + return 0; +} + +static struct platform_driver imx_gpc_driver = { + .driver = { + .name = "imx-gpc", + .of_match_table = imx_gpc_dt_ids, + }, + .probe = imx_gpc_probe, + .remove = imx_gpc_remove, +}; +builtin_platform_driver(imx_gpc_driver) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c new file mode 100644 index 000000000000..3039072911a5 --- /dev/null +++ b/drivers/soc/imx/gpcv2.c @@ -0,0 +1,363 @@ +/* + * Copyright 2017 Impinj, Inc + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * Based on the code of analogus driver: + * + * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <dt-bindings/power/imx7-power.h> + +#define GPC_LPCR_A7_BSC 0x000 + +#define GPC_PGC_CPU_MAPPING 0x0ec +#define USB_HSIC_PHY_A7_DOMAIN BIT(6) +#define USB_OTG2_PHY_A7_DOMAIN BIT(5) +#define USB_OTG1_PHY_A7_DOMAIN BIT(4) +#define PCIE_PHY_A7_DOMAIN BIT(3) +#define MIPI_PHY_A7_DOMAIN BIT(2) + +#define GPC_PU_PGC_SW_PUP_REQ 0x0f8 +#define GPC_PU_PGC_SW_PDN_REQ 0x104 +#define USB_HSIC_PHY_SW_Pxx_REQ BIT(4) +#define USB_OTG2_PHY_SW_Pxx_REQ BIT(3) +#define USB_OTG1_PHY_SW_Pxx_REQ BIT(2) +#define PCIE_PHY_SW_Pxx_REQ BIT(1) +#define MIPI_PHY_SW_Pxx_REQ BIT(0) + +#define GPC_M4_PU_PDN_FLG 0x1bc + + +#define PGC_MIPI 4 +#define PGC_PCIE 5 +#define PGC_USB_HSIC 8 +#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) +#define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) + +#define GPC_PGC_CTRL_PCR BIT(0) + +struct imx7_pgc_domain { + struct generic_pm_domain genpd; + struct regmap *regmap; + struct regulator *regulator; + + unsigned int pgc; + + const struct { + u32 pxx; + u32 map; + } bits; + + const int voltage; + struct device *dev; +}; + +static int imx7_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, + bool on) +{ + struct imx7_pgc_domain *domain = container_of(genpd, + struct imx7_pgc_domain, + genpd); + unsigned int offset = on ? + GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; + const bool enable_power_control = !on; + const bool has_regulator = !IS_ERR(domain->regulator); + unsigned long deadline; + int ret = 0; + + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, domain->bits.map); + + if (has_regulator && on) { + ret = regulator_enable(domain->regulator); + if (ret) { + dev_err(domain->dev, "failed to enable regulator\n"); + goto unmap; + } + } + + if (enable_power_control) + regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), + GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); + + regmap_update_bits(domain->regmap, offset, + domain->bits.pxx, domain->bits.pxx); + + /* + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait + * for PUP_REQ/PDN_REQ bit to be cleared + */ + deadline = jiffies + msecs_to_jiffies(1); + while (true) { + u32 pxx_req; + + regmap_read(domain->regmap, offset, &pxx_req); + + if (!(pxx_req & domain->bits.pxx)) + break; + + if (time_after(jiffies, deadline)) { + dev_err(domain->dev, "falied to command PGC\n"); + ret = -ETIMEDOUT; + /* + * If we were in a process of enabling a + * domain and failed we might as well disable + * the regulator we just enabled. And if it + * was the opposite situation and we failed to + * power down -- keep the regulator on + */ + on = !on; + break; + } + + cpu_relax(); + } + + if (enable_power_control) + regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), + GPC_PGC_CTRL_PCR, 0); + + if (has_regulator && !on) { + int err; + + err = regulator_disable(domain->regulator); + if (err) + dev_err(domain->dev, + "failed to disable regulator: %d\n", ret); + /* Preserve earlier error code */ + ret = ret ?: err; + } +unmap: + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, 0); + return ret; +} + +static int imx7_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd) +{ + return imx7_gpc_pu_pgc_sw_pxx_req(genpd, true); +} + +static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) +{ + return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false); +} + +static struct imx7_pgc_domain imx7_pgc_domains[] = { + [IMX7_POWER_DOMAIN_MIPI_PHY] = { + .genpd = { + .name = "mipi-phy", + }, + .bits = { + .pxx = MIPI_PHY_SW_Pxx_REQ, + .map = MIPI_PHY_A7_DOMAIN, + }, + .voltage = 1000000, + .pgc = PGC_MIPI, + }, + + [IMX7_POWER_DOMAIN_PCIE_PHY] = { + .genpd = { + .name = "pcie-phy", + }, + .bits = { + .pxx = PCIE_PHY_SW_Pxx_REQ, + .map = PCIE_PHY_A7_DOMAIN, + }, + .voltage = 1000000, + .pgc = PGC_PCIE, + }, + + [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = { + .genpd = { + .name = "usb-hsic-phy", + }, + .bits = { + .pxx = USB_HSIC_PHY_SW_Pxx_REQ, + .map = USB_HSIC_PHY_A7_DOMAIN, + }, + .voltage = 1200000, + .pgc = PGC_USB_HSIC, + }, +}; + +static int imx7_pgc_domain_probe(struct platform_device *pdev) +{ + struct imx7_pgc_domain *domain = pdev->dev.platform_data; + int ret; + + domain->dev = &pdev->dev; + + ret = pm_genpd_init(&domain->genpd, NULL, true); + if (ret) { + dev_err(domain->dev, "Failed to init power domain\n"); + return ret; + } + + domain->regulator = devm_regulator_get_optional(domain->dev, "power"); + if (IS_ERR(domain->regulator)) { + if (PTR_ERR(domain->regulator) != -ENODEV) { + dev_err(domain->dev, "Failed to get domain's regulator\n"); + return PTR_ERR(domain->regulator); + } + } else { + regulator_set_voltage(domain->regulator, + domain->voltage, domain->voltage); + } + + ret = of_genpd_add_provider_simple(domain->dev->of_node, + &domain->genpd); + if (ret) { + dev_err(domain->dev, "Failed to add genpd provider\n"); + pm_genpd_remove(&domain->genpd); + } + + return ret; +} + +static int imx7_pgc_domain_remove(struct platform_device *pdev) +{ + struct imx7_pgc_domain *domain = pdev->dev.platform_data; + + of_genpd_del_provider(domain->dev->of_node); + pm_genpd_remove(&domain->genpd); + + return 0; +} + +static const struct platform_device_id imx7_pgc_domain_id[] = { + { "imx7-pgc-domain", }, + { }, +}; + +static struct platform_driver imx7_pgc_domain_driver = { + .driver = { + .name = "imx7-pgc", + }, + .probe = imx7_pgc_domain_probe, + .remove = imx7_pgc_domain_remove, + .id_table = imx7_pgc_domain_id, +}; +builtin_platform_driver(imx7_pgc_domain_driver) + +static int imx_gpcv2_probe(struct platform_device *pdev) +{ + static const struct regmap_range yes_ranges[] = { + regmap_reg_range(GPC_LPCR_A7_BSC, + GPC_M4_PU_PDN_FLG), + regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI), + GPC_PGC_SR(PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(PGC_PCIE), + GPC_PGC_SR(PGC_PCIE)), + regmap_reg_range(GPC_PGC_CTRL(PGC_USB_HSIC), + GPC_PGC_SR(PGC_USB_HSIC)), + }; + static const struct regmap_access_table access_table = { + .yes_ranges = yes_ranges, + .n_yes_ranges = ARRAY_SIZE(yes_ranges), + }; + static const struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .rd_table = &access_table, + .wr_table = &access_table, + .max_register = SZ_4K, + }; + struct device *dev = &pdev->dev; + struct device_node *pgc_np, *np; + struct regmap *regmap; + struct resource *res; + void __iomem *base; + int ret; + + pgc_np = of_get_child_by_name(dev->of_node, "pgc"); + if (!pgc_np) { + dev_err(dev, "No power domains specified in DT\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(dev, base, ®map_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(dev, "failed to init regmap (%d)\n", ret); + return ret; + } + + for_each_child_of_node(pgc_np, np) { + struct platform_device *pd_pdev; + struct imx7_pgc_domain *domain; + u32 domain_index; + + ret = of_property_read_u32(np, "reg", &domain_index); + if (ret) { + dev_err(dev, "Failed to read 'reg' property\n"); + of_node_put(np); + return ret; + } + + if (domain_index >= ARRAY_SIZE(imx7_pgc_domains)) { + dev_warn(dev, + "Domain index %d is out of bounds\n", + domain_index); + continue; + } + + domain = &imx7_pgc_domains[domain_index]; + domain->regmap = regmap; + domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; + domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; + + pd_pdev = platform_device_alloc("imx7-pgc-domain", + domain_index); + if (!pd_pdev) { + dev_err(dev, "Failed to allocate platform device\n"); + of_node_put(np); + return -ENOMEM; + } + + pd_pdev->dev.platform_data = domain; + pd_pdev->dev.parent = dev; + pd_pdev->dev.of_node = np; + + ret = platform_device_add(pd_pdev); + if (ret) { + platform_device_put(pd_pdev); + of_node_put(np); + return ret; + } + } + + return 0; +} + +static const struct of_device_id imx_gpcv2_dt_ids[] = { + { .compatible = "fsl,imx7d-gpc" }, + { } +}; + +static struct platform_driver imx_gpc_driver = { + .driver = { + .name = "imx-gpcv2", + .of_match_table = imx_gpcv2_dt_ids, + }, + .probe = imx_gpcv2_probe, +}; +builtin_platform_driver(imx_gpc_driver) diff --git a/drivers/soc/renesas/r8a7795-sysc.c b/drivers/soc/renesas/r8a7795-sysc.c index 5e7537c96f7b..7412666187b3 100644 --- a/drivers/soc/renesas/r8a7795-sysc.c +++ b/drivers/soc/renesas/r8a7795-sysc.c @@ -1,7 +1,7 @@ /* * Renesas R-Car H3 System Controller * - * Copyright (C) 2016 Glider bvba + * Copyright (C) 2016-2017 Glider bvba * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -10,12 +10,13 @@ #include <linux/bug.h> #include <linux/kernel.h> +#include <linux/sys_soc.h> #include <dt-bindings/power/r8a7795-sysc.h> #include "rcar-sysc.h" -static const struct rcar_sysc_area r8a7795_areas[] __initconst = { +static struct rcar_sysc_area r8a7795_areas[] __initdata = { { "always-on", 0, 0, R8A7795_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, { "ca57-scu", 0x1c0, 0, R8A7795_PD_CA57_SCU, R8A7795_PD_ALWAYS_ON, PD_SCU }, @@ -40,6 +41,7 @@ static const struct rcar_sysc_area r8a7795_areas[] __initconst = { { "a3vp", 0x340, 0, R8A7795_PD_A3VP, R8A7795_PD_ALWAYS_ON }, { "cr7", 0x240, 0, R8A7795_PD_CR7, R8A7795_PD_ALWAYS_ON }, { "a3vc", 0x380, 0, R8A7795_PD_A3VC, R8A7795_PD_ALWAYS_ON }, + /* A2VC0 exists on ES1.x only */ { "a2vc0", 0x3c0, 0, R8A7795_PD_A2VC0, R8A7795_PD_A3VC }, { "a2vc1", 0x3c0, 1, R8A7795_PD_A2VC1, R8A7795_PD_A3VC }, { "3dg-a", 0x100, 0, R8A7795_PD_3DG_A, R8A7795_PD_ALWAYS_ON }, @@ -50,7 +52,27 @@ static const struct rcar_sysc_area r8a7795_areas[] __initconst = { { "a3ir", 0x180, 0, R8A7795_PD_A3IR, R8A7795_PD_ALWAYS_ON }, }; + + /* + * Fixups for R-Car H3 revisions after ES1.x + */ + +static const struct soc_device_attribute r8a7795es1[] __initconst = { + { .soc_id = "r8a7795", .revision = "ES1.*" }, + { /* sentinel */ } +}; + +static int __init r8a7795_sysc_init(void) +{ + if (!soc_device_match(r8a7795es1)) + rcar_sysc_nullify(r8a7795_areas, ARRAY_SIZE(r8a7795_areas), + R8A7795_PD_A2VC0); + + return 0; +} + const struct rcar_sysc_info r8a7795_sysc_info __initconst = { + .init = r8a7795_sysc_init, .areas = r8a7795_areas, .num_areas = ARRAY_SIZE(r8a7795_areas), }; diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 225c35c79d9a..528a13742aeb 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -2,7 +2,7 @@ * R-Car SYSC Power management support * * Copyright (C) 2014 Magnus Damm - * Copyright (C) 2015-2016 Glider bvba + * Copyright (C) 2015-2017 Glider bvba * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -334,6 +334,12 @@ static int __init rcar_sysc_pd_init(void) info = match->data; + if (info->init) { + error = info->init(); + if (error) + return error; + } + has_cpg_mstp = of_find_compatible_node(NULL, NULL, "renesas,cpg-mstp-clocks"); @@ -377,6 +383,11 @@ static int __init rcar_sysc_pd_init(void) const struct rcar_sysc_area *area = &info->areas[i]; struct rcar_sysc_pd *pd; + if (!area->name) { + /* Skip NULLified area */ + continue; + } + pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL); if (!pd) { error = -ENOMEM; @@ -406,6 +417,18 @@ out_put: } early_initcall(rcar_sysc_pd_init); +void __init rcar_sysc_nullify(struct rcar_sysc_area *areas, + unsigned int num_areas, u8 id) +{ + unsigned int i; + + for (i = 0; i < num_areas; i++) + if (areas[i].isr_bit == id) { + areas[i].name = NULL; + return; + } +} + void __init rcar_sysc_init(phys_addr_t base, u32 syscier) { u32 syscimr; diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h index f6e842e2976e..07edb049a401 100644 --- a/drivers/soc/renesas/rcar-sysc.h +++ b/drivers/soc/renesas/rcar-sysc.h @@ -46,6 +46,7 @@ struct rcar_sysc_area { */ struct rcar_sysc_info { + int (*init)(void); /* Optional */ const struct rcar_sysc_area *areas; unsigned int num_areas; }; @@ -59,4 +60,13 @@ extern const struct rcar_sysc_info r8a7792_sysc_info; extern const struct rcar_sysc_info r8a7794_sysc_info; extern const struct rcar_sysc_info r8a7795_sysc_info; extern const struct rcar_sysc_info r8a7796_sysc_info; + + + /* + * Helpers for fixing up power area tables depending on SoC revision + */ + +extern void rcar_sysc_nullify(struct rcar_sysc_area *areas, + unsigned int num_areas, u8 id); + #endif /* __SOC_RENESAS_RCAR_SYSC_H__ */ diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 330960312296..ca26f13d399c 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -80,11 +80,21 @@ static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = { .id = 0x40, }; +static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = { + .family = &fam_rzg, + .id = 0x45, +}; + static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = { .family = &fam_rzg, .id = 0x47, }; +static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = { + .family = &fam_rzg, + .id = 0x4b, +}; + static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = { .family = &fam_rzg, .id = 0x4c, @@ -150,9 +160,15 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A7740 { .compatible = "renesas,r8a7740", .data = &soc_rmobile_a1 }, #endif +#ifdef CONFIG_ARCH_R8A7742 + { .compatible = "renesas,r8a7742", .data = &soc_rz_g1h }, +#endif #ifdef CONFIG_ARCH_R8A7743 { .compatible = "renesas,r8a7743", .data = &soc_rz_g1m }, #endif +#ifdef CONFIG_ARCH_R8A7744 + { .compatible = "renesas,r8a7744", .data = &soc_rz_g1n }, +#endif #ifdef CONFIG_ARCH_R8A7745 { .compatible = "renesas,r8a7745", .data = &soc_rz_g1e }, #endif @@ -254,4 +270,4 @@ static int __init renesas_soc_init(void) return 0; } -core_initcall(renesas_soc_init); +early_initcall(renesas_soc_init); diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index 245533907d1b..8b25bd55e648 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -8,7 +8,13 @@ if SOC_SAMSUNG config EXYNOS_PMU bool "Exynos PMU controller driver" if COMPILE_TEST - depends on (ARM && ARCH_EXYNOS) || ((ARM || ARM64) && COMPILE_TEST) + depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST) + select EXYNOS_PMU_ARM_DRIVERS if ARM && ARCH_EXYNOS + +# There is no need to enable these drivers for ARMv8 +config EXYNOS_PMU_ARM_DRIVERS + bool "Exynos PMU ARMv7-specific driver extensions" if COMPILE_TEST + depends on EXYNOS_PMU config EXYNOS_PM_DOMAINS bool "Exynos PM domains" if COMPILE_TEST diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index 3619f2ecddaa..4d7694a4e7a4 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -1,3 +1,5 @@ -obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o exynos3250-pmu.o exynos4-pmu.o \ +obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o + +obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \ exynos5250-pmu.o exynos5420-pmu.o obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index 56d9244ff981..bd4a76f27bc2 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -69,27 +69,37 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) } /* + * Split the data between ARM architectures because it is relatively big + * and useless on other arch. + */ +#ifdef CONFIG_EXYNOS_PMU_ARM_DRIVERS +#define exynos_pmu_data_arm_ptr(data) (&data) +#else +#define exynos_pmu_data_arm_ptr(data) NULL +#endif + +/* * PMU platform driver and devicetree bindings. */ static const struct of_device_id exynos_pmu_of_device_ids[] = { { .compatible = "samsung,exynos3250-pmu", - .data = &exynos3250_pmu_data, + .data = exynos_pmu_data_arm_ptr(exynos3250_pmu_data), }, { .compatible = "samsung,exynos4210-pmu", - .data = &exynos4210_pmu_data, + .data = exynos_pmu_data_arm_ptr(exynos4210_pmu_data), }, { .compatible = "samsung,exynos4212-pmu", - .data = &exynos4212_pmu_data, + .data = exynos_pmu_data_arm_ptr(exynos4212_pmu_data), }, { .compatible = "samsung,exynos4412-pmu", - .data = &exynos4412_pmu_data, + .data = exynos_pmu_data_arm_ptr(exynos4412_pmu_data), }, { .compatible = "samsung,exynos5250-pmu", - .data = &exynos5250_pmu_data, + .data = exynos_pmu_data_arm_ptr(exynos5250_pmu_data), }, { .compatible = "samsung,exynos5420-pmu", - .data = &exynos5420_pmu_data, + .data = exynos_pmu_data_arm_ptr(exynos5420_pmu_data), }, { .compatible = "samsung,exynos5433-pmu", }, diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h index a469e366fead..40d4229abfb5 100644 --- a/drivers/soc/samsung/exynos-pmu.h +++ b/drivers/soc/samsung/exynos-pmu.h @@ -31,6 +31,8 @@ struct exynos_pmu_data { }; extern void __iomem *pmu_base_addr; + +#ifdef CONFIG_EXYNOS_PMU_ARM_DRIVERS /* list of all exported SoC specific data */ extern const struct exynos_pmu_data exynos3250_pmu_data; extern const struct exynos_pmu_data exynos4210_pmu_data; @@ -38,6 +40,7 @@ extern const struct exynos_pmu_data exynos4212_pmu_data; extern const struct exynos_pmu_data exynos4412_pmu_data; extern const struct exynos_pmu_data exynos5250_pmu_data; extern const struct exynos_pmu_data exynos5420_pmu_data; +#endif extern void pmu_raw_writel(u32 val, u32 offset); extern u32 pmu_raw_readl(u32 offset); diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index e5e124c07066..dcf088db40b6 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -12,6 +12,8 @@ config ARCH_TEGRA_2x_SOC select PINCTRL_TEGRA20 select PL310_ERRATA_727915 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0 + select SOC_TEGRA_FLOWCTRL + select SOC_TEGRA_PMC select TEGRA_TIMER help Support for NVIDIA Tegra AP20 and T20 processors, based on the @@ -23,6 +25,8 @@ config ARCH_TEGRA_3x_SOC select ARM_ERRATA_764369 if SMP select PINCTRL_TEGRA30 select PL310_ERRATA_769419 if CACHE_L2X0 + select SOC_TEGRA_FLOWCTRL + select SOC_TEGRA_PMC select TEGRA_TIMER help Support for NVIDIA Tegra T30 processor family, based on the @@ -33,6 +37,8 @@ config ARCH_TEGRA_114_SOC select ARM_ERRATA_798181 if SMP select HAVE_ARM_ARCH_TIMER select PINCTRL_TEGRA114 + select SOC_TEGRA_FLOWCTRL + select SOC_TEGRA_PMC select TEGRA_TIMER help Support for NVIDIA Tegra T114 processor family, based on the @@ -42,6 +48,8 @@ config ARCH_TEGRA_124_SOC bool "Enable support for Tegra124 family" select HAVE_ARM_ARCH_TIMER select PINCTRL_TEGRA124 + select SOC_TEGRA_FLOWCTRL + select SOC_TEGRA_PMC select TEGRA_TIMER help Support for NVIDIA Tegra T124 processor family, based on the @@ -55,6 +63,8 @@ if ARM64 config ARCH_TEGRA_132_SOC bool "NVIDIA Tegra132 SoC" select PINCTRL_TEGRA124 + select SOC_TEGRA_FLOWCTRL + select SOC_TEGRA_PMC help Enable support for NVIDIA Tegra132 SoC, based on the Denver ARMv8 CPU. The Tegra132 SoC is similar to the Tegra124 SoC, @@ -64,6 +74,8 @@ config ARCH_TEGRA_132_SOC config ARCH_TEGRA_210_SOC bool "NVIDIA Tegra210 SoC" select PINCTRL_TEGRA210 + select SOC_TEGRA_FLOWCTRL + select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1, the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53 @@ -83,6 +95,7 @@ config ARCH_TEGRA_186_SOC select TEGRA_BPMP select TEGRA_HSP_MBOX select TEGRA_IVC + select SOC_TEGRA_PMC_TEGRA186 help Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a combination of Denver and Cortex-A57 CPU cores and a GPU based on @@ -93,3 +106,12 @@ config ARCH_TEGRA_186_SOC endif endif + +config SOC_TEGRA_FLOWCTRL + bool + +config SOC_TEGRA_PMC + bool + +config SOC_TEGRA_PMC_TEGRA186 + bool diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile index ae857ff7d53d..4f81dd55e5d1 100644 --- a/drivers/soc/tegra/Makefile +++ b/drivers/soc/tegra/Makefile @@ -1,4 +1,6 @@ obj-y += fuse/ obj-y += common.o -obj-y += pmc.o +obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o +obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o +obj-$(CONFIG_SOC_TEGRA_PMC_TEGRA186) += pmc-tegra186.o diff --git a/arch/arm/mach-tegra/flowctrl.c b/drivers/soc/tegra/flowctrl.c index 475e783992fd..0e345c05fc65 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/drivers/soc/tegra/flowctrl.c @@ -1,7 +1,7 @@ /* - * arch/arm/mach-tegra/flowctrl.c + * drivers/soc/tegra/flowctrl.c * - * functions and macros to control the flowcontroller + * Functions and macros to control the flowcontroller * * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved. * @@ -24,11 +24,12 @@ #include <linux/kernel.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/platform_device.h> +#include <soc/tegra/common.h> +#include <soc/tegra/flowctrl.h> #include <soc/tegra/fuse.h> -#include "flowctrl.h" - static u8 flowctrl_offset_halt_cpu[] = { FLOW_CTRL_HALT_CPU0_EVENTS, FLOW_CTRL_HALT_CPU1_EVENTS, @@ -47,6 +48,10 @@ static void __iomem *tegra_flowctrl_base; static void flowctrl_update(u8 offset, u32 value) { + if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base), + "Tegra flowctrl not initialised!\n")) + return; + writel(value, tegra_flowctrl_base + offset); /* ensure the update has reached the flow controller */ @@ -58,6 +63,10 @@ u32 flowctrl_read_cpu_csr(unsigned int cpuid) { u8 offset = flowctrl_offset_cpu_csr[cpuid]; + if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base), + "Tegra flowctrl not initialised!\n")) + return 0; + return readl(tegra_flowctrl_base + offset); } @@ -140,7 +149,23 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid) flowctrl_write_cpu_csr(cpuid, reg); } -static const struct of_device_id matches[] __initconst = { +static int tegra_flowctrl_probe(struct platform_device *pdev) +{ + void __iomem *base = tegra_flowctrl_base; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra_flowctrl_base)) + return PTR_ERR(base); + + iounmap(base); + + return 0; +} + +static const struct of_device_id tegra_flowctrl_match[] = { + { .compatible = "nvidia,tegra210-flowctrl" }, { .compatible = "nvidia,tegra124-flowctrl" }, { .compatible = "nvidia,tegra114-flowctrl" }, { .compatible = "nvidia,tegra30-flowctrl" }, @@ -148,24 +173,52 @@ static const struct of_device_id matches[] __initconst = { { } }; -void __init tegra_flowctrl_init(void) +static struct platform_driver tegra_flowctrl_driver = { + .driver = { + .name = "tegra-flowctrl", + .suppress_bind_attrs = true, + .of_match_table = tegra_flowctrl_match, + }, + .probe = tegra_flowctrl_probe, +}; +builtin_platform_driver(tegra_flowctrl_driver); + +static int __init tegra_flowctrl_init(void) { - /* hardcoded fallback if device tree node is missing */ - unsigned long base = 0x60007000; - unsigned long size = SZ_4K; + struct resource res; struct device_node *np; - np = of_find_matching_node(NULL, matches); - if (np) { - struct resource res; + if (!soc_is_tegra()) + return 0; - if (of_address_to_resource(np, 0, &res) == 0) { - size = resource_size(&res); - base = res.start; + np = of_find_matching_node(NULL, tegra_flowctrl_match); + if (np) { + if (of_address_to_resource(np, 0, &res) < 0) { + pr_err("failed to get flowctrl register\n"); + return -ENXIO; } - of_node_put(np); + } else if (IS_ENABLED(CONFIG_ARM)) { + /* + * Hardcoded fallback for 32-bit Tegra + * devices if device tree node is missing. + */ + res.start = 0x60007000; + res.end = 0x60007fff; + res.flags = IORESOURCE_MEM; + } else { + /* + * At this point we're running on a Tegra, + * that doesn't support the flow controller + * (eg. Tegra186), so just return. + */ + return 0; } - tegra_flowctrl_base = ioremap_nocache(base, size); + tegra_flowctrl_base = ioremap_nocache(res.start, resource_size(&res)); + if (!tegra_flowctrl_base) + return -ENXIO; + + return 0; } +early_initcall(tegra_flowctrl_init); diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index de2c1bfe28b5..7413f60fa855 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -18,7 +18,7 @@ #include <linux/clk.h> #include <linux/device.h> #include <linux/kobject.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_address.h> @@ -168,7 +168,7 @@ static struct platform_driver tegra_fuse_driver = { }, .probe = tegra_fuse_probe, }; -module_platform_driver(tegra_fuse_driver); +builtin_platform_driver(tegra_fuse_driver); bool __init tegra_fuse_read_spare(unsigned int spare) { diff --git a/drivers/soc/tegra/pmc-tegra186.c b/drivers/soc/tegra/pmc-tegra186.c new file mode 100644 index 000000000000..6f5c6f98ba92 --- /dev/null +++ b/drivers/soc/tegra/pmc-tegra186.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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) "tegra-pmc: " fmt + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> + +#include <asm/system_misc.h> + +#define PMC_CNTRL 0x000 +#define PMC_CNTRL_MAIN_RST BIT(4) + +#define PMC_RST_STATUS 0x070 + +#define WAKE_AOWAKE_CTRL 0x4f4 +#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) + +#define SCRATCH_SCRATCH0 0x2000 +#define SCRATCH_SCRATCH0_MODE_RECOVERY BIT(31) +#define SCRATCH_SCRATCH0_MODE_BOOTLOADER BIT(30) +#define SCRATCH_SCRATCH0_MODE_RCM BIT(1) +#define SCRATCH_SCRATCH0_MODE_MASK (SCRATCH_SCRATCH0_MODE_RECOVERY | \ + SCRATCH_SCRATCH0_MODE_BOOTLOADER | \ + SCRATCH_SCRATCH0_MODE_RCM) + +struct tegra_pmc { + struct device *dev; + void __iomem *regs; + void __iomem *wake; + void __iomem *aotag; + void __iomem *scratch; + + void (*system_restart)(enum reboot_mode mode, const char *cmd); + struct notifier_block restart; +}; + +static int tegra186_pmc_restart_notify(struct notifier_block *nb, + unsigned long action, + void *data) +{ + struct tegra_pmc *pmc = container_of(nb, struct tegra_pmc, restart); + const char *cmd = data; + u32 value; + + value = readl(pmc->scratch + SCRATCH_SCRATCH0); + value &= ~SCRATCH_SCRATCH0_MODE_MASK; + + if (cmd) { + if (strcmp(cmd, "recovery") == 0) + value |= SCRATCH_SCRATCH0_MODE_RECOVERY; + + if (strcmp(cmd, "bootloader") == 0) + value |= SCRATCH_SCRATCH0_MODE_BOOTLOADER; + + if (strcmp(cmd, "forced-recovery") == 0) + value |= SCRATCH_SCRATCH0_MODE_RCM; + } + + writel(value, pmc->scratch + SCRATCH_SCRATCH0); + + /* + * If available, call the system restart implementation that was + * registered earlier (typically PSCI). + */ + if (pmc->system_restart) { + pmc->system_restart(reboot_mode, cmd); + return NOTIFY_DONE; + } + + /* reset everything but SCRATCH0_SCRATCH0 and PMC_RST_STATUS */ + value = readl(pmc->regs + PMC_CNTRL); + value |= PMC_CNTRL_MAIN_RST; + writel(value, pmc->regs + PMC_CNTRL); + + return NOTIFY_DONE; +} + +static int tegra186_pmc_setup(struct tegra_pmc *pmc) +{ + struct device_node *np = pmc->dev->of_node; + bool invert; + u32 value; + + invert = of_property_read_bool(np, "nvidia,invert-interrupt"); + + value = readl(pmc->wake + WAKE_AOWAKE_CTRL); + + if (invert) + value |= WAKE_AOWAKE_CTRL_INTR_POLARITY; + else + value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY; + + writel(value, pmc->wake + WAKE_AOWAKE_CTRL); + + /* + * We need to hook any system restart implementation registered + * previously so we can write SCRATCH_SCRATCH0 before reset. + */ + pmc->system_restart = arm_pm_restart; + arm_pm_restart = NULL; + + pmc->restart.notifier_call = tegra186_pmc_restart_notify; + pmc->restart.priority = 128; + + return register_restart_handler(&pmc->restart); +} + +static int tegra186_pmc_probe(struct platform_device *pdev) +{ + struct tegra_pmc *pmc; + struct resource *res; + + pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL); + if (!pmc) + return -ENOMEM; + + pmc->dev = &pdev->dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmc"); + pmc->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->regs)) + return PTR_ERR(pmc->regs); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake"); + pmc->wake = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->wake)) + return PTR_ERR(pmc->wake); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag"); + pmc->aotag = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->aotag)) + return PTR_ERR(pmc->aotag); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch"); + pmc->scratch = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->scratch)) + return PTR_ERR(pmc->scratch); + + return tegra186_pmc_setup(pmc); +} + +static const struct of_device_id tegra186_pmc_of_match[] = { + { .compatible = "nvidia,tegra186-pmc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tegra186_pmc_of_match); + +static struct platform_driver tegra186_pmc_driver = { + .driver = { + .name = "tegra186-pmc", + .of_match_table = tegra186_pmc_of_match, + }, + .probe = tegra186_pmc_probe, +}; +builtin_platform_driver(tegra186_pmc_driver); diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index 3557c5e32a93..39e152abe6b9 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -38,4 +38,16 @@ config WKUP_M3_IPC to communicate and use the Wakeup M3 for PM features like suspend resume and boots it using wkup_m3_rproc driver. +config TI_SCI_PM_DOMAINS + tristate "TI SCI PM Domains Driver" + depends on TI_SCI_PROTOCOL + depends on PM_GENERIC_DOMAINS + help + Generic power domain implementation for TI device implementing + the TI SCI protocol. + + To compile this as a module, choose M here. The module will be + called ti_sci_pm_domains. Note this is needed early in boot before + rootfs may be available. + endif # SOC_TI diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile index 48ff3a79634f..7d572736c86e 100644 --- a/drivers/soc/ti/Makefile +++ b/drivers/soc/ti/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o +obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c new file mode 100644 index 000000000000..b0b283810e72 --- /dev/null +++ b/drivers/soc/ti/ti_sci_pm_domains.c @@ -0,0 +1,202 @@ +/* + * TI SCI Generic Power Domain Driver + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ + * J Keerthy <j-keerthy@ti.com> + * Dave Gerlach <d-gerlach@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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/err.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/slab.h> +#include <linux/soc/ti/ti_sci_protocol.h> + +/** + * struct ti_sci_genpd_dev_data: holds data needed for every device attached + * to this genpd + * @idx: index of the device that identifies it with the system + * control processor. + */ +struct ti_sci_genpd_dev_data { + int idx; +}; + +/** + * struct ti_sci_pm_domain: TI specific data needed for power domain + * @ti_sci: handle to TI SCI protocol driver that provides ops to + * communicate with system control processor. + * @dev: pointer to dev for the driver for devm allocs + * @pd: generic_pm_domain for use with the genpd framework + */ +struct ti_sci_pm_domain { + const struct ti_sci_handle *ti_sci; + struct device *dev; + struct generic_pm_domain pd; +}; + +#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd) + +/** + * ti_sci_dev_id(): get prepopulated ti_sci id from struct dev + * @dev: pointer to device associated with this genpd + * + * Returns device_id stored from ti,sci_id property + */ +static int ti_sci_dev_id(struct device *dev) +{ + struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev); + struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data; + + return sci_dev_data->idx; +} + +/** + * ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle + * @dev: pointer to device associated with this genpd + * + * Returns ti_sci_handle to be used to communicate with system + * control processor. + */ +static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev) +{ + struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain); + struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd); + + return ti_sci_genpd->ti_sci; +} + +/** + * ti_sci_dev_start(): genpd device start hook called to turn device on + * @dev: pointer to device associated with this genpd to be powered on + */ +static int ti_sci_dev_start(struct device *dev) +{ + const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev); + int idx = ti_sci_dev_id(dev); + + return ti_sci->ops.dev_ops.get_device(ti_sci, idx); +} + +/** + * ti_sci_dev_stop(): genpd device stop hook called to turn device off + * @dev: pointer to device associated with this genpd to be powered off + */ +static int ti_sci_dev_stop(struct device *dev) +{ + const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev); + int idx = ti_sci_dev_id(dev); + + return ti_sci->ops.dev_ops.put_device(ti_sci, idx); +} + +static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain, + struct device *dev) +{ + struct device_node *np = dev->of_node; + struct of_phandle_args pd_args; + struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain); + const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci; + struct ti_sci_genpd_dev_data *sci_dev_data; + struct generic_pm_domain_data *genpd_data; + int idx, ret = 0; + + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", 0, &pd_args); + if (ret < 0) + return ret; + + if (pd_args.args_count != 1) + return -EINVAL; + + idx = pd_args.args[0]; + + /* + * Check the validity of the requested idx, if the index is not valid + * the PMMC will return a NAK here and we will not allocate it. + */ + ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx); + if (ret) + return -EINVAL; + + sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL); + if (!sci_dev_data) + return -ENOMEM; + + sci_dev_data->idx = idx; + + genpd_data = dev_gpd_data(dev); + genpd_data->data = sci_dev_data; + + return 0; +} + +static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain, + struct device *dev) +{ + struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev); + struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data; + + kfree(sci_dev_data); + genpd_data->data = NULL; +} + +static const struct of_device_id ti_sci_pm_domain_matches[] = { + { .compatible = "ti,sci-pm-domain", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches); + +static int ti_sci_pm_domain_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct ti_sci_pm_domain *ti_sci_pd; + int ret; + + ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL); + if (!ti_sci_pd) + return -ENOMEM; + + ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev); + if (IS_ERR(ti_sci_pd->ti_sci)) + return PTR_ERR(ti_sci_pd->ti_sci); + + ti_sci_pd->dev = dev; + + ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev; + ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev; + + ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start; + ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop; + + pm_genpd_init(&ti_sci_pd->pd, NULL, true); + + ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd); + + return ret; +} + +static struct platform_driver ti_sci_pm_domains_driver = { + .probe = ti_sci_pm_domain_probe, + .driver = { + .name = "ti_sci_pm_domains", + .of_match_table = ti_sci_pm_domain_matches, + }, +}; +module_platform_driver(ti_sci_pm_domains_driver); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI System Control Interface (SCI) Power Domain driver"); +MODULE_AUTHOR("Dave Gerlach"); diff --git a/drivers/soc/zte/zx296718_pm_domains.c b/drivers/soc/zte/zx296718_pm_domains.c index 5ed924fee855..4dc5d62ee81b 100644 --- a/drivers/soc/zte/zx296718_pm_domains.c +++ b/drivers/soc/zte/zx296718_pm_domains.c @@ -169,7 +169,6 @@ static const struct of_device_id zx296718_pm_domain_matches[] = { static struct platform_driver zx296718_pd_driver = { .driver = { .name = "zx296718-powerdomain", - .owner = THIS_MODULE, .of_match_table = zx296718_pm_domain_matches, }, .probe = zx296718_pd_probe, diff --git a/drivers/soc/zte/zx2967_pm_domains.c b/drivers/soc/zte/zx2967_pm_domains.c index 61c8d84bf315..c42aeaaa34ba 100644 --- a/drivers/soc/zte/zx2967_pm_domains.c +++ b/drivers/soc/zte/zx2967_pm_domains.c @@ -125,10 +125,8 @@ int zx2967_pd_probe(struct platform_device *pdev, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pcubase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pcubase)) { - dev_err(&pdev->dev, "ioremap fail.\n"); + if (IS_ERR(pcubase)) return PTR_ERR(pcubase); - } for (i = 0; i < domain_num; ++i) { zx_pm_domains[i]->power_on = zx2967_power_on; diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 6f9d540a97ce..fff930fc3cff 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -1115,7 +1115,7 @@ int ldlm_init(void) ldlm_lock_slab = kmem_cache_create("ldlm_locks", sizeof(struct ldlm_lock), 0, SLAB_HWCACHE_ALIGN | - SLAB_DESTROY_BY_RCU, NULL); + SLAB_TYPESAFE_BY_RCU, NULL); if (!ldlm_lock_slab) { kmem_cache_destroy(ldlm_resource_slab); return -ENOMEM; diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig new file mode 100644 index 000000000000..2330a4eb4e8b --- /dev/null +++ b/drivers/tee/Kconfig @@ -0,0 +1,18 @@ +# Generic Trusted Execution Environment Configuration +config TEE + tristate "Trusted Execution Environment support" + select DMA_SHARED_BUFFER + select GENERIC_ALLOCATOR + help + This implements a generic interface towards a Trusted Execution + Environment (TEE). + +if TEE + +menu "TEE drivers" + +source "drivers/tee/optee/Kconfig" + +endmenu + +endif diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile new file mode 100644 index 000000000000..7a4e4a1ac39c --- /dev/null +++ b/drivers/tee/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_TEE) += tee.o +tee-objs += tee_core.o +tee-objs += tee_shm.o +tee-objs += tee_shm_pool.o +obj-$(CONFIG_OPTEE) += optee/ diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig new file mode 100644 index 000000000000..0126de898036 --- /dev/null +++ b/drivers/tee/optee/Kconfig @@ -0,0 +1,7 @@ +# OP-TEE Trusted Execution Environment Configuration +config OPTEE + tristate "OP-TEE" + depends on HAVE_ARM_SMCCC + help + This implements the OP-TEE Trusted Execution Environment (TEE) + driver. diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile new file mode 100644 index 000000000000..92fe5789bcce --- /dev/null +++ b/drivers/tee/optee/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_OPTEE) += optee.o +optee-objs += core.o +optee-objs += call.o +optee-objs += rpc.o +optee-objs += supp.o diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c new file mode 100644 index 000000000000..f7b7b404c990 --- /dev/null +++ b/drivers/tee/optee/call.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/arm-smccc.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include "optee_private.h" +#include "optee_smc.h" + +struct optee_call_waiter { + struct list_head list_node; + struct completion c; +}; + +static void optee_cq_wait_init(struct optee_call_queue *cq, + struct optee_call_waiter *w) +{ + /* + * We're preparing to make a call to secure world. In case we can't + * allocate a thread in secure world we'll end up waiting in + * optee_cq_wait_for_completion(). + * + * Normally if there's no contention in secure world the call will + * complete and we can cleanup directly with optee_cq_wait_final(). + */ + mutex_lock(&cq->mutex); + + /* + * We add ourselves to the queue, but we don't wait. This + * guarantees that we don't lose a completion if secure world + * returns busy and another thread just exited and try to complete + * someone. + */ + init_completion(&w->c); + list_add_tail(&w->list_node, &cq->waiters); + + mutex_unlock(&cq->mutex); +} + +static void optee_cq_wait_for_completion(struct optee_call_queue *cq, + struct optee_call_waiter *w) +{ + wait_for_completion(&w->c); + + mutex_lock(&cq->mutex); + + /* Move to end of list to get out of the way for other waiters */ + list_del(&w->list_node); + reinit_completion(&w->c); + list_add_tail(&w->list_node, &cq->waiters); + + mutex_unlock(&cq->mutex); +} + +static void optee_cq_complete_one(struct optee_call_queue *cq) +{ + struct optee_call_waiter *w; + + list_for_each_entry(w, &cq->waiters, list_node) { + if (!completion_done(&w->c)) { + complete(&w->c); + break; + } + } +} + +static void optee_cq_wait_final(struct optee_call_queue *cq, + struct optee_call_waiter *w) +{ + /* + * We're done with the call to secure world. The thread in secure + * world that was used for this call is now available for some + * other task to use. + */ + mutex_lock(&cq->mutex); + + /* Get out of the list */ + list_del(&w->list_node); + + /* Wake up one eventual waiting task */ + optee_cq_complete_one(cq); + + /* + * If we're completed we've got a completion from another task that + * was just done with its call to secure world. Since yet another + * thread now is available in secure world wake up another eventual + * waiting task. + */ + if (completion_done(&w->c)) + optee_cq_complete_one(cq); + + mutex_unlock(&cq->mutex); +} + +/* Requires the filpstate mutex to be held */ +static struct optee_session *find_session(struct optee_context_data *ctxdata, + u32 session_id) +{ + struct optee_session *sess; + + list_for_each_entry(sess, &ctxdata->sess_list, list_node) + if (sess->session_id == session_id) + return sess; + + return NULL; +} + +/** + * optee_do_call_with_arg() - Do an SMC to OP-TEE in secure world + * @ctx: calling context + * @parg: physical address of message to pass to secure world + * + * Does and SMC to OP-TEE in secure world and handles eventual resulting + * Remote Procedure Calls (RPC) from OP-TEE. + * + * Returns return code from secure world, 0 is OK + */ +u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg) +{ + struct optee *optee = tee_get_drvdata(ctx->teedev); + struct optee_call_waiter w; + struct optee_rpc_param param = { }; + u32 ret; + + param.a0 = OPTEE_SMC_CALL_WITH_ARG; + reg_pair_from_64(¶m.a1, ¶m.a2, parg); + /* Initialize waiter */ + optee_cq_wait_init(&optee->call_queue, &w); + while (true) { + struct arm_smccc_res res; + + optee->invoke_fn(param.a0, param.a1, param.a2, param.a3, + param.a4, param.a5, param.a6, param.a7, + &res); + + if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) { + /* + * Out of threads in secure world, wait for a thread + * become available. + */ + optee_cq_wait_for_completion(&optee->call_queue, &w); + } else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) { + param.a0 = res.a0; + param.a1 = res.a1; + param.a2 = res.a2; + param.a3 = res.a3; + optee_handle_rpc(ctx, ¶m); + } else { + ret = res.a0; + break; + } + } + + /* + * We're done with our thread in secure world, if there's any + * thread waiters wake up one. + */ + optee_cq_wait_final(&optee->call_queue, &w); + + return ret; +} + +static struct tee_shm *get_msg_arg(struct tee_context *ctx, size_t num_params, + struct optee_msg_arg **msg_arg, + phys_addr_t *msg_parg) +{ + int rc; + struct tee_shm *shm; + struct optee_msg_arg *ma; + + shm = tee_shm_alloc(ctx, OPTEE_MSG_GET_ARG_SIZE(num_params), + TEE_SHM_MAPPED); + if (IS_ERR(shm)) + return shm; + + ma = tee_shm_get_va(shm, 0); + if (IS_ERR(ma)) { + rc = PTR_ERR(ma); + goto out; + } + + rc = tee_shm_get_pa(shm, 0, msg_parg); + if (rc) + goto out; + + memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params)); + ma->num_params = num_params; + *msg_arg = ma; +out: + if (rc) { + tee_shm_free(shm); + return ERR_PTR(rc); + } + + return shm; +} + +int optee_open_session(struct tee_context *ctx, + struct tee_ioctl_open_session_arg *arg, + struct tee_param *param) +{ + struct optee_context_data *ctxdata = ctx->data; + int rc; + struct tee_shm *shm; + struct optee_msg_arg *msg_arg; + phys_addr_t msg_parg; + struct optee_session *sess = NULL; + + /* +2 for the meta parameters added below */ + shm = get_msg_arg(ctx, arg->num_params + 2, &msg_arg, &msg_parg); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + msg_arg->cmd = OPTEE_MSG_CMD_OPEN_SESSION; + msg_arg->cancel_id = arg->cancel_id; + + /* + * Initialize and add the meta parameters needed when opening a + * session. + */ + msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT | + OPTEE_MSG_ATTR_META; + msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT | + OPTEE_MSG_ATTR_META; + memcpy(&msg_arg->params[0].u.value, arg->uuid, sizeof(arg->uuid)); + memcpy(&msg_arg->params[1].u.value, arg->uuid, sizeof(arg->clnt_uuid)); + msg_arg->params[1].u.value.c = arg->clnt_login; + + rc = optee_to_msg_param(msg_arg->params + 2, arg->num_params, param); + if (rc) + goto out; + + sess = kzalloc(sizeof(*sess), GFP_KERNEL); + if (!sess) { + rc = -ENOMEM; + goto out; + } + + if (optee_do_call_with_arg(ctx, msg_parg)) { + msg_arg->ret = TEEC_ERROR_COMMUNICATION; + msg_arg->ret_origin = TEEC_ORIGIN_COMMS; + } + + if (msg_arg->ret == TEEC_SUCCESS) { + /* A new session has been created, add it to the list. */ + sess->session_id = msg_arg->session; + mutex_lock(&ctxdata->mutex); + list_add(&sess->list_node, &ctxdata->sess_list); + mutex_unlock(&ctxdata->mutex); + } else { + kfree(sess); + } + + if (optee_from_msg_param(param, arg->num_params, msg_arg->params + 2)) { + arg->ret = TEEC_ERROR_COMMUNICATION; + arg->ret_origin = TEEC_ORIGIN_COMMS; + /* Close session again to avoid leakage */ + optee_close_session(ctx, msg_arg->session); + } else { + arg->session = msg_arg->session; + arg->ret = msg_arg->ret; + arg->ret_origin = msg_arg->ret_origin; + } +out: + tee_shm_free(shm); + + return rc; +} + +int optee_close_session(struct tee_context *ctx, u32 session) +{ + struct optee_context_data *ctxdata = ctx->data; + struct tee_shm *shm; + struct optee_msg_arg *msg_arg; + phys_addr_t msg_parg; + struct optee_session *sess; + + /* Check that the session is valid and remove it from the list */ + mutex_lock(&ctxdata->mutex); + sess = find_session(ctxdata, session); + if (sess) + list_del(&sess->list_node); + mutex_unlock(&ctxdata->mutex); + if (!sess) + return -EINVAL; + kfree(sess); + + shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION; + msg_arg->session = session; + optee_do_call_with_arg(ctx, msg_parg); + + tee_shm_free(shm); + return 0; +} + +int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, + struct tee_param *param) +{ + struct optee_context_data *ctxdata = ctx->data; + struct tee_shm *shm; + struct optee_msg_arg *msg_arg; + phys_addr_t msg_parg; + struct optee_session *sess; + int rc; + + /* Check that the session is valid */ + mutex_lock(&ctxdata->mutex); + sess = find_session(ctxdata, arg->session); + mutex_unlock(&ctxdata->mutex); + if (!sess) + return -EINVAL; + + shm = get_msg_arg(ctx, arg->num_params, &msg_arg, &msg_parg); + if (IS_ERR(shm)) + return PTR_ERR(shm); + msg_arg->cmd = OPTEE_MSG_CMD_INVOKE_COMMAND; + msg_arg->func = arg->func; + msg_arg->session = arg->session; + msg_arg->cancel_id = arg->cancel_id; + + rc = optee_to_msg_param(msg_arg->params, arg->num_params, param); + if (rc) + goto out; + + if (optee_do_call_with_arg(ctx, msg_parg)) { + msg_arg->ret = TEEC_ERROR_COMMUNICATION; + msg_arg->ret_origin = TEEC_ORIGIN_COMMS; + } + + if (optee_from_msg_param(param, arg->num_params, msg_arg->params)) { + msg_arg->ret = TEEC_ERROR_COMMUNICATION; + msg_arg->ret_origin = TEEC_ORIGIN_COMMS; + } + + arg->ret = msg_arg->ret; + arg->ret_origin = msg_arg->ret_origin; +out: + tee_shm_free(shm); + return rc; +} + +int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session) +{ + struct optee_context_data *ctxdata = ctx->data; + struct tee_shm *shm; + struct optee_msg_arg *msg_arg; + phys_addr_t msg_parg; + struct optee_session *sess; + + /* Check that the session is valid */ + mutex_lock(&ctxdata->mutex); + sess = find_session(ctxdata, session); + mutex_unlock(&ctxdata->mutex); + if (!sess) + return -EINVAL; + + shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + msg_arg->cmd = OPTEE_MSG_CMD_CANCEL; + msg_arg->session = session; + msg_arg->cancel_id = cancel_id; + optee_do_call_with_arg(ctx, msg_parg); + + tee_shm_free(shm); + return 0; +} + +/** + * optee_enable_shm_cache() - Enables caching of some shared memory allocation + * in OP-TEE + * @optee: main service struct + */ +void optee_enable_shm_cache(struct optee *optee) +{ + struct optee_call_waiter w; + + /* We need to retry until secure world isn't busy. */ + optee_cq_wait_init(&optee->call_queue, &w); + while (true) { + struct arm_smccc_res res; + + optee->invoke_fn(OPTEE_SMC_ENABLE_SHM_CACHE, 0, 0, 0, 0, 0, 0, + 0, &res); + if (res.a0 == OPTEE_SMC_RETURN_OK) + break; + optee_cq_wait_for_completion(&optee->call_queue, &w); + } + optee_cq_wait_final(&optee->call_queue, &w); +} + +/** + * optee_disable_shm_cache() - Disables caching of some shared memory allocation + * in OP-TEE + * @optee: main service struct + */ +void optee_disable_shm_cache(struct optee *optee) +{ + struct optee_call_waiter w; + + /* We need to retry until secure world isn't busy. */ + optee_cq_wait_init(&optee->call_queue, &w); + while (true) { + union { + struct arm_smccc_res smccc; + struct optee_smc_disable_shm_cache_result result; + } res; + + optee->invoke_fn(OPTEE_SMC_DISABLE_SHM_CACHE, 0, 0, 0, 0, 0, 0, + 0, &res.smccc); + if (res.result.status == OPTEE_SMC_RETURN_ENOTAVAIL) + break; /* All shm's freed */ + if (res.result.status == OPTEE_SMC_RETURN_OK) { + struct tee_shm *shm; + + shm = reg_pair_to_ptr(res.result.shm_upper32, + res.result.shm_lower32); + tee_shm_free(shm); + } else { + optee_cq_wait_for_completion(&optee->call_queue, &w); + } + } + optee_cq_wait_final(&optee->call_queue, &w); +} diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c new file mode 100644 index 000000000000..58169e519422 --- /dev/null +++ b/drivers/tee/optee/core.c @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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) KBUILD_MODNAME ": " fmt + +#include <linux/arm-smccc.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/tee_drv.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include "optee_private.h" +#include "optee_smc.h" + +#define DRIVER_NAME "optee" + +#define OPTEE_SHM_NUM_PRIV_PAGES 1 + +/** + * optee_from_msg_param() - convert from OPTEE_MSG parameters to + * struct tee_param + * @params: subsystem internal parameter representation + * @num_params: number of elements in the parameter arrays + * @msg_params: OPTEE_MSG parameters + * Returns 0 on success or <0 on failure + */ +int optee_from_msg_param(struct tee_param *params, size_t num_params, + const struct optee_msg_param *msg_params) +{ + int rc; + size_t n; + struct tee_shm *shm; + phys_addr_t pa; + + for (n = 0; n < num_params; n++) { + struct tee_param *p = params + n; + const struct optee_msg_param *mp = msg_params + n; + u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK; + + switch (attr) { + case OPTEE_MSG_ATTR_TYPE_NONE: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + memset(&p->u, 0, sizeof(p->u)); + break; + case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT: + case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT: + case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT + + attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + p->u.value.a = mp->u.value.a; + p->u.value.b = mp->u.value.b; + p->u.value.c = mp->u.value.c; + break; + case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT: + case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT: + case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT + + attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; + p->u.memref.size = mp->u.tmem.size; + shm = (struct tee_shm *)(unsigned long) + mp->u.tmem.shm_ref; + if (!shm) { + p->u.memref.shm_offs = 0; + p->u.memref.shm = NULL; + break; + } + rc = tee_shm_get_pa(shm, 0, &pa); + if (rc) + return rc; + p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa; + p->u.memref.shm = shm; + + /* Check that the memref is covered by the shm object */ + if (p->u.memref.size) { + size_t o = p->u.memref.shm_offs + + p->u.memref.size - 1; + + rc = tee_shm_get_pa(shm, o, NULL); + if (rc) + return rc; + } + break; + default: + return -EINVAL; + } + } + return 0; +} + +/** + * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters + * @msg_params: OPTEE_MSG parameters + * @num_params: number of elements in the parameter arrays + * @params: subsystem itnernal parameter representation + * Returns 0 on success or <0 on failure + */ +int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params, + const struct tee_param *params) +{ + int rc; + size_t n; + phys_addr_t pa; + + for (n = 0; n < num_params; n++) { + const struct tee_param *p = params + n; + struct optee_msg_param *mp = msg_params + n; + + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + memset(&mp->u, 0, sizeof(mp->u)); + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr - + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + mp->u.value.a = p->u.value.a; + mp->u.value.b = p->u.value.b; + mp->u.value.c = p->u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + + p->attr - + TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm; + mp->u.tmem.size = p->u.memref.size; + if (!p->u.memref.shm) { + mp->u.tmem.buf_ptr = 0; + break; + } + rc = tee_shm_get_pa(p->u.memref.shm, + p->u.memref.shm_offs, &pa); + if (rc) + return rc; + mp->u.tmem.buf_ptr = pa; + mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED << + OPTEE_MSG_ATTR_CACHE_SHIFT; + break; + default: + return -EINVAL; + } + } + return 0; +} + +static void optee_get_version(struct tee_device *teedev, + struct tee_ioctl_version_data *vers) +{ + struct tee_ioctl_version_data v = { + .impl_id = TEE_IMPL_ID_OPTEE, + .impl_caps = TEE_OPTEE_CAP_TZ, + .gen_caps = TEE_GEN_CAP_GP, + }; + *vers = v; +} + +static int optee_open(struct tee_context *ctx) +{ + struct optee_context_data *ctxdata; + struct tee_device *teedev = ctx->teedev; + struct optee *optee = tee_get_drvdata(teedev); + + ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL); + if (!ctxdata) + return -ENOMEM; + + if (teedev == optee->supp_teedev) { + bool busy = true; + + mutex_lock(&optee->supp.ctx_mutex); + if (!optee->supp.ctx) { + busy = false; + optee->supp.ctx = ctx; + } + mutex_unlock(&optee->supp.ctx_mutex); + if (busy) { + kfree(ctxdata); + return -EBUSY; + } + } + + mutex_init(&ctxdata->mutex); + INIT_LIST_HEAD(&ctxdata->sess_list); + + ctx->data = ctxdata; + return 0; +} + +static void optee_release(struct tee_context *ctx) +{ + struct optee_context_data *ctxdata = ctx->data; + struct tee_device *teedev = ctx->teedev; + struct optee *optee = tee_get_drvdata(teedev); + struct tee_shm *shm; + struct optee_msg_arg *arg = NULL; + phys_addr_t parg; + struct optee_session *sess; + struct optee_session *sess_tmp; + + if (!ctxdata) + return; + + shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED); + if (!IS_ERR(shm)) { + arg = tee_shm_get_va(shm, 0); + /* + * If va2pa fails for some reason, we can't call + * optee_close_session(), only free the memory. Secure OS + * will leak sessions and finally refuse more sessions, but + * we will at least let normal world reclaim its memory. + */ + if (!IS_ERR(arg)) + tee_shm_va2pa(shm, arg, &parg); + } + + list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list, + list_node) { + list_del(&sess->list_node); + if (!IS_ERR_OR_NULL(arg)) { + memset(arg, 0, sizeof(*arg)); + arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION; + arg->session = sess->session_id; + optee_do_call_with_arg(ctx, parg); + } + kfree(sess); + } + kfree(ctxdata); + + if (!IS_ERR(shm)) + tee_shm_free(shm); + + ctx->data = NULL; + + if (teedev == optee->supp_teedev) { + mutex_lock(&optee->supp.ctx_mutex); + optee->supp.ctx = NULL; + mutex_unlock(&optee->supp.ctx_mutex); + } +} + +static struct tee_driver_ops optee_ops = { + .get_version = optee_get_version, + .open = optee_open, + .release = optee_release, + .open_session = optee_open_session, + .close_session = optee_close_session, + .invoke_func = optee_invoke_func, + .cancel_req = optee_cancel_req, +}; + +static struct tee_desc optee_desc = { + .name = DRIVER_NAME "-clnt", + .ops = &optee_ops, + .owner = THIS_MODULE, +}; + +static struct tee_driver_ops optee_supp_ops = { + .get_version = optee_get_version, + .open = optee_open, + .release = optee_release, + .supp_recv = optee_supp_recv, + .supp_send = optee_supp_send, +}; + +static struct tee_desc optee_supp_desc = { + .name = DRIVER_NAME "-supp", + .ops = &optee_supp_ops, + .owner = THIS_MODULE, + .flags = TEE_DESC_PRIVILEGED, +}; + +static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn) +{ + struct arm_smccc_res res; + + invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res); + + if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 && + res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3) + return true; + return false; +} + +static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn) +{ + union { + struct arm_smccc_res smccc; + struct optee_smc_calls_revision_result result; + } res; + + invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc); + + if (res.result.major == OPTEE_MSG_REVISION_MAJOR && + (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR) + return true; + return false; +} + +static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn, + u32 *sec_caps) +{ + union { + struct arm_smccc_res smccc; + struct optee_smc_exchange_capabilities_result result; + } res; + u32 a1 = 0; + + /* + * TODO This isn't enough to tell if it's UP system (from kernel + * point of view) or not, is_smp() returns the the information + * needed, but can't be called directly from here. + */ + if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1) + a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR; + + invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0, + &res.smccc); + + if (res.result.status != OPTEE_SMC_RETURN_OK) + return false; + + *sec_caps = res.result.capabilities; + return true; +} + +static struct tee_shm_pool * +optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm) +{ + union { + struct arm_smccc_res smccc; + struct optee_smc_get_shm_config_result result; + } res; + struct tee_shm_pool *pool; + unsigned long vaddr; + phys_addr_t paddr; + size_t size; + phys_addr_t begin; + phys_addr_t end; + void *va; + struct tee_shm_pool_mem_info priv_info; + struct tee_shm_pool_mem_info dmabuf_info; + + invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc); + if (res.result.status != OPTEE_SMC_RETURN_OK) { + pr_info("shm service not available\n"); + return ERR_PTR(-ENOENT); + } + + if (res.result.settings != OPTEE_SMC_SHM_CACHED) { + pr_err("only normal cached shared memory supported\n"); + return ERR_PTR(-EINVAL); + } + + begin = roundup(res.result.start, PAGE_SIZE); + end = rounddown(res.result.start + res.result.size, PAGE_SIZE); + paddr = begin; + size = end - begin; + + if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) { + pr_err("too small shared memory area\n"); + return ERR_PTR(-EINVAL); + } + + va = memremap(paddr, size, MEMREMAP_WB); + if (!va) { + pr_err("shared memory ioremap failed\n"); + return ERR_PTR(-EINVAL); + } + vaddr = (unsigned long)va; + + priv_info.vaddr = vaddr; + priv_info.paddr = paddr; + priv_info.size = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; + dmabuf_info.vaddr = vaddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; + dmabuf_info.paddr = paddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; + dmabuf_info.size = size - OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; + + pool = tee_shm_pool_alloc_res_mem(&priv_info, &dmabuf_info); + if (IS_ERR(pool)) { + memunmap(va); + goto out; + } + + *memremaped_shm = va; +out: + return pool; +} + +/* Simple wrapper functions to be able to use a function pointer */ +static void optee_smccc_smc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res) +{ + arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res); +} + +static void optee_smccc_hvc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res) +{ + arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res); +} + +static optee_invoke_fn *get_invoke_func(struct device_node *np) +{ + const char *method; + + pr_info("probing for conduit method from DT.\n"); + + if (of_property_read_string(np, "method", &method)) { + pr_warn("missing \"method\" property\n"); + return ERR_PTR(-ENXIO); + } + + if (!strcmp("hvc", method)) + return optee_smccc_hvc; + else if (!strcmp("smc", method)) + return optee_smccc_smc; + + pr_warn("invalid \"method\" property: %s\n", method); + return ERR_PTR(-EINVAL); +} + +static struct optee *optee_probe(struct device_node *np) +{ + optee_invoke_fn *invoke_fn; + struct tee_shm_pool *pool; + struct optee *optee = NULL; + void *memremaped_shm = NULL; + struct tee_device *teedev; + u32 sec_caps; + int rc; + + invoke_fn = get_invoke_func(np); + if (IS_ERR(invoke_fn)) + return (void *)invoke_fn; + + if (!optee_msg_api_uid_is_optee_api(invoke_fn)) { + pr_warn("api uid mismatch\n"); + return ERR_PTR(-EINVAL); + } + + if (!optee_msg_api_revision_is_compatible(invoke_fn)) { + pr_warn("api revision mismatch\n"); + return ERR_PTR(-EINVAL); + } + + if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) { + pr_warn("capabilities mismatch\n"); + return ERR_PTR(-EINVAL); + } + + /* + * We have no other option for shared memory, if secure world + * doesn't have any reserved memory we can use we can't continue. + */ + if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) + return ERR_PTR(-EINVAL); + + pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm); + if (IS_ERR(pool)) + return (void *)pool; + + optee = kzalloc(sizeof(*optee), GFP_KERNEL); + if (!optee) { + rc = -ENOMEM; + goto err; + } + + optee->invoke_fn = invoke_fn; + + teedev = tee_device_alloc(&optee_desc, NULL, pool, optee); + if (IS_ERR(teedev)) { + rc = PTR_ERR(teedev); + goto err; + } + optee->teedev = teedev; + + teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee); + if (IS_ERR(teedev)) { + rc = PTR_ERR(teedev); + goto err; + } + optee->supp_teedev = teedev; + + rc = tee_device_register(optee->teedev); + if (rc) + goto err; + + rc = tee_device_register(optee->supp_teedev); + if (rc) + goto err; + + mutex_init(&optee->call_queue.mutex); + INIT_LIST_HEAD(&optee->call_queue.waiters); + optee_wait_queue_init(&optee->wait_queue); + optee_supp_init(&optee->supp); + optee->memremaped_shm = memremaped_shm; + optee->pool = pool; + + optee_enable_shm_cache(optee); + + pr_info("initialized driver\n"); + return optee; +err: + if (optee) { + /* + * tee_device_unregister() is safe to call even if the + * devices hasn't been registered with + * tee_device_register() yet. + */ + tee_device_unregister(optee->supp_teedev); + tee_device_unregister(optee->teedev); + kfree(optee); + } + if (pool) + tee_shm_pool_free(pool); + if (memremaped_shm) + memunmap(memremaped_shm); + return ERR_PTR(rc); +} + +static void optee_remove(struct optee *optee) +{ + /* + * Ask OP-TEE to free all cached shared memory objects to decrease + * reference counters and also avoid wild pointers in secure world + * into the old shared memory range. + */ + optee_disable_shm_cache(optee); + + /* + * The two devices has to be unregistered before we can free the + * other resources. + */ + tee_device_unregister(optee->supp_teedev); + tee_device_unregister(optee->teedev); + + tee_shm_pool_free(optee->pool); + if (optee->memremaped_shm) + memunmap(optee->memremaped_shm); + optee_wait_queue_exit(&optee->wait_queue); + optee_supp_uninit(&optee->supp); + mutex_destroy(&optee->call_queue.mutex); + + kfree(optee); +} + +static const struct of_device_id optee_match[] = { + { .compatible = "linaro,optee-tz" }, + {}, +}; + +static struct optee *optee_svc; + +static int __init optee_driver_init(void) +{ + struct device_node *fw_np; + struct device_node *np; + struct optee *optee; + + /* Node is supposed to be below /firmware */ + fw_np = of_find_node_by_name(NULL, "firmware"); + if (!fw_np) + return -ENODEV; + + np = of_find_matching_node(fw_np, optee_match); + of_node_put(fw_np); + if (!np) + return -ENODEV; + + optee = optee_probe(np); + of_node_put(np); + + if (IS_ERR(optee)) + return PTR_ERR(optee); + + optee_svc = optee; + + return 0; +} +module_init(optee_driver_init); + +static void __exit optee_driver_exit(void) +{ + struct optee *optee = optee_svc; + + optee_svc = NULL; + if (optee) + optee_remove(optee); +} +module_exit(optee_driver_exit); + +MODULE_AUTHOR("Linaro"); +MODULE_DESCRIPTION("OP-TEE driver"); +MODULE_SUPPORTED_DEVICE(""); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h new file mode 100644 index 000000000000..dd7a06ee0462 --- /dev/null +++ b/drivers/tee/optee/optee_msg.h @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _OPTEE_MSG_H +#define _OPTEE_MSG_H + +#include <linux/bitops.h> +#include <linux/types.h> + +/* + * This file defines the OP-TEE message protocol used to communicate + * with an instance of OP-TEE running in secure world. + * + * This file is divided into three sections. + * 1. Formatting of messages. + * 2. Requests from normal world + * 3. Requests from secure world, Remote Procedure Call (RPC), handled by + * tee-supplicant. + */ + +/***************************************************************************** + * Part 1 - formatting of messages + *****************************************************************************/ + +#define OPTEE_MSG_ATTR_TYPE_NONE 0x0 +#define OPTEE_MSG_ATTR_TYPE_VALUE_INPUT 0x1 +#define OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT 0x2 +#define OPTEE_MSG_ATTR_TYPE_VALUE_INOUT 0x3 +#define OPTEE_MSG_ATTR_TYPE_RMEM_INPUT 0x5 +#define OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT 0x6 +#define OPTEE_MSG_ATTR_TYPE_RMEM_INOUT 0x7 +#define OPTEE_MSG_ATTR_TYPE_TMEM_INPUT 0x9 +#define OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT 0xa +#define OPTEE_MSG_ATTR_TYPE_TMEM_INOUT 0xb + +#define OPTEE_MSG_ATTR_TYPE_MASK GENMASK(7, 0) + +/* + * Meta parameter to be absorbed by the Secure OS and not passed + * to the Trusted Application. + * + * Currently only used with OPTEE_MSG_CMD_OPEN_SESSION. + */ +#define OPTEE_MSG_ATTR_META BIT(8) + +/* + * The temporary shared memory object is not physically contigous and this + * temp memref is followed by another fragment until the last temp memref + * that doesn't have this bit set. + */ +#define OPTEE_MSG_ATTR_FRAGMENT BIT(9) + +/* + * Memory attributes for caching passed with temp memrefs. The actual value + * used is defined outside the message protocol with the exception of + * OPTEE_MSG_ATTR_CACHE_PREDEFINED which means the attributes already + * defined for the memory range should be used. If optee_smc.h is used as + * bearer of this protocol OPTEE_SMC_SHM_* is used for values. + */ +#define OPTEE_MSG_ATTR_CACHE_SHIFT 16 +#define OPTEE_MSG_ATTR_CACHE_MASK GENMASK(2, 0) +#define OPTEE_MSG_ATTR_CACHE_PREDEFINED 0 + +/* + * Same values as TEE_LOGIN_* from TEE Internal API + */ +#define OPTEE_MSG_LOGIN_PUBLIC 0x00000000 +#define OPTEE_MSG_LOGIN_USER 0x00000001 +#define OPTEE_MSG_LOGIN_GROUP 0x00000002 +#define OPTEE_MSG_LOGIN_APPLICATION 0x00000004 +#define OPTEE_MSG_LOGIN_APPLICATION_USER 0x00000005 +#define OPTEE_MSG_LOGIN_APPLICATION_GROUP 0x00000006 + +/** + * struct optee_msg_param_tmem - temporary memory reference parameter + * @buf_ptr: Address of the buffer + * @size: Size of the buffer + * @shm_ref: Temporary shared memory reference, pointer to a struct tee_shm + * + * Secure and normal world communicates pointers as physical address + * instead of the virtual address. This is because secure and normal world + * have completely independent memory mapping. Normal world can even have a + * hypervisor which need to translate the guest physical address (AKA IPA + * in ARM documentation) to a real physical address before passing the + * structure to secure world. + */ +struct optee_msg_param_tmem { + u64 buf_ptr; + u64 size; + u64 shm_ref; +}; + +/** + * struct optee_msg_param_rmem - registered memory reference parameter + * @offs: Offset into shared memory reference + * @size: Size of the buffer + * @shm_ref: Shared memory reference, pointer to a struct tee_shm + */ +struct optee_msg_param_rmem { + u64 offs; + u64 size; + u64 shm_ref; +}; + +/** + * struct optee_msg_param_value - opaque value parameter + * + * Value parameters are passed unchecked between normal and secure world. + */ +struct optee_msg_param_value { + u64 a; + u64 b; + u64 c; +}; + +/** + * struct optee_msg_param - parameter used together with struct optee_msg_arg + * @attr: attributes + * @tmem: parameter by temporary memory reference + * @rmem: parameter by registered memory reference + * @value: parameter by opaque value + * + * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in + * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value, + * OPTEE_MSG_ATTR_TYPE_TMEM_* indicates tmem and + * OPTEE_MSG_ATTR_TYPE_RMEM_* indicates rmem. + * OPTEE_MSG_ATTR_TYPE_NONE indicates that none of the members are used. + */ +struct optee_msg_param { + u64 attr; + union { + struct optee_msg_param_tmem tmem; + struct optee_msg_param_rmem rmem; + struct optee_msg_param_value value; + } u; +}; + +/** + * struct optee_msg_arg - call argument + * @cmd: Command, one of OPTEE_MSG_CMD_* or OPTEE_MSG_RPC_CMD_* + * @func: Trusted Application function, specific to the Trusted Application, + * used if cmd == OPTEE_MSG_CMD_INVOKE_COMMAND + * @session: In parameter for all OPTEE_MSG_CMD_* except + * OPTEE_MSG_CMD_OPEN_SESSION where it's an output parameter instead + * @cancel_id: Cancellation id, a unique value to identify this request + * @ret: return value + * @ret_origin: origin of the return value + * @num_params: number of parameters supplied to the OS Command + * @params: the parameters supplied to the OS Command + * + * All normal calls to Trusted OS uses this struct. If cmd requires further + * information than what these field holds it can be passed as a parameter + * tagged as meta (setting the OPTEE_MSG_ATTR_META bit in corresponding + * attrs field). All parameters tagged as meta has to come first. + * + * Temp memref parameters can be fragmented if supported by the Trusted OS + * (when optee_smc.h is bearer of this protocol this is indicated with + * OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM). If a logical memref parameter is + * fragmented then has all but the last fragment the + * OPTEE_MSG_ATTR_FRAGMENT bit set in attrs. Even if a memref is fragmented + * it will still be presented as a single logical memref to the Trusted + * Application. + */ +struct optee_msg_arg { + u32 cmd; + u32 func; + u32 session; + u32 cancel_id; + u32 pad; + u32 ret; + u32 ret_origin; + u32 num_params; + + /* num_params tells the actual number of element in params */ + struct optee_msg_param params[0]; +}; + +/** + * OPTEE_MSG_GET_ARG_SIZE - return size of struct optee_msg_arg + * + * @num_params: Number of parameters embedded in the struct optee_msg_arg + * + * Returns the size of the struct optee_msg_arg together with the number + * of embedded parameters. + */ +#define OPTEE_MSG_GET_ARG_SIZE(num_params) \ + (sizeof(struct optee_msg_arg) + \ + sizeof(struct optee_msg_param) * (num_params)) + +/***************************************************************************** + * Part 2 - requests from normal world + *****************************************************************************/ + +/* + * Return the following UID if using API specified in this file without + * further extensions: + * 384fb3e0-e7f8-11e3-af63-0002a5d5c51b. + * Represented in 4 32-bit words in OPTEE_MSG_UID_0, OPTEE_MSG_UID_1, + * OPTEE_MSG_UID_2, OPTEE_MSG_UID_3. + */ +#define OPTEE_MSG_UID_0 0x384fb3e0 +#define OPTEE_MSG_UID_1 0xe7f811e3 +#define OPTEE_MSG_UID_2 0xaf630002 +#define OPTEE_MSG_UID_3 0xa5d5c51b +#define OPTEE_MSG_FUNCID_CALLS_UID 0xFF01 + +/* + * Returns 2.0 if using API specified in this file without further + * extensions. Represented in 2 32-bit words in OPTEE_MSG_REVISION_MAJOR + * and OPTEE_MSG_REVISION_MINOR + */ +#define OPTEE_MSG_REVISION_MAJOR 2 +#define OPTEE_MSG_REVISION_MINOR 0 +#define OPTEE_MSG_FUNCID_CALLS_REVISION 0xFF03 + +/* + * Get UUID of Trusted OS. + * + * Used by non-secure world to figure out which Trusted OS is installed. + * Note that returned UUID is the UUID of the Trusted OS, not of the API. + * + * Returns UUID in 4 32-bit words in the same way as + * OPTEE_MSG_FUNCID_CALLS_UID described above. + */ +#define OPTEE_MSG_OS_OPTEE_UUID_0 0x486178e0 +#define OPTEE_MSG_OS_OPTEE_UUID_1 0xe7f811e3 +#define OPTEE_MSG_OS_OPTEE_UUID_2 0xbc5e0002 +#define OPTEE_MSG_OS_OPTEE_UUID_3 0xa5d5c51b +#define OPTEE_MSG_FUNCID_GET_OS_UUID 0x0000 + +/* + * Get revision of Trusted OS. + * + * Used by non-secure world to figure out which version of the Trusted OS + * is installed. Note that the returned revision is the revision of the + * Trusted OS, not of the API. + * + * Returns revision in 2 32-bit words in the same way as + * OPTEE_MSG_CALLS_REVISION described above. + */ +#define OPTEE_MSG_FUNCID_GET_OS_REVISION 0x0001 + +/* + * Do a secure call with struct optee_msg_arg as argument + * The OPTEE_MSG_CMD_* below defines what goes in struct optee_msg_arg::cmd + * + * OPTEE_MSG_CMD_OPEN_SESSION opens a session to a Trusted Application. + * The first two parameters are tagged as meta, holding two value + * parameters to pass the following information: + * param[0].u.value.a-b uuid of Trusted Application + * param[1].u.value.a-b uuid of Client + * param[1].u.value.c Login class of client OPTEE_MSG_LOGIN_* + * + * OPTEE_MSG_CMD_INVOKE_COMMAND invokes a command a previously opened + * session to a Trusted Application. struct optee_msg_arg::func is Trusted + * Application function, specific to the Trusted Application. + * + * OPTEE_MSG_CMD_CLOSE_SESSION closes a previously opened session to + * Trusted Application. + * + * OPTEE_MSG_CMD_CANCEL cancels a currently invoked command. + * + * OPTEE_MSG_CMD_REGISTER_SHM registers a shared memory reference. The + * information is passed as: + * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + * [| OPTEE_MSG_ATTR_FRAGMENT] + * [in] param[0].u.tmem.buf_ptr physical address (of first fragment) + * [in] param[0].u.tmem.size size (of first fragment) + * [in] param[0].u.tmem.shm_ref holds shared memory reference + * ... + * The shared memory can optionally be fragmented, temp memrefs can follow + * each other with all but the last with the OPTEE_MSG_ATTR_FRAGMENT bit set. + * + * OPTEE_MSG_CMD_UNREGISTER_SHM unregisteres a previously registered shared + * memory reference. The information is passed as: + * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + * [in] param[0].u.rmem.shm_ref holds shared memory reference + * [in] param[0].u.rmem.offs 0 + * [in] param[0].u.rmem.size 0 + */ +#define OPTEE_MSG_CMD_OPEN_SESSION 0 +#define OPTEE_MSG_CMD_INVOKE_COMMAND 1 +#define OPTEE_MSG_CMD_CLOSE_SESSION 2 +#define OPTEE_MSG_CMD_CANCEL 3 +#define OPTEE_MSG_CMD_REGISTER_SHM 4 +#define OPTEE_MSG_CMD_UNREGISTER_SHM 5 +#define OPTEE_MSG_FUNCID_CALL_WITH_ARG 0x0004 + +/***************************************************************************** + * Part 3 - Requests from secure world, RPC + *****************************************************************************/ + +/* + * All RPC is done with a struct optee_msg_arg as bearer of information, + * struct optee_msg_arg::arg holds values defined by OPTEE_MSG_RPC_CMD_* below + * + * RPC communication with tee-supplicant is reversed compared to normal + * client communication desribed above. The supplicant receives requests + * and sends responses. + */ + +/* + * Load a TA into memory, defined in tee-supplicant + */ +#define OPTEE_MSG_RPC_CMD_LOAD_TA 0 + +/* + * Reserved + */ +#define OPTEE_MSG_RPC_CMD_RPMB 1 + +/* + * File system access, defined in tee-supplicant + */ +#define OPTEE_MSG_RPC_CMD_FS 2 + +/* + * Get time + * + * Returns number of seconds and nano seconds since the Epoch, + * 1970-01-01 00:00:00 +0000 (UTC). + * + * [out] param[0].u.value.a Number of seconds + * [out] param[0].u.value.b Number of nano seconds. + */ +#define OPTEE_MSG_RPC_CMD_GET_TIME 3 + +/* + * Wait queue primitive, helper for secure world to implement a wait queue. + * + * If secure world need to wait for a secure world mutex it issues a sleep + * request instead of spinning in secure world. Conversely is a wakeup + * request issued when a secure world mutex with a thread waiting thread is + * unlocked. + * + * Waiting on a key + * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP + * [in] param[0].u.value.b wait key + * + * Waking up a key + * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP + * [in] param[0].u.value.b wakeup key + */ +#define OPTEE_MSG_RPC_CMD_WAIT_QUEUE 4 +#define OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP 0 +#define OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP 1 + +/* + * Suspend execution + * + * [in] param[0].value .a number of milliseconds to suspend + */ +#define OPTEE_MSG_RPC_CMD_SUSPEND 5 + +/* + * Allocate a piece of shared memory + * + * Shared memory can optionally be fragmented, to support that additional + * spare param entries are allocated to make room for eventual fragments. + * The spare param entries has .attr = OPTEE_MSG_ATTR_TYPE_NONE when + * unused. All returned temp memrefs except the last should have the + * OPTEE_MSG_ATTR_FRAGMENT bit set in the attr field. + * + * [in] param[0].u.value.a type of memory one of + * OPTEE_MSG_RPC_SHM_TYPE_* below + * [in] param[0].u.value.b requested size + * [in] param[0].u.value.c required alignment + * + * [out] param[0].u.tmem.buf_ptr physical address (of first fragment) + * [out] param[0].u.tmem.size size (of first fragment) + * [out] param[0].u.tmem.shm_ref shared memory reference + * ... + * [out] param[n].u.tmem.buf_ptr physical address + * [out] param[n].u.tmem.size size + * [out] param[n].u.tmem.shm_ref shared memory reference (same value + * as in param[n-1].u.tmem.shm_ref) + */ +#define OPTEE_MSG_RPC_CMD_SHM_ALLOC 6 +/* Memory that can be shared with a non-secure user space application */ +#define OPTEE_MSG_RPC_SHM_TYPE_APPL 0 +/* Memory only shared with non-secure kernel */ +#define OPTEE_MSG_RPC_SHM_TYPE_KERNEL 1 + +/* + * Free shared memory previously allocated with OPTEE_MSG_RPC_CMD_SHM_ALLOC + * + * [in] param[0].u.value.a type of memory one of + * OPTEE_MSG_RPC_SHM_TYPE_* above + * [in] param[0].u.value.b value of shared memory reference + * returned in param[0].u.tmem.shm_ref + * above + */ +#define OPTEE_MSG_RPC_CMD_SHM_FREE 7 + +#endif /* _OPTEE_MSG_H */ diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h new file mode 100644 index 000000000000..c374cd594314 --- /dev/null +++ b/drivers/tee/optee/optee_private.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 OPTEE_PRIVATE_H +#define OPTEE_PRIVATE_H + +#include <linux/arm-smccc.h> +#include <linux/semaphore.h> +#include <linux/tee_drv.h> +#include <linux/types.h> +#include "optee_msg.h" + +#define OPTEE_MAX_ARG_SIZE 1024 + +/* Some Global Platform error codes used in this driver */ +#define TEEC_SUCCESS 0x00000000 +#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEEC_ERROR_COMMUNICATION 0xFFFF000E +#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C + +#define TEEC_ORIGIN_COMMS 0x00000002 + +typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long, + struct arm_smccc_res *); + +struct optee_call_queue { + /* Serializes access to this struct */ + struct mutex mutex; + struct list_head waiters; +}; + +struct optee_wait_queue { + /* Serializes access to this struct */ + struct mutex mu; + struct list_head db; +}; + +/** + * struct optee_supp - supplicant synchronization struct + * @ctx the context of current connected supplicant. + * if !NULL the supplicant device is available for use, + * else busy + * @ctx_mutex: held while accessing @ctx + * @func: supplicant function id to call + * @ret: call return value + * @num_params: number of elements in @param + * @param: parameters for @func + * @req_posted: if true, a request has been posted to the supplicant + * @supp_next_send: if true, next step is for supplicant to send response + * @thrd_mutex: held by the thread doing a request to supplicant + * @supp_mutex: held by supplicant while operating on this struct + * @data_to_supp: supplicant is waiting on this for next request + * @data_from_supp: requesting thread is waiting on this to get the result + */ +struct optee_supp { + struct tee_context *ctx; + /* Serializes access of ctx */ + struct mutex ctx_mutex; + + u32 func; + u32 ret; + size_t num_params; + struct tee_param *param; + + bool req_posted; + bool supp_next_send; + /* Serializes access to this struct for requesting thread */ + struct mutex thrd_mutex; + /* Serializes access to this struct for supplicant threads */ + struct mutex supp_mutex; + struct completion data_to_supp; + struct completion data_from_supp; +}; + +/** + * struct optee - main service struct + * @supp_teedev: supplicant device + * @teedev: client device + * @invoke_fn: function to issue smc or hvc + * @call_queue: queue of threads waiting to call @invoke_fn + * @wait_queue: queue of threads from secure world waiting for a + * secure world sync object + * @supp: supplicant synchronization struct for RPC to supplicant + * @pool: shared memory pool + * @memremaped_shm virtual address of memory in shared memory pool + */ +struct optee { + struct tee_device *supp_teedev; + struct tee_device *teedev; + optee_invoke_fn *invoke_fn; + struct optee_call_queue call_queue; + struct optee_wait_queue wait_queue; + struct optee_supp supp; + struct tee_shm_pool *pool; + void *memremaped_shm; +}; + +struct optee_session { + struct list_head list_node; + u32 session_id; +}; + +struct optee_context_data { + /* Serializes access to this struct */ + struct mutex mutex; + struct list_head sess_list; +}; + +struct optee_rpc_param { + u32 a0; + u32 a1; + u32 a2; + u32 a3; + u32 a4; + u32 a5; + u32 a6; + u32 a7; +}; + +void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param); + +void optee_wait_queue_init(struct optee_wait_queue *wq); +void optee_wait_queue_exit(struct optee_wait_queue *wq); + +u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + struct tee_param *param); + +int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len); +int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len); +void optee_supp_init(struct optee_supp *supp); +void optee_supp_uninit(struct optee_supp *supp); + +int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct tee_param *param); +int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + struct tee_param *param); + +u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg); +int optee_open_session(struct tee_context *ctx, + struct tee_ioctl_open_session_arg *arg, + struct tee_param *param); +int optee_close_session(struct tee_context *ctx, u32 session); +int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, + struct tee_param *param); +int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session); + +void optee_enable_shm_cache(struct optee *optee); +void optee_disable_shm_cache(struct optee *optee); + +int optee_from_msg_param(struct tee_param *params, size_t num_params, + const struct optee_msg_param *msg_params); +int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params, + const struct tee_param *params); + +/* + * Small helpers + */ + +static inline void *reg_pair_to_ptr(u32 reg0, u32 reg1) +{ + return (void *)(unsigned long)(((u64)reg0 << 32) | reg1); +} + +static inline void reg_pair_from_64(u32 *reg0, u32 *reg1, u64 val) +{ + *reg0 = val >> 32; + *reg1 = val; +} + +#endif /*OPTEE_PRIVATE_H*/ diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h new file mode 100644 index 000000000000..13b7c98cdf25 --- /dev/null +++ b/drivers/tee/optee/optee_smc.h @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPTEE_SMC_H +#define OPTEE_SMC_H + +#include <linux/arm-smccc.h> +#include <linux/bitops.h> + +#define OPTEE_SMC_STD_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS, (func_num)) +#define OPTEE_SMC_FAST_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS, (func_num)) + +/* + * Function specified by SMC Calling convention. + */ +#define OPTEE_SMC_FUNCID_CALLS_COUNT 0xFF00 +#define OPTEE_SMC_CALLS_COUNT \ + ARM_SMCCC_CALL_VAL(OPTEE_SMC_FAST_CALL, SMCCC_SMC_32, \ + SMCCC_OWNER_TRUSTED_OS_END, \ + OPTEE_SMC_FUNCID_CALLS_COUNT) + +/* + * Normal cached memory (write-back), shareable for SMP systems and not + * shareable for UP systems. + */ +#define OPTEE_SMC_SHM_CACHED 1 + +/* + * a0..a7 is used as register names in the descriptions below, on arm32 + * that translates to r0..r7 and on arm64 to w0..w7. In both cases it's + * 32-bit registers. + */ + +/* + * Function specified by SMC Calling convention + * + * Return one of the following UIDs if using API specified in this file + * without further extentions: + * 65cb6b93-af0c-4617-8ed6-644a8d1140f8 + * see also OPTEE_SMC_UID_* in optee_msg.h + */ +#define OPTEE_SMC_FUNCID_CALLS_UID OPTEE_MSG_FUNCID_CALLS_UID +#define OPTEE_SMC_CALLS_UID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS_END, \ + OPTEE_SMC_FUNCID_CALLS_UID) + +/* + * Function specified by SMC Calling convention + * + * Returns 2.0 if using API specified in this file without further extentions. + * see also OPTEE_MSG_REVISION_* in optee_msg.h + */ +#define OPTEE_SMC_FUNCID_CALLS_REVISION OPTEE_MSG_FUNCID_CALLS_REVISION +#define OPTEE_SMC_CALLS_REVISION \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS_END, \ + OPTEE_SMC_FUNCID_CALLS_REVISION) + +struct optee_smc_calls_revision_result { + unsigned long major; + unsigned long minor; + unsigned long reserved0; + unsigned long reserved1; +}; + +/* + * Get UUID of Trusted OS. + * + * Used by non-secure world to figure out which Trusted OS is installed. + * Note that returned UUID is the UUID of the Trusted OS, not of the API. + * + * Returns UUID in a0-4 in the same way as OPTEE_SMC_CALLS_UID + * described above. + */ +#define OPTEE_SMC_FUNCID_GET_OS_UUID OPTEE_MSG_FUNCID_GET_OS_UUID +#define OPTEE_SMC_CALL_GET_OS_UUID \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_UUID) + +/* + * Get revision of Trusted OS. + * + * Used by non-secure world to figure out which version of the Trusted OS + * is installed. Note that the returned revision is the revision of the + * Trusted OS, not of the API. + * + * Returns revision in a0-1 in the same way as OPTEE_SMC_CALLS_REVISION + * described above. + */ +#define OPTEE_SMC_FUNCID_GET_OS_REVISION OPTEE_MSG_FUNCID_GET_OS_REVISION +#define OPTEE_SMC_CALL_GET_OS_REVISION \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_REVISION) + +/* + * Call with struct optee_msg_arg as argument + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC*CALL_WITH_ARG + * a1 Upper 32bit of a 64bit physical pointer to a struct optee_msg_arg + * a2 Lower 32bit of a 64bit physical pointer to a struct optee_msg_arg + * a3 Cache settings, not used if physical pointer is in a predefined shared + * memory area else per OPTEE_SMC_SHM_* + * a4-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 Return value, OPTEE_SMC_RETURN_* + * a1-3 Not used + * a4-7 Preserved + * + * OPTEE_SMC_RETURN_ETHREAD_LIMIT return register usage: + * a0 Return value, OPTEE_SMC_RETURN_ETHREAD_LIMIT + * a1-3 Preserved + * a4-7 Preserved + * + * RPC return register usage: + * a0 Return value, OPTEE_SMC_RETURN_IS_RPC(val) + * a1-2 RPC parameters + * a3-7 Resume information, must be preserved + * + * Possible return values: + * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this + * function. + * OPTEE_SMC_RETURN_OK Call completed, result updated in + * the previously supplied struct + * optee_msg_arg. + * OPTEE_SMC_RETURN_ETHREAD_LIMIT Number of Trusted OS threads exceeded, + * try again later. + * OPTEE_SMC_RETURN_EBADADDR Bad physcial pointer to struct + * optee_msg_arg. + * OPTEE_SMC_RETURN_EBADCMD Bad/unknown cmd in struct optee_msg_arg + * OPTEE_SMC_RETURN_IS_RPC() Call suspended by RPC call to normal + * world. + */ +#define OPTEE_SMC_FUNCID_CALL_WITH_ARG OPTEE_MSG_FUNCID_CALL_WITH_ARG +#define OPTEE_SMC_CALL_WITH_ARG \ + OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_ARG) + +/* + * Get Shared Memory Config + * + * Returns the Secure/Non-secure shared memory config. + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_GET_SHM_CONFIG + * a1-6 Not used + * a7 Hypervisor Client ID register + * + * Have config return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1 Physical address of start of SHM + * a2 Size of of SHM + * a3 Cache settings of memory, as defined by the + * OPTEE_SMC_SHM_* values above + * a4-7 Preserved + * + * Not available register usage: + * a0 OPTEE_SMC_RETURN_ENOTAVAIL + * a1-3 Not used + * a4-7 Preserved + */ +#define OPTEE_SMC_FUNCID_GET_SHM_CONFIG 7 +#define OPTEE_SMC_GET_SHM_CONFIG \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_SHM_CONFIG) + +struct optee_smc_get_shm_config_result { + unsigned long status; + unsigned long start; + unsigned long size; + unsigned long settings; +}; + +/* + * Exchanges capabilities between normal world and secure world + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_EXCHANGE_CAPABILITIES + * a1 bitfield of normal world capabilities OPTEE_SMC_NSEC_CAP_* + * a2-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_* + * a2-7 Preserved + * + * Error return register usage: + * a0 OPTEE_SMC_RETURN_ENOTAVAIL, can't use the capabilities from normal world + * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_* + * a2-7 Preserved + */ +/* Normal world works as a uniprocessor system */ +#define OPTEE_SMC_NSEC_CAP_UNIPROCESSOR BIT(0) +/* Secure world has reserved shared memory for normal world to use */ +#define OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM BIT(0) +/* Secure world can communicate via previously unregistered shared memory */ +#define OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM BIT(1) +#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9 +#define OPTEE_SMC_EXCHANGE_CAPABILITIES \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES) + +struct optee_smc_exchange_capabilities_result { + unsigned long status; + unsigned long capabilities; + unsigned long reserved0; + unsigned long reserved1; +}; + +/* + * Disable and empties cache of shared memory objects + * + * Secure world can cache frequently used shared memory objects, for + * example objects used as RPC arguments. When secure world is idle this + * function returns one shared memory reference to free. To disable the + * cache and free all cached objects this function has to be called until + * it returns OPTEE_SMC_RETURN_ENOTAVAIL. + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_DISABLE_SHM_CACHE + * a1-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1 Upper 32bit of a 64bit Shared memory cookie + * a2 Lower 32bit of a 64bit Shared memory cookie + * a3-7 Preserved + * + * Cache empty return register usage: + * a0 OPTEE_SMC_RETURN_ENOTAVAIL + * a1-7 Preserved + * + * Not idle return register usage: + * a0 OPTEE_SMC_RETURN_EBUSY + * a1-7 Preserved + */ +#define OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE 10 +#define OPTEE_SMC_DISABLE_SHM_CACHE \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE) + +struct optee_smc_disable_shm_cache_result { + unsigned long status; + unsigned long shm_upper32; + unsigned long shm_lower32; + unsigned long reserved0; +}; + +/* + * Enable cache of shared memory objects + * + * Secure world can cache frequently used shared memory objects, for + * example objects used as RPC arguments. When secure world is idle this + * function returns OPTEE_SMC_RETURN_OK and the cache is enabled. If + * secure world isn't idle OPTEE_SMC_RETURN_EBUSY is returned. + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_ENABLE_SHM_CACHE + * a1-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1-7 Preserved + * + * Not idle return register usage: + * a0 OPTEE_SMC_RETURN_EBUSY + * a1-7 Preserved + */ +#define OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE 11 +#define OPTEE_SMC_ENABLE_SHM_CACHE \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE) + +/* + * Resume from RPC (for example after processing an IRQ) + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC + * a1-3 Value of a1-3 when OPTEE_SMC_CALL_WITH_ARG returned + * OPTEE_SMC_RETURN_RPC in a0 + * + * Return register usage is the same as for OPTEE_SMC_*CALL_WITH_ARG above. + * + * Possible return values + * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this + * function. + * OPTEE_SMC_RETURN_OK Original call completed, result + * updated in the previously supplied. + * struct optee_msg_arg + * OPTEE_SMC_RETURN_RPC Call suspended by RPC call to normal + * world. + * OPTEE_SMC_RETURN_ERESUME Resume failed, the opaque resume + * information was corrupt. + */ +#define OPTEE_SMC_FUNCID_RETURN_FROM_RPC 3 +#define OPTEE_SMC_CALL_RETURN_FROM_RPC \ + OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_RETURN_FROM_RPC) + +#define OPTEE_SMC_RETURN_RPC_PREFIX_MASK 0xFFFF0000 +#define OPTEE_SMC_RETURN_RPC_PREFIX 0xFFFF0000 +#define OPTEE_SMC_RETURN_RPC_FUNC_MASK 0x0000FFFF + +#define OPTEE_SMC_RETURN_GET_RPC_FUNC(ret) \ + ((ret) & OPTEE_SMC_RETURN_RPC_FUNC_MASK) + +#define OPTEE_SMC_RPC_VAL(func) ((func) | OPTEE_SMC_RETURN_RPC_PREFIX) + +/* + * Allocate memory for RPC parameter passing. The memory is used to hold a + * struct optee_msg_arg. + * + * "Call" register usage: + * a0 This value, OPTEE_SMC_RETURN_RPC_ALLOC + * a1 Size in bytes of required argument memory + * a2 Not used + * a3 Resume information, must be preserved + * a4-5 Not used + * a6-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1 Upper 32bits of 64bit physical pointer to allocated + * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't + * be allocated. + * a2 Lower 32bits of 64bit physical pointer to allocated + * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't + * be allocated + * a3 Preserved + * a4 Upper 32bits of 64bit Shared memory cookie used when freeing + * the memory or doing an RPC + * a5 Lower 32bits of 64bit Shared memory cookie used when freeing + * the memory or doing an RPC + * a6-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_ALLOC 0 +#define OPTEE_SMC_RETURN_RPC_ALLOC \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_ALLOC) + +/* + * Free memory previously allocated by OPTEE_SMC_RETURN_RPC_ALLOC + * + * "Call" register usage: + * a0 This value, OPTEE_SMC_RETURN_RPC_FREE + * a1 Upper 32bits of 64bit shared memory cookie belonging to this + * argument memory + * a2 Lower 32bits of 64bit shared memory cookie belonging to this + * argument memory + * a3-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1-2 Not used + * a3-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_FREE 2 +#define OPTEE_SMC_RETURN_RPC_FREE \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FREE) + +/* + * Deliver an IRQ in normal world. + * + * "Call" register usage: + * a0 OPTEE_SMC_RETURN_RPC_IRQ + * a1-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_IRQ 4 +#define OPTEE_SMC_RETURN_RPC_IRQ \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_IRQ) + +/* + * Do an RPC request. The supplied struct optee_msg_arg tells which + * request to do and the parameters for the request. The following fields + * are used (the rest are unused): + * - cmd the Request ID + * - ret return value of the request, filled in by normal world + * - num_params number of parameters for the request + * - params the parameters + * - param_attrs attributes of the parameters + * + * "Call" register usage: + * a0 OPTEE_SMC_RETURN_RPC_CMD + * a1 Upper 32bit of a 64bit Shared memory cookie holding a + * struct optee_msg_arg, must be preserved, only the data should + * be updated + * a2 Lower 32bit of a 64bit Shared memory cookie holding a + * struct optee_msg_arg, must be preserved, only the data should + * be updated + * a3-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1-2 Not used + * a3-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_CMD 5 +#define OPTEE_SMC_RETURN_RPC_CMD \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_CMD) + +/* Returned in a0 */ +#define OPTEE_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF + +/* Returned in a0 only from Trusted OS functions */ +#define OPTEE_SMC_RETURN_OK 0x0 +#define OPTEE_SMC_RETURN_ETHREAD_LIMIT 0x1 +#define OPTEE_SMC_RETURN_EBUSY 0x2 +#define OPTEE_SMC_RETURN_ERESUME 0x3 +#define OPTEE_SMC_RETURN_EBADADDR 0x4 +#define OPTEE_SMC_RETURN_EBADCMD 0x5 +#define OPTEE_SMC_RETURN_ENOMEM 0x6 +#define OPTEE_SMC_RETURN_ENOTAVAIL 0x7 +#define OPTEE_SMC_RETURN_IS_RPC(ret) __optee_smc_return_is_rpc((ret)) + +static inline bool __optee_smc_return_is_rpc(u32 ret) +{ + return ret != OPTEE_SMC_RETURN_UNKNOWN_FUNCTION && + (ret & OPTEE_SMC_RETURN_RPC_PREFIX_MASK) == + OPTEE_SMC_RETURN_RPC_PREFIX; +} + +#endif /* OPTEE_SMC_H */ diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c new file mode 100644 index 000000000000..8814eca06021 --- /dev/null +++ b/drivers/tee/optee/rpc.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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) KBUILD_MODNAME ": " fmt + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include "optee_private.h" +#include "optee_smc.h" + +struct wq_entry { + struct list_head link; + struct completion c; + u32 key; +}; + +void optee_wait_queue_init(struct optee_wait_queue *priv) +{ + mutex_init(&priv->mu); + INIT_LIST_HEAD(&priv->db); +} + +void optee_wait_queue_exit(struct optee_wait_queue *priv) +{ + mutex_destroy(&priv->mu); +} + +static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg) +{ + struct timespec64 ts; + + if (arg->num_params != 1) + goto bad; + if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) != + OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT) + goto bad; + + getnstimeofday64(&ts); + arg->params[0].u.value.a = ts.tv_sec; + arg->params[0].u.value.b = ts.tv_nsec; + + arg->ret = TEEC_SUCCESS; + return; +bad: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +} + +static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key) +{ + struct wq_entry *w; + + mutex_lock(&wq->mu); + + list_for_each_entry(w, &wq->db, link) + if (w->key == key) + goto out; + + w = kmalloc(sizeof(*w), GFP_KERNEL); + if (w) { + init_completion(&w->c); + w->key = key; + list_add_tail(&w->link, &wq->db); + } +out: + mutex_unlock(&wq->mu); + return w; +} + +static void wq_sleep(struct optee_wait_queue *wq, u32 key) +{ + struct wq_entry *w = wq_entry_get(wq, key); + + if (w) { + wait_for_completion(&w->c); + mutex_lock(&wq->mu); + list_del(&w->link); + mutex_unlock(&wq->mu); + kfree(w); + } +} + +static void wq_wakeup(struct optee_wait_queue *wq, u32 key) +{ + struct wq_entry *w = wq_entry_get(wq, key); + + if (w) + complete(&w->c); +} + +static void handle_rpc_func_cmd_wq(struct optee *optee, + struct optee_msg_arg *arg) +{ + if (arg->num_params != 1) + goto bad; + + if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) != + OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) + goto bad; + + switch (arg->params[0].u.value.a) { + case OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP: + wq_sleep(&optee->wait_queue, arg->params[0].u.value.b); + break; + case OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP: + wq_wakeup(&optee->wait_queue, arg->params[0].u.value.b); + break; + default: + goto bad; + } + + arg->ret = TEEC_SUCCESS; + return; +bad: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +} + +static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg) +{ + u32 msec_to_wait; + + if (arg->num_params != 1) + goto bad; + + if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) != + OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) + goto bad; + + msec_to_wait = arg->params[0].u.value.a; + + /* set task's state to interruptible sleep */ + set_current_state(TASK_INTERRUPTIBLE); + + /* take a nap */ + msleep(msec_to_wait); + + arg->ret = TEEC_SUCCESS; + return; +bad: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +} + +static void handle_rpc_supp_cmd(struct tee_context *ctx, + struct optee_msg_arg *arg) +{ + struct tee_param *params; + + arg->ret_origin = TEEC_ORIGIN_COMMS; + + params = kmalloc_array(arg->num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) { + arg->ret = TEEC_ERROR_OUT_OF_MEMORY; + return; + } + + if (optee_from_msg_param(params, arg->num_params, arg->params)) { + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + goto out; + } + + arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params); + + if (optee_to_msg_param(arg->params, arg->num_params, params)) + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +out: + kfree(params); +} + +static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz) +{ + u32 ret; + struct tee_param param; + struct optee *optee = tee_get_drvdata(ctx->teedev); + struct tee_shm *shm; + + param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; + param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL; + param.u.value.b = sz; + param.u.value.c = 0; + + ret = optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_ALLOC, 1, ¶m); + if (ret) + return ERR_PTR(-ENOMEM); + + mutex_lock(&optee->supp.ctx_mutex); + /* Increases count as secure world doesn't have a reference */ + shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c); + mutex_unlock(&optee->supp.ctx_mutex); + return shm; +} + +static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, + struct optee_msg_arg *arg) +{ + phys_addr_t pa; + struct tee_shm *shm; + size_t sz; + size_t n; + + arg->ret_origin = TEEC_ORIGIN_COMMS; + + if (!arg->num_params || + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) { + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + + for (n = 1; n < arg->num_params; n++) { + if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) { + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + } + + sz = arg->params[0].u.value.b; + switch (arg->params[0].u.value.a) { + case OPTEE_MSG_RPC_SHM_TYPE_APPL: + shm = cmd_alloc_suppl(ctx, sz); + break; + case OPTEE_MSG_RPC_SHM_TYPE_KERNEL: + shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED); + break; + default: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + + if (IS_ERR(shm)) { + arg->ret = TEEC_ERROR_OUT_OF_MEMORY; + return; + } + + if (tee_shm_get_pa(shm, 0, &pa)) { + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + goto bad; + } + + arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; + arg->params[0].u.tmem.buf_ptr = pa; + arg->params[0].u.tmem.size = sz; + arg->params[0].u.tmem.shm_ref = (unsigned long)shm; + arg->ret = TEEC_SUCCESS; + return; +bad: + tee_shm_free(shm); +} + +static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm) +{ + struct tee_param param; + + param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; + param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL; + param.u.value.b = tee_shm_get_id(shm); + param.u.value.c = 0; + + /* + * Match the tee_shm_get_from_id() in cmd_alloc_suppl() as secure + * world has released its reference. + * + * It's better to do this before sending the request to supplicant + * as we'd like to let the process doing the initial allocation to + * do release the last reference too in order to avoid stacking + * many pending fput() on the client process. This could otherwise + * happen if secure world does many allocate and free in a single + * invoke. + */ + tee_shm_put(shm); + + optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_FREE, 1, ¶m); +} + +static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx, + struct optee_msg_arg *arg) +{ + struct tee_shm *shm; + + arg->ret_origin = TEEC_ORIGIN_COMMS; + + if (arg->num_params != 1 || + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) { + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + + shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b; + switch (arg->params[0].u.value.a) { + case OPTEE_MSG_RPC_SHM_TYPE_APPL: + cmd_free_suppl(ctx, shm); + break; + case OPTEE_MSG_RPC_SHM_TYPE_KERNEL: + tee_shm_free(shm); + break; + default: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + } + arg->ret = TEEC_SUCCESS; +} + +static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee, + struct tee_shm *shm) +{ + struct optee_msg_arg *arg; + + arg = tee_shm_get_va(shm, 0); + if (IS_ERR(arg)) { + pr_err("%s: tee_shm_get_va %p failed\n", __func__, shm); + return; + } + + switch (arg->cmd) { + case OPTEE_MSG_RPC_CMD_GET_TIME: + handle_rpc_func_cmd_get_time(arg); + break; + case OPTEE_MSG_RPC_CMD_WAIT_QUEUE: + handle_rpc_func_cmd_wq(optee, arg); + break; + case OPTEE_MSG_RPC_CMD_SUSPEND: + handle_rpc_func_cmd_wait(arg); + break; + case OPTEE_MSG_RPC_CMD_SHM_ALLOC: + handle_rpc_func_cmd_shm_alloc(ctx, arg); + break; + case OPTEE_MSG_RPC_CMD_SHM_FREE: + handle_rpc_func_cmd_shm_free(ctx, arg); + break; + default: + handle_rpc_supp_cmd(ctx, arg); + } +} + +/** + * optee_handle_rpc() - handle RPC from secure world + * @ctx: context doing the RPC + * @param: value of registers for the RPC + * + * Result of RPC is written back into @param. + */ +void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param) +{ + struct tee_device *teedev = ctx->teedev; + struct optee *optee = tee_get_drvdata(teedev); + struct tee_shm *shm; + phys_addr_t pa; + + switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) { + case OPTEE_SMC_RPC_FUNC_ALLOC: + shm = tee_shm_alloc(ctx, param->a1, TEE_SHM_MAPPED); + if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) { + reg_pair_from_64(¶m->a1, ¶m->a2, pa); + reg_pair_from_64(¶m->a4, ¶m->a5, + (unsigned long)shm); + } else { + param->a1 = 0; + param->a2 = 0; + param->a4 = 0; + param->a5 = 0; + } + break; + case OPTEE_SMC_RPC_FUNC_FREE: + shm = reg_pair_to_ptr(param->a1, param->a2); + tee_shm_free(shm); + break; + case OPTEE_SMC_RPC_FUNC_IRQ: + /* + * An IRQ was raised while secure world was executing, + * since all IRQs are handled in Linux a dummy RPC is + * performed to let Linux take the IRQ through the normal + * vector. + */ + break; + case OPTEE_SMC_RPC_FUNC_CMD: + shm = reg_pair_to_ptr(param->a1, param->a2); + handle_rpc_func_cmd(ctx, optee, shm); + break; + default: + pr_warn("Unknown RPC func 0x%x\n", + (u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)); + break; + } + + param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC; +} diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c new file mode 100644 index 000000000000..b4ea0678a436 --- /dev/null +++ b/drivers/tee/optee/supp.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/device.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include "optee_private.h" + +void optee_supp_init(struct optee_supp *supp) +{ + memset(supp, 0, sizeof(*supp)); + mutex_init(&supp->ctx_mutex); + mutex_init(&supp->thrd_mutex); + mutex_init(&supp->supp_mutex); + init_completion(&supp->data_to_supp); + init_completion(&supp->data_from_supp); +} + +void optee_supp_uninit(struct optee_supp *supp) +{ + mutex_destroy(&supp->ctx_mutex); + mutex_destroy(&supp->thrd_mutex); + mutex_destroy(&supp->supp_mutex); +} + +/** + * optee_supp_thrd_req() - request service from supplicant + * @ctx: context doing the request + * @func: function requested + * @num_params: number of elements in @param array + * @param: parameters for function + * + * Returns result of operation to be passed to secure world + */ +u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, + struct tee_param *param) +{ + bool interruptable; + struct optee *optee = tee_get_drvdata(ctx->teedev); + struct optee_supp *supp = &optee->supp; + u32 ret; + + /* + * Other threads blocks here until we've copied our answer from + * supplicant. + */ + while (mutex_lock_interruptible(&supp->thrd_mutex)) { + /* See comment below on when the RPC can be interrupted. */ + mutex_lock(&supp->ctx_mutex); + interruptable = !supp->ctx; + mutex_unlock(&supp->ctx_mutex); + if (interruptable) + return TEEC_ERROR_COMMUNICATION; + } + + /* + * We have exclusive access now since the supplicant at this + * point is either doing a + * wait_for_completion_interruptible(&supp->data_to_supp) or is in + * userspace still about to do the ioctl() to enter + * optee_supp_recv() below. + */ + + supp->func = func; + supp->num_params = num_params; + supp->param = param; + supp->req_posted = true; + + /* Let supplicant get the data */ + complete(&supp->data_to_supp); + + /* + * Wait for supplicant to process and return result, once we've + * returned from wait_for_completion(data_from_supp) we have + * exclusive access again. + */ + while (wait_for_completion_interruptible(&supp->data_from_supp)) { + mutex_lock(&supp->ctx_mutex); + interruptable = !supp->ctx; + if (interruptable) { + /* + * There's no supplicant available and since the + * supp->ctx_mutex currently is held none can + * become available until the mutex released + * again. + * + * Interrupting an RPC to supplicant is only + * allowed as a way of slightly improving the user + * experience in case the supplicant hasn't been + * started yet. During normal operation the supplicant + * will serve all requests in a timely manner and + * interrupting then wouldn't make sense. + */ + supp->ret = TEEC_ERROR_COMMUNICATION; + init_completion(&supp->data_to_supp); + } + mutex_unlock(&supp->ctx_mutex); + if (interruptable) + break; + } + + ret = supp->ret; + supp->param = NULL; + supp->req_posted = false; + + /* We're done, let someone else talk to the supplicant now. */ + mutex_unlock(&supp->thrd_mutex); + + return ret; +} + +/** + * optee_supp_recv() - receive request for supplicant + * @ctx: context receiving the request + * @func: requested function in supplicant + * @num_params: number of elements allocated in @param, updated with number + * used elements + * @param: space for parameters for @func + * + * Returns 0 on success or <0 on failure + */ +int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, + struct tee_param *param) +{ + struct tee_device *teedev = ctx->teedev; + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + int rc; + + /* + * In case two threads in one supplicant is calling this function + * simultaneously we need to protect the data with a mutex which + * we'll release before returning. + */ + mutex_lock(&supp->supp_mutex); + + if (supp->supp_next_send) { + /* + * optee_supp_recv() has been called again without + * a optee_supp_send() in between. Supplicant has + * probably been restarted before it was able to + * write back last result. Abort last request and + * wait for a new. + */ + if (supp->req_posted) { + supp->ret = TEEC_ERROR_COMMUNICATION; + supp->supp_next_send = false; + complete(&supp->data_from_supp); + } + } + + /* + * This is where supplicant will be hanging most of the + * time, let's make this interruptable so we can easily + * restart supplicant if needed. + */ + if (wait_for_completion_interruptible(&supp->data_to_supp)) { + rc = -ERESTARTSYS; + goto out; + } + + /* We have exlusive access to the data */ + + if (*num_params < supp->num_params) { + /* + * Not enough room for parameters, tell supplicant + * it failed and abort last request. + */ + supp->ret = TEEC_ERROR_COMMUNICATION; + rc = -EINVAL; + complete(&supp->data_from_supp); + goto out; + } + + *func = supp->func; + *num_params = supp->num_params; + memcpy(param, supp->param, + sizeof(struct tee_param) * supp->num_params); + + /* Allow optee_supp_send() below to do its work */ + supp->supp_next_send = true; + + rc = 0; +out: + mutex_unlock(&supp->supp_mutex); + return rc; +} + +/** + * optee_supp_send() - send result of request from supplicant + * @ctx: context sending result + * @ret: return value of request + * @num_params: number of parameters returned + * @param: returned parameters + * + * Returns 0 on success or <0 on failure. + */ +int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, + struct tee_param *param) +{ + struct tee_device *teedev = ctx->teedev; + struct optee *optee = tee_get_drvdata(teedev); + struct optee_supp *supp = &optee->supp; + size_t n; + int rc = 0; + + /* + * We still have exclusive access to the data since that's how we + * left it when returning from optee_supp_read(). + */ + + /* See comment on mutex in optee_supp_read() above */ + mutex_lock(&supp->supp_mutex); + + if (!supp->supp_next_send) { + /* + * Something strange is going on, supplicant shouldn't + * enter optee_supp_send() in this state + */ + rc = -ENOENT; + goto out; + } + + if (num_params != supp->num_params) { + /* + * Something is wrong, let supplicant restart. Next call to + * optee_supp_recv() will give an error to the requesting + * thread and release it. + */ + rc = -EINVAL; + goto out; + } + + /* Update out and in/out parameters */ + for (n = 0; n < num_params; n++) { + struct tee_param *p = supp->param + n; + + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + p->u.value.a = param[n].u.value.a; + p->u.value.b = param[n].u.value.b; + p->u.value.c = param[n].u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + p->u.memref.size = param[n].u.memref.size; + break; + default: + break; + } + } + supp->ret = ret; + + /* Allow optee_supp_recv() above to do its work */ + supp->supp_next_send = false; + + /* Let the requesting thread continue */ + complete(&supp->data_from_supp); +out: + mutex_unlock(&supp->supp_mutex); + return rc; +} diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c new file mode 100644 index 000000000000..5c60bf4423e6 --- /dev/null +++ b/drivers/tee/tee_core.c @@ -0,0 +1,893 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/cdev.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/idr.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include <linux/uaccess.h> +#include "tee_private.h" + +#define TEE_NUM_DEVICES 32 + +#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) + +/* + * Unprivileged devices in the lower half range and privileged devices in + * the upper half range. + */ +static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); +static DEFINE_SPINLOCK(driver_lock); + +static struct class *tee_class; +static dev_t tee_devt; + +static int tee_open(struct inode *inode, struct file *filp) +{ + int rc; + struct tee_device *teedev; + struct tee_context *ctx; + + teedev = container_of(inode->i_cdev, struct tee_device, cdev); + if (!tee_device_get(teedev)) + return -EINVAL; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + rc = -ENOMEM; + goto err; + } + + ctx->teedev = teedev; + INIT_LIST_HEAD(&ctx->list_shm); + filp->private_data = ctx; + rc = teedev->desc->ops->open(ctx); + if (rc) + goto err; + + return 0; +err: + kfree(ctx); + tee_device_put(teedev); + return rc; +} + +static int tee_release(struct inode *inode, struct file *filp) +{ + struct tee_context *ctx = filp->private_data; + struct tee_device *teedev = ctx->teedev; + struct tee_shm *shm; + + ctx->teedev->desc->ops->release(ctx); + mutex_lock(&ctx->teedev->mutex); + list_for_each_entry(shm, &ctx->list_shm, link) + shm->ctx = NULL; + mutex_unlock(&ctx->teedev->mutex); + kfree(ctx); + tee_device_put(teedev); + return 0; +} + +static int tee_ioctl_version(struct tee_context *ctx, + struct tee_ioctl_version_data __user *uvers) +{ + struct tee_ioctl_version_data vers; + + ctx->teedev->desc->ops->get_version(ctx->teedev, &vers); + if (copy_to_user(uvers, &vers, sizeof(vers))) + return -EFAULT; + return 0; +} + +static int tee_ioctl_shm_alloc(struct tee_context *ctx, + struct tee_ioctl_shm_alloc_data __user *udata) +{ + long ret; + struct tee_ioctl_shm_alloc_data data; + struct tee_shm *shm; + + if (copy_from_user(&data, udata, sizeof(data))) + return -EFAULT; + + /* Currently no input flags are supported */ + if (data.flags) + return -EINVAL; + + data.id = -1; + + shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + data.id = shm->id; + data.flags = shm->flags; + data.size = shm->size; + + if (copy_to_user(udata, &data, sizeof(data))) + ret = -EFAULT; + else + ret = tee_shm_get_fd(shm); + + /* + * When user space closes the file descriptor the shared memory + * should be freed or if tee_shm_get_fd() failed then it will + * be freed immediately. + */ + tee_shm_put(shm); + return ret; +} + +static int params_from_user(struct tee_context *ctx, struct tee_param *params, + size_t num_params, + struct tee_ioctl_param __user *uparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_shm *shm; + struct tee_ioctl_param ip; + + if (copy_from_user(&ip, uparams + n, sizeof(ip))) + return -EFAULT; + + /* All unused attribute bits has to be zero */ + if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + return -EINVAL; + + params[n].attr = ip.attr; + switch (ip.attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + params[n].u.value.a = ip.a; + params[n].u.value.b = ip.b; + params[n].u.value.c = ip.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + /* + * If we fail to get a pointer to a shared memory + * object (and increase the ref count) from an + * identifier we return an error. All pointers that + * has been added in params have an increased ref + * count. It's the callers responibility to do + * tee_shm_put() on all resolved pointers. + */ + shm = tee_shm_get_from_id(ctx, ip.c); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + params[n].u.memref.shm_offs = ip.a; + params[n].u.memref.size = ip.b; + params[n].u.memref.shm = shm; + break; + default: + /* Unknown attribute */ + return -EINVAL; + } + } + return 0; +} + +static int params_to_user(struct tee_ioctl_param __user *uparams, + size_t num_params, struct tee_param *params) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_ioctl_param __user *up = uparams + n; + struct tee_param *p = params + n; + + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + if (put_user(p->u.value.a, &up->a) || + put_user(p->u.value.b, &up->b) || + put_user(p->u.value.c, &up->c)) + return -EFAULT; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + if (put_user((u64)p->u.memref.size, &up->b)) + return -EFAULT; + default: + break; + } + } + return 0; +} + +static bool param_is_memref(struct tee_param *param) +{ + switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + return true; + default: + return false; + } +} + +static int tee_ioctl_open_session(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + size_t n; + struct tee_ioctl_buf_data buf; + struct tee_ioctl_open_session_arg __user *uarg; + struct tee_ioctl_open_session_arg arg; + struct tee_ioctl_param __user *uparams = NULL; + struct tee_param *params = NULL; + bool have_session = false; + + if (!ctx->teedev->desc->ops->open_session) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_ioctl_open_session_arg)) + return -EINVAL; + + uarg = u64_to_user_ptr(buf.buf_ptr); + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params = kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams = uarg->params; + rc = params_from_user(ctx, params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params); + if (rc) + goto out; + have_session = true; + + if (put_user(arg.session, &uarg->session) || + put_user(arg.ret, &uarg->ret) || + put_user(arg.ret_origin, &uarg->ret_origin)) { + rc = -EFAULT; + goto out; + } + rc = params_to_user(uparams, arg.num_params, params); +out: + /* + * If we've succeeded to open the session but failed to communicate + * it back to user space, close the session again to avoid leakage. + */ + if (rc && have_session && ctx->teedev->desc->ops->close_session) + ctx->teedev->desc->ops->close_session(ctx, arg.session); + + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n = 0; n < arg.num_params; n++) + if (param_is_memref(params + n) && + params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + kfree(params); + } + + return rc; +} + +static int tee_ioctl_invoke(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + size_t n; + struct tee_ioctl_buf_data buf; + struct tee_ioctl_invoke_arg __user *uarg; + struct tee_ioctl_invoke_arg arg; + struct tee_ioctl_param __user *uparams = NULL; + struct tee_param *params = NULL; + + if (!ctx->teedev->desc->ops->invoke_func) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_ioctl_invoke_arg)) + return -EINVAL; + + uarg = u64_to_user_ptr(buf.buf_ptr); + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params = kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams = uarg->params; + rc = params_from_user(ctx, params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params); + if (rc) + goto out; + + if (put_user(arg.ret, &uarg->ret) || + put_user(arg.ret_origin, &uarg->ret_origin)) { + rc = -EFAULT; + goto out; + } + rc = params_to_user(uparams, arg.num_params, params); +out: + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n = 0; n < arg.num_params; n++) + if (param_is_memref(params + n) && + params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + kfree(params); + } + return rc; +} + +static int tee_ioctl_cancel(struct tee_context *ctx, + struct tee_ioctl_cancel_arg __user *uarg) +{ + struct tee_ioctl_cancel_arg arg; + + if (!ctx->teedev->desc->ops->cancel_req) + return -EINVAL; + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id, + arg.session); +} + +static int +tee_ioctl_close_session(struct tee_context *ctx, + struct tee_ioctl_close_session_arg __user *uarg) +{ + struct tee_ioctl_close_session_arg arg; + + if (!ctx->teedev->desc->ops->close_session) + return -EINVAL; + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + return ctx->teedev->desc->ops->close_session(ctx, arg.session); +} + +static int params_to_supp(struct tee_context *ctx, + struct tee_ioctl_param __user *uparams, + size_t num_params, struct tee_param *params) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_ioctl_param ip; + struct tee_param *p = params + n; + + ip.attr = p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK; + switch (p->attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + ip.a = p->u.value.a; + ip.b = p->u.value.b; + ip.c = p->u.value.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + ip.b = p->u.memref.size; + if (!p->u.memref.shm) { + ip.a = 0; + ip.c = (u64)-1; /* invalid shm id */ + break; + } + ip.a = p->u.memref.shm_offs; + ip.c = p->u.memref.shm->id; + break; + default: + ip.a = 0; + ip.b = 0; + ip.c = 0; + break; + } + + if (copy_to_user(uparams + n, &ip, sizeof(ip))) + return -EFAULT; + } + + return 0; +} + +static int tee_ioctl_supp_recv(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + struct tee_ioctl_buf_data buf; + struct tee_iocl_supp_recv_arg __user *uarg; + struct tee_param *params; + u32 num_params; + u32 func; + + if (!ctx->teedev->desc->ops->supp_recv) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg)) + return -EINVAL; + + uarg = u64_to_user_ptr(buf.buf_ptr); + if (get_user(num_params, &uarg->num_params)) + return -EFAULT; + + if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); + if (!params) + return -ENOMEM; + + rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); + if (rc) + goto out; + + if (put_user(func, &uarg->func) || + put_user(num_params, &uarg->num_params)) { + rc = -EFAULT; + goto out; + } + + rc = params_to_supp(ctx, uarg->params, num_params, params); +out: + kfree(params); + return rc; +} + +static int params_from_supp(struct tee_param *params, size_t num_params, + struct tee_ioctl_param __user *uparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) { + struct tee_param *p = params + n; + struct tee_ioctl_param ip; + + if (copy_from_user(&ip, uparams + n, sizeof(ip))) + return -EFAULT; + + /* All unused attribute bits has to be zero */ + if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + return -EINVAL; + + p->attr = ip.attr; + switch (ip.attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + /* Only out and in/out values can be updated */ + p->u.value.a = ip.a; + p->u.value.b = ip.b; + p->u.value.c = ip.c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + /* + * Only the size of the memref can be updated. + * Since we don't have access to the original + * parameters here, only store the supplied size. + * The driver will copy the updated size into the + * original parameters. + */ + p->u.memref.shm = NULL; + p->u.memref.shm_offs = 0; + p->u.memref.size = ip.b; + break; + default: + memset(&p->u, 0, sizeof(p->u)); + break; + } + } + return 0; +} + +static int tee_ioctl_supp_send(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + long rc; + struct tee_ioctl_buf_data buf; + struct tee_iocl_supp_send_arg __user *uarg; + struct tee_param *params; + u32 num_params; + u32 ret; + + /* Not valid for this driver */ + if (!ctx->teedev->desc->ops->supp_send) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_iocl_supp_send_arg)) + return -EINVAL; + + uarg = u64_to_user_ptr(buf.buf_ptr); + if (get_user(ret, &uarg->ret) || + get_user(num_params, &uarg->num_params)) + return -EFAULT; + + if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); + if (!params) + return -ENOMEM; + + rc = params_from_supp(params, num_params, uarg->params); + if (rc) + goto out; + + rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params); +out: + kfree(params); + return rc; +} + +static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct tee_context *ctx = filp->private_data; + void __user *uarg = (void __user *)arg; + + switch (cmd) { + case TEE_IOC_VERSION: + return tee_ioctl_version(ctx, uarg); + case TEE_IOC_SHM_ALLOC: + return tee_ioctl_shm_alloc(ctx, uarg); + case TEE_IOC_OPEN_SESSION: + return tee_ioctl_open_session(ctx, uarg); + case TEE_IOC_INVOKE: + return tee_ioctl_invoke(ctx, uarg); + case TEE_IOC_CANCEL: + return tee_ioctl_cancel(ctx, uarg); + case TEE_IOC_CLOSE_SESSION: + return tee_ioctl_close_session(ctx, uarg); + case TEE_IOC_SUPPL_RECV: + return tee_ioctl_supp_recv(ctx, uarg); + case TEE_IOC_SUPPL_SEND: + return tee_ioctl_supp_send(ctx, uarg); + default: + return -EINVAL; + } +} + +static const struct file_operations tee_fops = { + .owner = THIS_MODULE, + .open = tee_open, + .release = tee_release, + .unlocked_ioctl = tee_ioctl, + .compat_ioctl = tee_ioctl, +}; + +static void tee_release_device(struct device *dev) +{ + struct tee_device *teedev = container_of(dev, struct tee_device, dev); + + spin_lock(&driver_lock); + clear_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + mutex_destroy(&teedev->mutex); + idr_destroy(&teedev->idr); + kfree(teedev); +} + +/** + * tee_device_alloc() - Allocate a new struct tee_device instance + * @teedesc: Descriptor for this driver + * @dev: Parent device for this device + * @pool: Shared memory pool, NULL if not used + * @driver_data: Private driver data for this device + * + * Allocates a new struct tee_device instance. The device is + * removed by tee_device_unregister(). + * + * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure + */ +struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, + struct device *dev, + struct tee_shm_pool *pool, + void *driver_data) +{ + struct tee_device *teedev; + void *ret; + int rc; + int offs = 0; + + if (!teedesc || !teedesc->name || !teedesc->ops || + !teedesc->ops->get_version || !teedesc->ops->open || + !teedesc->ops->release || !pool) + return ERR_PTR(-EINVAL); + + teedev = kzalloc(sizeof(*teedev), GFP_KERNEL); + if (!teedev) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + if (teedesc->flags & TEE_DESC_PRIVILEGED) + offs = TEE_NUM_DEVICES / 2; + + spin_lock(&driver_lock); + teedev->id = find_next_zero_bit(dev_mask, TEE_NUM_DEVICES, offs); + if (teedev->id < TEE_NUM_DEVICES) + set_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + + if (teedev->id >= TEE_NUM_DEVICES) { + ret = ERR_PTR(-ENOMEM); + goto err; + } + + snprintf(teedev->name, sizeof(teedev->name), "tee%s%d", + teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "", + teedev->id - offs); + + teedev->dev.class = tee_class; + teedev->dev.release = tee_release_device; + teedev->dev.parent = dev; + + teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id); + + rc = dev_set_name(&teedev->dev, "%s", teedev->name); + if (rc) { + ret = ERR_PTR(rc); + goto err_devt; + } + + cdev_init(&teedev->cdev, &tee_fops); + teedev->cdev.owner = teedesc->owner; + teedev->cdev.kobj.parent = &teedev->dev.kobj; + + dev_set_drvdata(&teedev->dev, driver_data); + device_initialize(&teedev->dev); + + /* 1 as tee_device_unregister() does one final tee_device_put() */ + teedev->num_users = 1; + init_completion(&teedev->c_no_users); + mutex_init(&teedev->mutex); + idr_init(&teedev->idr); + + teedev->desc = teedesc; + teedev->pool = pool; + + return teedev; +err_devt: + unregister_chrdev_region(teedev->dev.devt, 1); +err: + pr_err("could not register %s driver\n", + teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client"); + if (teedev && teedev->id < TEE_NUM_DEVICES) { + spin_lock(&driver_lock); + clear_bit(teedev->id, dev_mask); + spin_unlock(&driver_lock); + } + kfree(teedev); + return ret; +} +EXPORT_SYMBOL_GPL(tee_device_alloc); + +static ssize_t implementation_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tee_device *teedev = container_of(dev, struct tee_device, dev); + struct tee_ioctl_version_data vers; + + teedev->desc->ops->get_version(teedev, &vers); + return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id); +} +static DEVICE_ATTR_RO(implementation_id); + +static struct attribute *tee_dev_attrs[] = { + &dev_attr_implementation_id.attr, + NULL +}; + +static const struct attribute_group tee_dev_group = { + .attrs = tee_dev_attrs, +}; + +/** + * tee_device_register() - Registers a TEE device + * @teedev: Device to register + * + * tee_device_unregister() need to be called to remove the @teedev if + * this function fails. + * + * @returns < 0 on failure + */ +int tee_device_register(struct tee_device *teedev) +{ + int rc; + + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { + dev_err(&teedev->dev, "attempt to register twice\n"); + return -EINVAL; + } + + rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1); + if (rc) { + dev_err(&teedev->dev, + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", + teedev->name, MAJOR(teedev->dev.devt), + MINOR(teedev->dev.devt), rc); + return rc; + } + + rc = device_add(&teedev->dev); + if (rc) { + dev_err(&teedev->dev, + "unable to device_add() %s, major %d, minor %d, err=%d\n", + teedev->name, MAJOR(teedev->dev.devt), + MINOR(teedev->dev.devt), rc); + goto err_device_add; + } + + rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group); + if (rc) { + dev_err(&teedev->dev, + "failed to create sysfs attributes, err=%d\n", rc); + goto err_sysfs_create_group; + } + + teedev->flags |= TEE_DEVICE_FLAG_REGISTERED; + return 0; + +err_sysfs_create_group: + device_del(&teedev->dev); +err_device_add: + cdev_del(&teedev->cdev); + return rc; +} +EXPORT_SYMBOL_GPL(tee_device_register); + +void tee_device_put(struct tee_device *teedev) +{ + mutex_lock(&teedev->mutex); + /* Shouldn't put in this state */ + if (!WARN_ON(!teedev->desc)) { + teedev->num_users--; + if (!teedev->num_users) { + teedev->desc = NULL; + complete(&teedev->c_no_users); + } + } + mutex_unlock(&teedev->mutex); +} + +bool tee_device_get(struct tee_device *teedev) +{ + mutex_lock(&teedev->mutex); + if (!teedev->desc) { + mutex_unlock(&teedev->mutex); + return false; + } + teedev->num_users++; + mutex_unlock(&teedev->mutex); + return true; +} + +/** + * tee_device_unregister() - Removes a TEE device + * @teedev: Device to unregister + * + * This function should be called to remove the @teedev even if + * tee_device_register() hasn't been called yet. Does nothing if + * @teedev is NULL. + */ +void tee_device_unregister(struct tee_device *teedev) +{ + if (!teedev) + return; + + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { + sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group); + cdev_del(&teedev->cdev); + device_del(&teedev->dev); + } + + tee_device_put(teedev); + wait_for_completion(&teedev->c_no_users); + + /* + * No need to take a mutex any longer now since teedev->desc was + * set to NULL before teedev->c_no_users was completed. + */ + + teedev->pool = NULL; + + put_device(&teedev->dev); +} +EXPORT_SYMBOL_GPL(tee_device_unregister); + +/** + * tee_get_drvdata() - Return driver_data pointer + * @teedev: Device containing the driver_data pointer + * @returns the driver_data pointer supplied to tee_register(). + */ +void *tee_get_drvdata(struct tee_device *teedev) +{ + return dev_get_drvdata(&teedev->dev); +} +EXPORT_SYMBOL_GPL(tee_get_drvdata); + +static int __init tee_init(void) +{ + int rc; + + tee_class = class_create(THIS_MODULE, "tee"); + if (IS_ERR(tee_class)) { + pr_err("couldn't create class\n"); + return PTR_ERR(tee_class); + } + + rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); + if (rc) { + pr_err("failed to allocate char dev region\n"); + class_destroy(tee_class); + tee_class = NULL; + } + + return rc; +} + +static void __exit tee_exit(void) +{ + class_destroy(tee_class); + tee_class = NULL; + unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); +} + +subsys_initcall(tee_init); +module_exit(tee_exit); + +MODULE_AUTHOR("Linaro"); +MODULE_DESCRIPTION("TEE Driver"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h new file mode 100644 index 000000000000..21cb6be8bce9 --- /dev/null +++ b/drivers/tee/tee_private.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 TEE_PRIVATE_H +#define TEE_PRIVATE_H + +#include <linux/cdev.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/kref.h> +#include <linux/mutex.h> +#include <linux/types.h> + +struct tee_device; + +/** + * struct tee_shm - shared memory object + * @teedev: device used to allocate the object + * @ctx: context using the object, if NULL the context is gone + * @link link element + * @paddr: physical address of the shared memory + * @kaddr: virtual address of the shared memory + * @size: size of shared memory + * @dmabuf: dmabuf used to for exporting to user space + * @flags: defined by TEE_SHM_* in tee_drv.h + * @id: unique id of a shared memory object on this device + */ +struct tee_shm { + struct tee_device *teedev; + struct tee_context *ctx; + struct list_head link; + phys_addr_t paddr; + void *kaddr; + size_t size; + struct dma_buf *dmabuf; + u32 flags; + int id; +}; + +struct tee_shm_pool_mgr; + +/** + * struct tee_shm_pool_mgr_ops - shared memory pool manager operations + * @alloc: called when allocating shared memory + * @free: called when freeing shared memory + */ +struct tee_shm_pool_mgr_ops { + int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm, + size_t size); + void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm); +}; + +/** + * struct tee_shm_pool_mgr - shared memory manager + * @ops: operations + * @private_data: private data for the shared memory manager + */ +struct tee_shm_pool_mgr { + const struct tee_shm_pool_mgr_ops *ops; + void *private_data; +}; + +/** + * struct tee_shm_pool - shared memory pool + * @private_mgr: pool manager for shared memory only between kernel + * and secure world + * @dma_buf_mgr: pool manager for shared memory exported to user space + * @destroy: called when destroying the pool + * @private_data: private data for the pool + */ +struct tee_shm_pool { + struct tee_shm_pool_mgr private_mgr; + struct tee_shm_pool_mgr dma_buf_mgr; + void (*destroy)(struct tee_shm_pool *pool); + void *private_data; +}; + +#define TEE_DEVICE_FLAG_REGISTERED 0x1 +#define TEE_MAX_DEV_NAME_LEN 32 + +/** + * struct tee_device - TEE Device representation + * @name: name of device + * @desc: description of device + * @id: unique id of device + * @flags: represented by TEE_DEVICE_FLAG_REGISTERED above + * @dev: embedded basic device structure + * @cdev: embedded cdev + * @num_users: number of active users of this device + * @c_no_user: completion used when unregistering the device + * @mutex: mutex protecting @num_users and @idr + * @idr: register of shared memory object allocated on this device + * @pool: shared memory pool + */ +struct tee_device { + char name[TEE_MAX_DEV_NAME_LEN]; + const struct tee_desc *desc; + int id; + unsigned int flags; + + struct device dev; + struct cdev cdev; + + size_t num_users; + struct completion c_no_users; + struct mutex mutex; /* protects num_users and idr */ + + struct idr idr; + struct tee_shm_pool *pool; +}; + +int tee_shm_init(void); + +int tee_shm_get_fd(struct tee_shm *shm); + +bool tee_device_get(struct tee_device *teedev); +void tee_device_put(struct tee_device *teedev); + +#endif /*TEE_PRIVATE_H*/ diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c new file mode 100644 index 000000000000..d356d7f025eb --- /dev/null +++ b/drivers/tee/tee_shm.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/device.h> +#include <linux/dma-buf.h> +#include <linux/fdtable.h> +#include <linux/idr.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include "tee_private.h" + +static void tee_shm_release(struct tee_shm *shm) +{ + struct tee_device *teedev = shm->teedev; + struct tee_shm_pool_mgr *poolm; + + mutex_lock(&teedev->mutex); + idr_remove(&teedev->idr, shm->id); + if (shm->ctx) + list_del(&shm->link); + mutex_unlock(&teedev->mutex); + + if (shm->flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else + poolm = &teedev->pool->private_mgr; + + poolm->ops->free(poolm, shm); + kfree(shm); + + tee_device_put(teedev); +} + +static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment + *attach, enum dma_data_direction dir) +{ + return NULL; +} + +static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach, + struct sg_table *table, + enum dma_data_direction dir) +{ +} + +static void tee_shm_op_release(struct dma_buf *dmabuf) +{ + struct tee_shm *shm = dmabuf->priv; + + tee_shm_release(shm); +} + +static void *tee_shm_op_map_atomic(struct dma_buf *dmabuf, unsigned long pgnum) +{ + return NULL; +} + +static void *tee_shm_op_map(struct dma_buf *dmabuf, unsigned long pgnum) +{ + return NULL; +} + +static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct tee_shm *shm = dmabuf->priv; + size_t size = vma->vm_end - vma->vm_start; + + return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, + size, vma->vm_page_prot); +} + +static struct dma_buf_ops tee_shm_dma_buf_ops = { + .map_dma_buf = tee_shm_op_map_dma_buf, + .unmap_dma_buf = tee_shm_op_unmap_dma_buf, + .release = tee_shm_op_release, + .map_atomic = tee_shm_op_map_atomic, + .map = tee_shm_op_map, + .mmap = tee_shm_op_mmap, +}; + +/** + * tee_shm_alloc() - Allocate shared memory + * @ctx: Context that allocates the shared memory + * @size: Requested size of shared memory + * @flags: Flags setting properties for the requested shared memory. + * + * Memory allocated as global shared memory is automatically freed when the + * TEE file pointer is closed. The @flags field uses the bits defined by + * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be + * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and + * associated with a dma-buf handle, else driver private memory. + */ +struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) +{ + struct tee_device *teedev = ctx->teedev; + struct tee_shm_pool_mgr *poolm = NULL; + struct tee_shm *shm; + void *ret; + int rc; + + if (!(flags & TEE_SHM_MAPPED)) { + dev_err(teedev->dev.parent, + "only mapped allocations supported\n"); + return ERR_PTR(-EINVAL); + } + + if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) { + dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags); + return ERR_PTR(-EINVAL); + } + + if (!tee_device_get(teedev)) + return ERR_PTR(-EINVAL); + + if (!teedev->pool) { + /* teedev has been detached from driver */ + ret = ERR_PTR(-EINVAL); + goto err_dev_put; + } + + shm = kzalloc(sizeof(*shm), GFP_KERNEL); + if (!shm) { + ret = ERR_PTR(-ENOMEM); + goto err_dev_put; + } + + shm->flags = flags; + shm->teedev = teedev; + shm->ctx = ctx; + if (flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else + poolm = &teedev->pool->private_mgr; + + rc = poolm->ops->alloc(poolm, shm, size); + if (rc) { + ret = ERR_PTR(rc); + goto err_kfree; + } + + mutex_lock(&teedev->mutex); + shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); + mutex_unlock(&teedev->mutex); + if (shm->id < 0) { + ret = ERR_PTR(shm->id); + goto err_pool_free; + } + + if (flags & TEE_SHM_DMA_BUF) { + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &tee_shm_dma_buf_ops; + exp_info.size = shm->size; + exp_info.flags = O_RDWR; + exp_info.priv = shm; + + shm->dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(shm->dmabuf)) { + ret = ERR_CAST(shm->dmabuf); + goto err_rem; + } + } + mutex_lock(&teedev->mutex); + list_add_tail(&shm->link, &ctx->list_shm); + mutex_unlock(&teedev->mutex); + + return shm; +err_rem: + mutex_lock(&teedev->mutex); + idr_remove(&teedev->idr, shm->id); + mutex_unlock(&teedev->mutex); +err_pool_free: + poolm->ops->free(poolm, shm); +err_kfree: + kfree(shm); +err_dev_put: + tee_device_put(teedev); + return ret; +} +EXPORT_SYMBOL_GPL(tee_shm_alloc); + +/** + * tee_shm_get_fd() - Increase reference count and return file descriptor + * @shm: Shared memory handle + * @returns user space file descriptor to shared memory + */ +int tee_shm_get_fd(struct tee_shm *shm) +{ + u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF; + int fd; + + if ((shm->flags & req_flags) != req_flags) + return -EINVAL; + + fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC); + if (fd >= 0) + get_dma_buf(shm->dmabuf); + return fd; +} + +/** + * tee_shm_free() - Free shared memory + * @shm: Handle to shared memory to free + */ +void tee_shm_free(struct tee_shm *shm) +{ + /* + * dma_buf_put() decreases the dmabuf reference counter and will + * call tee_shm_release() when the last reference is gone. + * + * In the case of driver private memory we call tee_shm_release + * directly instead as it doesn't have a reference counter. + */ + if (shm->flags & TEE_SHM_DMA_BUF) + dma_buf_put(shm->dmabuf); + else + tee_shm_release(shm); +} +EXPORT_SYMBOL_GPL(tee_shm_free); + +/** + * tee_shm_va2pa() - Get physical address of a virtual address + * @shm: Shared memory handle + * @va: Virtual address to tranlsate + * @pa: Returned physical address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa) +{ + /* Check that we're in the range of the shm */ + if ((char *)va < (char *)shm->kaddr) + return -EINVAL; + if ((char *)va >= ((char *)shm->kaddr + shm->size)) + return -EINVAL; + + return tee_shm_get_pa( + shm, (unsigned long)va - (unsigned long)shm->kaddr, pa); +} +EXPORT_SYMBOL_GPL(tee_shm_va2pa); + +/** + * tee_shm_pa2va() - Get virtual address of a physical address + * @shm: Shared memory handle + * @pa: Physical address to tranlsate + * @va: Returned virtual address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va) +{ + /* Check that we're in the range of the shm */ + if (pa < shm->paddr) + return -EINVAL; + if (pa >= (shm->paddr + shm->size)) + return -EINVAL; + + if (va) { + void *v = tee_shm_get_va(shm, pa - shm->paddr); + + if (IS_ERR(v)) + return PTR_ERR(v); + *va = v; + } + return 0; +} +EXPORT_SYMBOL_GPL(tee_shm_pa2va); + +/** + * tee_shm_get_va() - Get virtual address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @returns virtual address of the shared memory + offs if offs is within + * the bounds of this shared memory, else an ERR_PTR + */ +void *tee_shm_get_va(struct tee_shm *shm, size_t offs) +{ + if (offs >= shm->size) + return ERR_PTR(-EINVAL); + return (char *)shm->kaddr + offs; +} +EXPORT_SYMBOL_GPL(tee_shm_get_va); + +/** + * tee_shm_get_pa() - Get physical address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @pa: Physical address to return + * @returns 0 if offs is within the bounds of this shared memory, else an + * error code. + */ +int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa) +{ + if (offs >= shm->size) + return -EINVAL; + if (pa) + *pa = shm->paddr + offs; + return 0; +} +EXPORT_SYMBOL_GPL(tee_shm_get_pa); + +/** + * tee_shm_get_from_id() - Find shared memory object and increase reference + * count + * @ctx: Context owning the shared memory + * @id: Id of shared memory object + * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure + */ +struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id) +{ + struct tee_device *teedev; + struct tee_shm *shm; + + if (!ctx) + return ERR_PTR(-EINVAL); + + teedev = ctx->teedev; + mutex_lock(&teedev->mutex); + shm = idr_find(&teedev->idr, id); + if (!shm || shm->ctx != ctx) + shm = ERR_PTR(-EINVAL); + else if (shm->flags & TEE_SHM_DMA_BUF) + get_dma_buf(shm->dmabuf); + mutex_unlock(&teedev->mutex); + return shm; +} +EXPORT_SYMBOL_GPL(tee_shm_get_from_id); + +/** + * tee_shm_get_id() - Get id of a shared memory object + * @shm: Shared memory handle + * @returns id + */ +int tee_shm_get_id(struct tee_shm *shm) +{ + return shm->id; +} +EXPORT_SYMBOL_GPL(tee_shm_get_id); + +/** + * tee_shm_put() - Decrease reference count on a shared memory handle + * @shm: Shared memory handle + */ +void tee_shm_put(struct tee_shm *shm) +{ + if (shm->flags & TEE_SHM_DMA_BUF) + dma_buf_put(shm->dmabuf); +} +EXPORT_SYMBOL_GPL(tee_shm_put); diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c new file mode 100644 index 000000000000..fb4f8522a526 --- /dev/null +++ b/drivers/tee/tee_shm_pool.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/device.h> +#include <linux/dma-buf.h> +#include <linux/genalloc.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include "tee_private.h" + +static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm, size_t size) +{ + unsigned long va; + struct gen_pool *genpool = poolm->private_data; + size_t s = roundup(size, 1 << genpool->min_alloc_order); + + va = gen_pool_alloc(genpool, s); + if (!va) + return -ENOMEM; + + memset((void *)va, 0, s); + shm->kaddr = (void *)va; + shm->paddr = gen_pool_virt_to_phys(genpool, va); + shm->size = s; + return 0; +} + +static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm) +{ + gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr, + shm->size); + shm->kaddr = NULL; +} + +static const struct tee_shm_pool_mgr_ops pool_ops_generic = { + .alloc = pool_op_gen_alloc, + .free = pool_op_gen_free, +}; + +static void pool_res_mem_destroy(struct tee_shm_pool *pool) +{ + gen_pool_destroy(pool->private_mgr.private_data); + gen_pool_destroy(pool->dma_buf_mgr.private_data); +} + +static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr, + struct tee_shm_pool_mem_info *info, + int min_alloc_order) +{ + size_t page_mask = PAGE_SIZE - 1; + struct gen_pool *genpool = NULL; + int rc; + + /* + * Start and end must be page aligned + */ + if ((info->vaddr & page_mask) || (info->paddr & page_mask) || + (info->size & page_mask)) + return -EINVAL; + + genpool = gen_pool_create(min_alloc_order, -1); + if (!genpool) + return -ENOMEM; + + gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); + rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size, + -1); + if (rc) { + gen_pool_destroy(genpool); + return rc; + } + + mgr->private_data = genpool; + mgr->ops = &pool_ops_generic; + return 0; +} + +/** + * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved + * memory range + * @priv_info: Information for driver private shared memory pool + * @dmabuf_info: Information for dma-buf shared memory pool + * + * Start and end of pools will must be page aligned. + * + * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied + * in @dmabuf, others will use the range provided by @priv. + * + * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. + */ +struct tee_shm_pool * +tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info, + struct tee_shm_pool_mem_info *dmabuf_info) +{ + struct tee_shm_pool *pool = NULL; + int ret; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) { + ret = -ENOMEM; + goto err; + } + + /* + * Create the pool for driver private shared memory + */ + ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info, + 3 /* 8 byte aligned */); + if (ret) + goto err; + + /* + * Create the pool for dma_buf shared memory + */ + ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info, + PAGE_SHIFT); + if (ret) + goto err; + + pool->destroy = pool_res_mem_destroy; + return pool; +err: + if (ret == -ENOMEM) + pr_err("%s: can't allocate memory for res_mem shared memory pool\n", __func__); + if (pool && pool->private_mgr.private_data) + gen_pool_destroy(pool->private_mgr.private_data); + kfree(pool); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem); + +/** + * tee_shm_pool_free() - Free a shared memory pool + * @pool: The shared memory pool to free + * + * There must be no remaining shared memory allocated from this pool when + * this function is called. + */ +void tee_shm_pool_free(struct tee_shm_pool *pool) +{ + pool->destroy(pool); + kfree(pool); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_free); diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 328c3987b112..967f069385d0 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -44,14 +44,14 @@ static const struct file_operations capabilities_file_ops = { static int xenfs_fill_super(struct super_block *sb, void *data, int silent) { - static struct tree_descr xenfs_files[] = { + static const struct tree_descr xenfs_files[] = { [2] = { "xenbus", &xen_xenbus_fops, S_IRUSR|S_IWUSR }, { "capabilities", &capabilities_file_ops, S_IRUGO }, { "privcmd", &xen_privcmd_fops, S_IRUSR|S_IWUSR }, {""}, }; - static struct tree_descr xenfs_init_files[] = { + static const struct tree_descr xenfs_init_files[] = { [2] = { "xenbus", &xen_xenbus_fops, S_IRUSR|S_IWUSR }, { "capabilities", &capabilities_file_ops, S_IRUGO }, { "privcmd", &xen_privcmd_fops, S_IRUSR|S_IWUSR }, diff --git a/fs/affs/affs.h b/fs/affs/affs.h index 2f8bab390d13..773749be8290 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -7,7 +7,7 @@ #include <linux/types.h> #include <linux/fs.h> #include <linux/buffer_head.h> -#include <linux/amigaffs.h> +#include "amigaffs.h" #include <linux/mutex.h> #include <linux/workqueue.h> @@ -173,7 +173,7 @@ extern int affs_link(struct dentry *olddentry, struct inode *dir, struct dentry *dentry); extern int affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); -extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry, +extern int affs_rename2(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags); diff --git a/include/linux/amigaffs.h b/fs/affs/amigaffs.h index 43b41c06aa37..43b41c06aa37 100644 --- a/include/linux/amigaffs.h +++ b/fs/affs/amigaffs.h diff --git a/fs/affs/dir.c b/fs/affs/dir.c index f1e7294381c5..591ecd7f3063 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -35,7 +35,7 @@ const struct inode_operations affs_dir_inode_operations = { .symlink = affs_symlink, .mkdir = affs_mkdir, .rmdir = affs_rmdir, - .rename = affs_rename, + .rename = affs_rename2, .setattr = affs_notify_change, }; diff --git a/fs/affs/file.c b/fs/affs/file.c index 0deec9cc2362..196ee7f6fdc4 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -499,7 +499,7 @@ affs_getemptyblk_ino(struct inode *inode, int block) } static int -affs_do_readpage_ofs(struct page *page, unsigned to) +affs_do_readpage_ofs(struct page *page, unsigned to, int create) { struct inode *inode = page->mapping->host; struct super_block *sb = inode->i_sb; @@ -518,7 +518,7 @@ affs_do_readpage_ofs(struct page *page, unsigned to) boff = tmp % bsize; while (pos < to) { - bh = affs_bread_ino(inode, bidx, 0); + bh = affs_bread_ino(inode, bidx, create); if (IS_ERR(bh)) return PTR_ERR(bh); tmp = min(bsize - boff, to - pos); @@ -620,7 +620,7 @@ affs_readpage_ofs(struct file *file, struct page *page) memset(page_address(page) + to, 0, PAGE_SIZE - to); } - err = affs_do_readpage_ofs(page, to); + err = affs_do_readpage_ofs(page, to, 0); if (!err) SetPageUptodate(page); unlock_page(page); @@ -657,7 +657,7 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping return 0; /* XXX: inefficient but safe in the face of short writes */ - err = affs_do_readpage_ofs(page, PAGE_SIZE); + err = affs_do_readpage_ofs(page, PAGE_SIZE, 1); if (err) { unlock_page(page); put_page(page); @@ -679,7 +679,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping, int written; from = pos & (PAGE_SIZE - 1); - to = pos + len; + to = from + len; /* * XXX: not sure if this can handle short copies (len < copied), but * we don't have to, because the page should always be uptodate here, diff --git a/fs/affs/inode.c b/fs/affs/inode.c index abcc59899229..fd4ef3c40e40 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -140,6 +140,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) inode->i_fop = &affs_file_operations; break; case ST_SOFTLINK: + inode->i_size = strlen((char *)AFFS_HEAD(bh)->table); inode->i_mode |= S_IFLNK; inode_nohighmem(inode); inode->i_op = &affs_symlink_inode_operations; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 96dd1d09a273..46d3ace6761d 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -365,6 +365,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) symname++; } *p = 0; + inode->i_size = i + 1; mark_buffer_dirty_inode(bh, inode); affs_brelse(bh); mark_inode_dirty(inode); @@ -393,21 +394,14 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) return affs_add_entry(dir, inode, dentry, ST_LINKFILE); } -int +static int affs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) + struct inode *new_dir, struct dentry *new_dentry) { struct super_block *sb = old_dir->i_sb; struct buffer_head *bh = NULL; int retval; - if (flags & ~RENAME_NOREPLACE) - return -EINVAL; - - pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__, - old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry); - retval = affs_check_name(new_dentry->d_name.name, new_dentry->d_name.len, affs_nofilenametruncate(old_dentry)); @@ -447,6 +441,76 @@ done: return retval; } +static int +affs_xrename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + + struct super_block *sb = old_dir->i_sb; + struct buffer_head *bh_old = NULL; + struct buffer_head *bh_new = NULL; + int retval; + + bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino); + if (!bh_old) + return -EIO; + + bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino); + if (!bh_new) + return -EIO; + + /* Remove old header from its parent directory. */ + affs_lock_dir(old_dir); + retval = affs_remove_hash(old_dir, bh_old); + affs_unlock_dir(old_dir); + if (retval) + goto done; + + /* Remove new header from its parent directory. */ + affs_lock_dir(new_dir); + retval = affs_remove_hash(new_dir, bh_new); + affs_unlock_dir(new_dir); + if (retval) + goto done; + + /* Insert old into the new directory with the new name. */ + affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry); + affs_fix_checksum(sb, bh_old); + affs_lock_dir(new_dir); + retval = affs_insert_hash(new_dir, bh_old); + affs_unlock_dir(new_dir); + + /* Insert new into the old directory with the old name. */ + affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry); + affs_fix_checksum(sb, bh_new); + affs_lock_dir(old_dir); + retval = affs_insert_hash(old_dir, bh_new); + affs_unlock_dir(old_dir); +done: + mark_buffer_dirty_inode(bh_old, new_dir); + mark_buffer_dirty_inode(bh_new, old_dir); + affs_brelse(bh_old); + affs_brelse(bh_new); + return retval; +} + +int affs_rename2(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + + if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) + return -EINVAL; + + pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__, + old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry); + + if (flags & RENAME_EXCHANGE) + return affs_xrename(old_dir, old_dentry, new_dir, new_dentry); + + return affs_rename(old_dir, old_dentry, new_dir, new_dentry); +} + static struct dentry *affs_get_parent(struct dentry *child) { struct inode *parent; @@ -477,11 +541,6 @@ static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino, if (IS_ERR(inode)) return ERR_CAST(inode); - if (generation && inode->i_generation != generation) { - iput(inode); - return ERR_PTR(-ESTALE); - } - return inode; } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index bee1a36bc2ec..f4718098ac31 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -818,7 +818,7 @@ static const struct super_operations s_ops = { static int bm_fill_super(struct super_block *sb, void *data, int silent) { int err; - static struct tree_descr bm_files[] = { + static const struct tree_descr bm_files[] = { [2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO}, [3] = {"register", &bm_register_operations, S_IWUSR}, /* last one */ {""} diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 7699e16784d3..24865da63d8f 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -26,6 +26,11 @@ #include "delayed-ref.h" #include "locking.h" +enum merge_mode { + MERGE_IDENTICAL_KEYS = 1, + MERGE_IDENTICAL_PARENTS, +}; + /* Just an arbitrary number so we can be sure this happened */ #define BACKREF_FOUND_SHARED 6 @@ -533,7 +538,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, * slot==nritems. In that case, go to the next leaf before we continue. */ if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { - if (time_seq == (u64)-1) + if (time_seq == SEQ_LAST) ret = btrfs_next_leaf(root, path); else ret = btrfs_next_old_leaf(root, path, time_seq); @@ -577,7 +582,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, eie = NULL; } next: - if (time_seq == (u64)-1) + if (time_seq == SEQ_LAST) ret = btrfs_next_item(root, path); else ret = btrfs_next_old_item(root, path, time_seq); @@ -629,7 +634,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, if (path->search_commit_root) root_level = btrfs_header_level(root->commit_root); - else if (time_seq == (u64)-1) + else if (time_seq == SEQ_LAST) root_level = btrfs_header_level(root->node); else root_level = btrfs_old_root_level(root, time_seq); @@ -640,7 +645,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, } path->lowest_level = level; - if (time_seq == (u64)-1) + if (time_seq == SEQ_LAST) ret = btrfs_search_slot(NULL, root, &ref->key_for_search, path, 0, 0); else @@ -809,14 +814,12 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info, /* * merge backrefs and adjust counts accordingly * - * mode = 1: merge identical keys, if key is set - * FIXME: if we add more keys in __add_prelim_ref, we can merge more here. - * additionally, we could even add a key range for the blocks we - * looked into to merge even more (-> replace unresolved refs by those - * having a parent). - * mode = 2: merge identical parents + * FIXME: For MERGE_IDENTICAL_KEYS, if we add more keys in __add_prelim_ref + * then we can merge more here. Additionally, we could even add a key + * range for the blocks we looked into to merge even more (-> replace + * unresolved refs by those having a parent). */ -static void __merge_refs(struct list_head *head, int mode) +static void __merge_refs(struct list_head *head, enum merge_mode mode) { struct __prelim_ref *pos1; @@ -829,7 +832,7 @@ static void __merge_refs(struct list_head *head, int mode) if (!ref_for_same_block(ref1, ref2)) continue; - if (mode == 1) { + if (mode == MERGE_IDENTICAL_KEYS) { if (!ref1->parent && ref2->parent) swap(ref1, ref2); } else { @@ -1196,7 +1199,7 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info, * * NOTE: This can return values > 0 * - * If time_seq is set to (u64)-1, it will not search delayed_refs, and behave + * If time_seq is set to SEQ_LAST, it will not search delayed_refs, and behave * much like trans == NULL case, the difference only lies in it will not * commit root. * The special case is for qgroup to search roots in commit_transaction(). @@ -1243,7 +1246,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, path->skip_locking = 1; } - if (time_seq == (u64)-1) + if (time_seq == SEQ_LAST) path->skip_locking = 1; /* @@ -1273,9 +1276,9 @@ again: #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS if (trans && likely(trans->type != __TRANS_DUMMY) && - time_seq != (u64)-1) { + time_seq != SEQ_LAST) { #else - if (trans && time_seq != (u64)-1) { + if (trans && time_seq != SEQ_LAST) { #endif /* * look if there are updates for this ref queued and lock the @@ -1286,7 +1289,7 @@ again: head = btrfs_find_delayed_ref_head(delayed_refs, bytenr); if (head) { if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); + refcount_inc(&head->node.refs); spin_unlock(&delayed_refs->lock); btrfs_release_path(path); @@ -1374,7 +1377,7 @@ again: if (ret) goto out; - __merge_refs(&prefs, 1); + __merge_refs(&prefs, MERGE_IDENTICAL_KEYS); ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs, extent_item_pos, total_refs, @@ -1382,7 +1385,7 @@ again: if (ret) goto out; - __merge_refs(&prefs, 2); + __merge_refs(&prefs, MERGE_IDENTICAL_PARENTS); while (!list_empty(&prefs)) { ref = list_first_entry(&prefs, struct __prelim_ref, list); diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 0c6baaba0651..b8622e4d1744 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -125,6 +125,13 @@ struct btrfs_inode { u64 delalloc_bytes; /* + * Total number of bytes pending delalloc that fall within a file + * range that is either a hole or beyond EOF (and no prealloc extent + * exists in the range). This is always <= delalloc_bytes. + */ + u64 new_delalloc_bytes; + + /* * total number of bytes pending defrag, used by stat to check whether * it needs COW. */ diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index c7721a6aa3bb..10e6b282d09d 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -44,7 +44,7 @@ struct compressed_bio { /* number of bios pending for this compressed extent */ - atomic_t pending_bios; + refcount_t pending_bios; /* the pages with the compressed data on them */ struct page **compressed_pages; @@ -161,7 +161,7 @@ static void end_compressed_bio_read(struct bio *bio) /* if there are more bios still pending for this compressed * extent, just exit */ - if (!atomic_dec_and_test(&cb->pending_bios)) + if (!refcount_dec_and_test(&cb->pending_bios)) goto out; inode = cb->inode; @@ -274,7 +274,7 @@ static void end_compressed_bio_write(struct bio *bio) /* if there are more bios still pending for this compressed * extent, just exit */ - if (!atomic_dec_and_test(&cb->pending_bios)) + if (!refcount_dec_and_test(&cb->pending_bios)) goto out; /* ok, we're the last bio for this extent, step one is to @@ -342,7 +342,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, cb = kmalloc(compressed_bio_size(fs_info, compressed_len), GFP_NOFS); if (!cb) return -ENOMEM; - atomic_set(&cb->pending_bios, 0); + refcount_set(&cb->pending_bios, 0); cb->errors = 0; cb->inode = inode; cb->start = start; @@ -363,7 +363,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, bio_set_op_attrs(bio, REQ_OP_WRITE, 0); bio->bi_private = cb; bio->bi_end_io = end_compressed_bio_write; - atomic_inc(&cb->pending_bios); + refcount_set(&cb->pending_bios, 1); /* create and submit bios for the compressed pages */ bytes_left = compressed_len; @@ -388,7 +388,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, * we inc the count. Otherwise, the cb might get * freed before we're done setting it up */ - atomic_inc(&cb->pending_bios); + refcount_inc(&cb->pending_bios); ret = btrfs_bio_wq_end_io(fs_info, bio, BTRFS_WQ_ENDIO_DATA); BUG_ON(ret); /* -ENOMEM */ @@ -607,7 +607,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, if (!cb) goto out; - atomic_set(&cb->pending_bios, 0); + refcount_set(&cb->pending_bios, 0); cb->errors = 0; cb->inode = inode; cb->mirror_num = mirror_num; @@ -656,7 +656,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, bio_set_op_attrs (comp_bio, REQ_OP_READ, 0); comp_bio->bi_private = cb; comp_bio->bi_end_io = end_compressed_bio_read; - atomic_inc(&cb->pending_bios); + refcount_set(&cb->pending_bios, 1); for (pg_index = 0; pg_index < nr_pages; pg_index++) { page = cb->compressed_pages[pg_index]; @@ -685,7 +685,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, * we inc the count. Otherwise, the cb might get * freed before we're done setting it up */ - atomic_inc(&cb->pending_bios); + refcount_inc(&cb->pending_bios); if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { ret = btrfs_lookup_bio_sums(inode, comp_bio, diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 1c3b6c54d5ee..a3a75f1de002 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -567,7 +567,7 @@ tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, static noinline int tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, int dst_slot, int src_slot, - int nr_items, gfp_t flags) + int nr_items) { struct tree_mod_elem *tm = NULL; struct tree_mod_elem **tm_list = NULL; @@ -578,11 +578,11 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, if (!tree_mod_need_log(fs_info, eb)) return 0; - tm_list = kcalloc(nr_items, sizeof(struct tree_mod_elem *), flags); + tm_list = kcalloc(nr_items, sizeof(struct tree_mod_elem *), GFP_NOFS); if (!tm_list) return -ENOMEM; - tm = kzalloc(sizeof(*tm), flags); + tm = kzalloc(sizeof(*tm), GFP_NOFS); if (!tm) { ret = -ENOMEM; goto free_tms; @@ -596,7 +596,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { tm_list[i] = alloc_tree_mod_elem(eb, i + dst_slot, - MOD_LOG_KEY_REMOVE_WHILE_MOVING, flags); + MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS); if (!tm_list[i]) { ret = -ENOMEM; goto free_tms; @@ -663,7 +663,7 @@ __tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, static noinline int tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, struct extent_buffer *old_root, - struct extent_buffer *new_root, gfp_t flags, + struct extent_buffer *new_root, int log_removal) { struct tree_mod_elem *tm = NULL; @@ -678,14 +678,14 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, if (log_removal && btrfs_header_level(old_root) > 0) { nritems = btrfs_header_nritems(old_root); tm_list = kcalloc(nritems, sizeof(struct tree_mod_elem *), - flags); + GFP_NOFS); if (!tm_list) { ret = -ENOMEM; goto free_tms; } for (i = 0; i < nritems; i++) { tm_list[i] = alloc_tree_mod_elem(old_root, i, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, flags); + MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); if (!tm_list[i]) { ret = -ENOMEM; goto free_tms; @@ -693,7 +693,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, } } - tm = kzalloc(sizeof(*tm), flags); + tm = kzalloc(sizeof(*tm), GFP_NOFS); if (!tm) { ret = -ENOMEM; goto free_tms; @@ -873,7 +873,7 @@ tree_mod_log_eb_move(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, { int ret; ret = tree_mod_log_insert_move(fs_info, dst, dst_offset, src_offset, - nr_items, GFP_NOFS); + nr_items); BUG_ON(ret < 0); } @@ -943,7 +943,7 @@ tree_mod_log_set_root_pointer(struct btrfs_root *root, { int ret; ret = tree_mod_log_insert_root(root->fs_info, root->node, - new_root_node, GFP_NOFS, log_removal); + new_root_node, log_removal); BUG_ON(ret < 0); } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3e21211e99c3..643c70d2b2e6 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -39,6 +39,7 @@ #include <linux/security.h> #include <linux/sizes.h> #include <linux/dynamic_debug.h> +#include <linux/refcount.h> #include "extent_io.h" #include "extent_map.h" #include "async-thread.h" @@ -518,7 +519,7 @@ struct btrfs_caching_control { struct btrfs_work work; struct btrfs_block_group_cache *block_group; u64 progress; - atomic_t count; + refcount_t count; }; /* Once caching_thread() finds this much free space, it will wake up waiters. */ @@ -538,6 +539,14 @@ struct btrfs_io_ctl { unsigned check_crcs:1; }; +/* + * Tree to record all locked full stripes of a RAID5/6 block group + */ +struct btrfs_full_stripe_locks_tree { + struct rb_root root; + struct mutex lock; +}; + struct btrfs_block_group_cache { struct btrfs_key key; struct btrfs_block_group_item item; @@ -648,6 +657,9 @@ struct btrfs_block_group_cache { * Protected by free_space_lock. */ int needs_free_space; + + /* Record locked full stripes for RAID5/6 block group */ + struct btrfs_full_stripe_locks_tree full_stripe_locks_root; }; /* delayed seq elem */ @@ -658,6 +670,8 @@ struct seq_list { #define SEQ_LIST_INIT(name) { .list = LIST_HEAD_INIT((name).list), .seq = 0 } +#define SEQ_LAST ((u64)-1) + enum btrfs_orphan_cleanup_state { ORPHAN_CLEANUP_STARTED = 1, ORPHAN_CLEANUP_DONE = 2, @@ -702,6 +716,11 @@ struct btrfs_delayed_root; #define BTRFS_FS_BTREE_ERR 11 #define BTRFS_FS_LOG1_ERR 12 #define BTRFS_FS_LOG2_ERR 13 +/* + * Indicate that a whole-filesystem exclusive operation is running + * (device replace, resize, device add/delete, balance) + */ +#define BTRFS_FS_EXCL_OP 14 struct btrfs_fs_info { u8 fsid[BTRFS_FSID_SIZE]; @@ -1066,8 +1085,6 @@ struct btrfs_fs_info { /* device replace state */ struct btrfs_dev_replace dev_replace; - atomic_t mutually_exclusive_operation_running; - struct percpu_counter bio_counter; wait_queue_head_t replace_wait; @@ -1220,7 +1237,7 @@ struct btrfs_root { dev_t anon_dev; spinlock_t root_item_lock; - atomic_t refs; + refcount_t refs; struct mutex delalloc_mutex; spinlock_t delalloc_lock; @@ -3646,6 +3663,12 @@ int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info, struct btrfs_device *dev); int btrfs_scrub_progress(struct btrfs_fs_info *fs_info, u64 devid, struct btrfs_scrub_progress *progress); +static inline void btrfs_init_full_stripe_locks_tree( + struct btrfs_full_stripe_locks_tree *locks_root) +{ + locks_root->root = RB_ROOT; + mutex_init(&locks_root->lock); +} /* dev-replace.c */ void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info); @@ -3670,8 +3693,7 @@ struct reada_control *btrfs_reada_add(struct btrfs_root *root, struct btrfs_key *start, struct btrfs_key *end); int btrfs_reada_wait(void *handle); void btrfs_reada_detach(void *handle); -int btree_readahead_hook(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, int err); +int btree_readahead_hook(struct extent_buffer *eb, int err); static inline int is_fstree(u64 rootid) { diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 1aff676f0e5b..8ae409b5a61d 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -52,7 +52,7 @@ static inline void btrfs_init_delayed_node( { delayed_node->root = root; delayed_node->inode_id = inode_id; - atomic_set(&delayed_node->refs, 0); + refcount_set(&delayed_node->refs, 0); delayed_node->ins_root = RB_ROOT; delayed_node->del_root = RB_ROOT; mutex_init(&delayed_node->mutex); @@ -81,7 +81,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node( node = READ_ONCE(btrfs_inode->delayed_node); if (node) { - atomic_inc(&node->refs); + refcount_inc(&node->refs); return node; } @@ -89,14 +89,14 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node( node = radix_tree_lookup(&root->delayed_nodes_tree, ino); if (node) { if (btrfs_inode->delayed_node) { - atomic_inc(&node->refs); /* can be accessed */ + refcount_inc(&node->refs); /* can be accessed */ BUG_ON(btrfs_inode->delayed_node != node); spin_unlock(&root->inode_lock); return node; } btrfs_inode->delayed_node = node; /* can be accessed and cached in the inode */ - atomic_add(2, &node->refs); + refcount_add(2, &node->refs); spin_unlock(&root->inode_lock); return node; } @@ -125,7 +125,7 @@ again: btrfs_init_delayed_node(node, root, ino); /* cached in the btrfs inode and can be accessed */ - atomic_add(2, &node->refs); + refcount_set(&node->refs, 2); ret = radix_tree_preload(GFP_NOFS); if (ret) { @@ -166,7 +166,7 @@ static void btrfs_queue_delayed_node(struct btrfs_delayed_root *root, } else { list_add_tail(&node->n_list, &root->node_list); list_add_tail(&node->p_list, &root->prepare_list); - atomic_inc(&node->refs); /* inserted into list */ + refcount_inc(&node->refs); /* inserted into list */ root->nodes++; set_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags); } @@ -180,7 +180,7 @@ static void btrfs_dequeue_delayed_node(struct btrfs_delayed_root *root, spin_lock(&root->lock); if (test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) { root->nodes--; - atomic_dec(&node->refs); /* not in the list */ + refcount_dec(&node->refs); /* not in the list */ list_del_init(&node->n_list); if (!list_empty(&node->p_list)) list_del_init(&node->p_list); @@ -201,7 +201,7 @@ static struct btrfs_delayed_node *btrfs_first_delayed_node( p = delayed_root->node_list.next; node = list_entry(p, struct btrfs_delayed_node, n_list); - atomic_inc(&node->refs); + refcount_inc(&node->refs); out: spin_unlock(&delayed_root->lock); @@ -228,7 +228,7 @@ static struct btrfs_delayed_node *btrfs_next_delayed_node( p = node->n_list.next; next = list_entry(p, struct btrfs_delayed_node, n_list); - atomic_inc(&next->refs); + refcount_inc(&next->refs); out: spin_unlock(&delayed_root->lock); @@ -253,11 +253,11 @@ static void __btrfs_release_delayed_node( btrfs_dequeue_delayed_node(delayed_root, delayed_node); mutex_unlock(&delayed_node->mutex); - if (atomic_dec_and_test(&delayed_node->refs)) { + if (refcount_dec_and_test(&delayed_node->refs)) { bool free = false; struct btrfs_root *root = delayed_node->root; spin_lock(&root->inode_lock); - if (atomic_read(&delayed_node->refs) == 0) { + if (refcount_read(&delayed_node->refs) == 0) { radix_tree_delete(&root->delayed_nodes_tree, delayed_node->inode_id); free = true; @@ -286,7 +286,7 @@ static struct btrfs_delayed_node *btrfs_first_prepared_delayed_node( p = delayed_root->prepare_list.next; list_del_init(p); node = list_entry(p, struct btrfs_delayed_node, p_list); - atomic_inc(&node->refs); + refcount_inc(&node->refs); out: spin_unlock(&delayed_root->lock); @@ -308,7 +308,7 @@ static struct btrfs_delayed_item *btrfs_alloc_delayed_item(u32 data_len) item->ins_or_del = 0; item->bytes_reserved = 0; item->delayed_node = NULL; - atomic_set(&item->refs, 1); + refcount_set(&item->refs, 1); } return item; } @@ -483,7 +483,7 @@ static void btrfs_release_delayed_item(struct btrfs_delayed_item *item) { if (item) { __btrfs_remove_delayed_item(item); - if (atomic_dec_and_test(&item->refs)) + if (refcount_dec_and_test(&item->refs)) kfree(item); } } @@ -1600,14 +1600,14 @@ bool btrfs_readdir_get_delayed_items(struct inode *inode, mutex_lock(&delayed_node->mutex); item = __btrfs_first_delayed_insertion_item(delayed_node); while (item) { - atomic_inc(&item->refs); + refcount_inc(&item->refs); list_add_tail(&item->readdir_list, ins_list); item = __btrfs_next_delayed_item(item); } item = __btrfs_first_delayed_deletion_item(delayed_node); while (item) { - atomic_inc(&item->refs); + refcount_inc(&item->refs); list_add_tail(&item->readdir_list, del_list); item = __btrfs_next_delayed_item(item); } @@ -1621,7 +1621,7 @@ bool btrfs_readdir_get_delayed_items(struct inode *inode, * insert/delete delayed items in this period. So we also needn't * requeue or dequeue this delayed node. */ - atomic_dec(&delayed_node->refs); + refcount_dec(&delayed_node->refs); return true; } @@ -1634,13 +1634,13 @@ void btrfs_readdir_put_delayed_items(struct inode *inode, list_for_each_entry_safe(curr, next, ins_list, readdir_list) { list_del(&curr->readdir_list); - if (atomic_dec_and_test(&curr->refs)) + if (refcount_dec_and_test(&curr->refs)) kfree(curr); } list_for_each_entry_safe(curr, next, del_list, readdir_list) { list_del(&curr->readdir_list); - if (atomic_dec_and_test(&curr->refs)) + if (refcount_dec_and_test(&curr->refs)) kfree(curr); } @@ -1667,7 +1667,7 @@ int btrfs_should_delete_dir_index(struct list_head *del_list, list_del(&curr->readdir_list); ret = (curr->key.offset == index); - if (atomic_dec_and_test(&curr->refs)) + if (refcount_dec_and_test(&curr->refs)) kfree(curr); if (ret) @@ -1705,7 +1705,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, list_del(&curr->readdir_list); if (curr->key.offset < ctx->pos) { - if (atomic_dec_and_test(&curr->refs)) + if (refcount_dec_and_test(&curr->refs)) kfree(curr); continue; } @@ -1722,7 +1722,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, over = !dir_emit(ctx, name, name_len, location.objectid, d_type); - if (atomic_dec_and_test(&curr->refs)) + if (refcount_dec_and_test(&curr->refs)) kfree(curr); if (over) @@ -1963,7 +1963,7 @@ void btrfs_kill_all_delayed_nodes(struct btrfs_root *root) inode_id = delayed_nodes[n - 1]->inode_id + 1; for (i = 0; i < n; i++) - atomic_inc(&delayed_nodes[i]->refs); + refcount_inc(&delayed_nodes[i]->refs); spin_unlock(&root->inode_lock); for (i = 0; i < n; i++) { diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index 40327cc3b99a..c4189d495934 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -26,7 +26,7 @@ #include <linux/list.h> #include <linux/wait.h> #include <linux/atomic.h> - +#include <linux/refcount.h> #include "ctree.h" /* types of the delayed item */ @@ -67,7 +67,7 @@ struct btrfs_delayed_node { struct rb_root del_root; struct mutex mutex; struct btrfs_inode_item inode_item; - atomic_t refs; + refcount_t refs; u64 index_cnt; unsigned long flags; int count; @@ -80,7 +80,7 @@ struct btrfs_delayed_item { struct list_head readdir_list; /* used for readdir items */ u64 bytes_reserved; struct btrfs_delayed_node *delayed_node; - atomic_t refs; + refcount_t refs; int ins_or_del; u32 data_len; char data[0]; diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 6eb80952efb3..be70d90dfee5 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -164,7 +164,7 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, if (mutex_trylock(&head->mutex)) return 0; - atomic_inc(&head->node.refs); + refcount_inc(&head->node.refs); spin_unlock(&delayed_refs->lock); mutex_lock(&head->mutex); @@ -590,7 +590,7 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info, delayed_refs = &trans->transaction->delayed_refs; /* first set the basic ref node struct up */ - atomic_set(&ref->refs, 1); + refcount_set(&ref->refs, 1); ref->bytenr = bytenr; ref->num_bytes = num_bytes; ref->ref_mod = count_mod; @@ -682,7 +682,7 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info, delayed_refs = &trans->transaction->delayed_refs; /* first set the basic ref node struct up */ - atomic_set(&ref->refs, 1); + refcount_set(&ref->refs, 1); ref->bytenr = bytenr; ref->num_bytes = num_bytes; ref->ref_mod = 1; @@ -739,7 +739,7 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info, seq = atomic64_read(&fs_info->tree_mod_seq); /* first set the basic ref node struct up */ - atomic_set(&ref->refs, 1); + refcount_set(&ref->refs, 1); ref->bytenr = bytenr; ref->num_bytes = num_bytes; ref->ref_mod = 1; diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index 0e537f98f1a1..c0264ff01b53 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -18,6 +18,8 @@ #ifndef __DELAYED_REF__ #define __DELAYED_REF__ +#include <linux/refcount.h> + /* these are the possible values of struct btrfs_delayed_ref_node->action */ #define BTRFS_ADD_DELAYED_REF 1 /* add one backref to the tree */ #define BTRFS_DROP_DELAYED_REF 2 /* delete one backref from the tree */ @@ -53,7 +55,7 @@ struct btrfs_delayed_ref_node { u64 seq; /* ref count on this data structure */ - atomic_t refs; + refcount_t refs; /* * how many refs is this entry adding or deleting. For @@ -220,8 +222,8 @@ btrfs_free_delayed_extent_op(struct btrfs_delayed_extent_op *op) static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) { - WARN_ON(atomic_read(&ref->refs) == 0); - if (atomic_dec_and_test(&ref->refs)) { + WARN_ON(refcount_read(&ref->refs) == 0); + if (refcount_dec_and_test(&ref->refs)) { WARN_ON(ref->in_tree); switch (ref->type) { case BTRFS_TREE_BLOCK_REF_KEY: diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index e653921f05d9..5fe1ca8abc70 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -546,8 +546,10 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, mutex_unlock(&fs_info->chunk_mutex); mutex_unlock(&fs_info->fs_devices->device_list_mutex); mutex_unlock(&uuid_mutex); + btrfs_rm_dev_replace_blocked(fs_info); if (tgt_device) btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); + btrfs_rm_dev_replace_unblocked(fs_info); mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); return scrub_ret; @@ -665,7 +667,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: srcdev = dev_replace->srcdev; - args->status.progress_1000 = div_u64(dev_replace->cursor_left, + args->status.progress_1000 = div64_u64(dev_replace->cursor_left, div_u64(btrfs_device_get_total_bytes(srcdev), 1000)); break; } @@ -784,8 +786,7 @@ int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info) } btrfs_dev_replace_unlock(dev_replace, 1); - WARN_ON(atomic_xchg( - &fs_info->mutually_exclusive_operation_running, 1)); + WARN_ON(test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)); task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl"); return PTR_ERR_OR_ZERO(task); } @@ -814,7 +815,7 @@ static int btrfs_dev_replace_kthread(void *data) (unsigned int)progress); } btrfs_dev_replace_continue_on_mount(fs_info); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); return 0; } diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 061c1d1f774f..8685d67185d0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -762,7 +762,7 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, err: if (reads_done && test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) - btree_readahead_hook(fs_info, eb, ret); + btree_readahead_hook(eb, ret); if (ret) { /* @@ -787,7 +787,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror) eb->read_mirror = failed_mirror; atomic_dec(&eb->io_pages); if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) - btree_readahead_hook(eb->fs_info, eb, -EIO); + btree_readahead_hook(eb, -EIO); return -EIO; /* we fixed nothing */ } @@ -1340,7 +1340,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, atomic_set(&root->log_writers, 0); atomic_set(&root->log_batch, 0); atomic_set(&root->orphan_inodes, 0); - atomic_set(&root->refs, 1); + refcount_set(&root->refs, 1); atomic_set(&root->will_be_snapshoted, 0); atomic64_set(&root->qgroup_meta_rsv, 0); root->log_transid = 0; @@ -3497,10 +3497,11 @@ static void btrfs_end_empty_barrier(struct bio *bio) */ static int write_dev_flush(struct btrfs_device *device, int wait) { + struct request_queue *q = bdev_get_queue(device->bdev); struct bio *bio; int ret = 0; - if (device->nobarriers) + if (!test_bit(QUEUE_FLAG_WC, &q->queue_flags)) return 0; if (wait) { @@ -4321,7 +4322,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, head = rb_entry(node, struct btrfs_delayed_ref_head, href_node); if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); + refcount_inc(&head->node.refs); spin_unlock(&delayed_refs->lock); mutex_lock(&head->mutex); @@ -4593,7 +4594,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info) t = list_first_entry(&fs_info->trans_list, struct btrfs_transaction, list); if (t->state >= TRANS_STATE_COMMIT_START) { - atomic_inc(&t->use_count); + refcount_inc(&t->use_count); spin_unlock(&fs_info->trans_lock); btrfs_wait_for_commit(fs_info, t->transid); btrfs_put_transaction(t); diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 2e0ec29bfd69..21f1ceb85b76 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -101,14 +101,14 @@ struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info); */ static inline struct btrfs_root *btrfs_grab_fs_root(struct btrfs_root *root) { - if (atomic_inc_not_zero(&root->refs)) + if (refcount_inc_not_zero(&root->refs)) return root; return NULL; } static inline void btrfs_put_fs_root(struct btrfs_root *root) { - if (atomic_dec_and_test(&root->refs)) + if (refcount_dec_and_test(&root->refs)) kfree(root); } diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index be5477676cc8..e390451c72e6 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -131,6 +131,16 @@ void btrfs_put_block_group(struct btrfs_block_group_cache *cache) if (atomic_dec_and_test(&cache->count)) { WARN_ON(cache->pinned > 0); WARN_ON(cache->reserved > 0); + + /* + * If not empty, someone is still holding mutex of + * full_stripe_lock, which can only be released by caller. + * And it will definitely cause use-after-free when caller + * tries to release full stripe lock. + * + * No better way to resolve, but only to warn. + */ + WARN_ON(!RB_EMPTY_ROOT(&cache->full_stripe_locks_root.root)); kfree(cache->free_space_ctl); kfree(cache); } @@ -316,14 +326,14 @@ get_caching_control(struct btrfs_block_group_cache *cache) } ctl = cache->caching_ctl; - atomic_inc(&ctl->count); + refcount_inc(&ctl->count); spin_unlock(&cache->lock); return ctl; } static void put_caching_control(struct btrfs_caching_control *ctl) { - if (atomic_dec_and_test(&ctl->count)) + if (refcount_dec_and_test(&ctl->count)) kfree(ctl); } @@ -599,7 +609,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, init_waitqueue_head(&caching_ctl->wait); caching_ctl->block_group = cache; caching_ctl->progress = cache->key.objectid; - atomic_set(&caching_ctl->count, 1); + refcount_set(&caching_ctl->count, 1); btrfs_init_work(&caching_ctl->work, btrfs_cache_helper, caching_thread, NULL, NULL); @@ -620,7 +630,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, struct btrfs_caching_control *ctl; ctl = cache->caching_ctl; - atomic_inc(&ctl->count); + refcount_inc(&ctl->count); prepare_to_wait(&ctl->wait, &wait, TASK_UNINTERRUPTIBLE); spin_unlock(&cache->lock); @@ -707,7 +717,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, } down_write(&fs_info->commit_root_sem); - atomic_inc(&caching_ctl->count); + refcount_inc(&caching_ctl->count); list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups); up_write(&fs_info->commit_root_sem); @@ -892,7 +902,7 @@ search_again: head = btrfs_find_delayed_ref_head(delayed_refs, bytenr); if (head) { if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); + refcount_inc(&head->node.refs); spin_unlock(&delayed_refs->lock); btrfs_release_path(path); @@ -2980,7 +2990,7 @@ again: struct btrfs_delayed_ref_node *ref; ref = &head->node; - atomic_inc(&ref->refs); + refcount_inc(&ref->refs); spin_unlock(&delayed_refs->lock); /* @@ -3003,7 +3013,6 @@ again: goto again; } out: - assert_qgroups_uptodate(trans); trans->can_flush_pending_bgs = can_flush_pending_bgs; return 0; } @@ -3057,7 +3066,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root, } if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); + refcount_inc(&head->node.refs); spin_unlock(&delayed_refs->lock); btrfs_release_path(path); @@ -3443,7 +3452,8 @@ again: /* * don't bother trying to write stuff out _if_ * a) we're not cached, - * b) we're with nospace_cache mount option. + * b) we're with nospace_cache mount option, + * c) we're with v2 space_cache (FREE_SPACE_TREE). */ dcs = BTRFS_DC_WRITTEN; spin_unlock(&block_group->lock); @@ -9917,6 +9927,7 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info, btrfs_init_free_space_ctl(cache); atomic_set(&cache->trimming, 0); mutex_init(&cache->free_space_lock); + btrfs_init_full_stripe_locks_tree(&cache->full_stripe_locks_root); return cache; } @@ -10416,7 +10427,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, &fs_info->caching_block_groups, list) if (ctl->block_group == block_group) { caching_ctl = ctl; - atomic_inc(&caching_ctl->count); + refcount_inc(&caching_ctl->count); break; } } @@ -10850,7 +10861,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, spin_lock(&fs_info->trans_lock); trans = fs_info->running_transaction; if (trans) - atomic_inc(&trans->use_count); + refcount_inc(&trans->use_count); spin_unlock(&fs_info->trans_lock); ret = find_free_dev_extent_start(trans, device, minlen, start, diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 27fdb250b446..d8da3edf2ac3 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -68,7 +68,7 @@ void btrfs_leak_debug_check(void) pr_err("BTRFS: state leak: start %llu end %llu state %u in tree %d refs %d\n", state->start, state->end, state->state, extent_state_in_tree(state), - atomic_read(&state->refs)); + refcount_read(&state->refs)); list_del(&state->leak_list); kmem_cache_free(extent_state_cache, state); } @@ -238,7 +238,7 @@ static struct extent_state *alloc_extent_state(gfp_t mask) state->failrec = NULL; RB_CLEAR_NODE(&state->rb_node); btrfs_leak_debug_add(&state->leak_list, &states); - atomic_set(&state->refs, 1); + refcount_set(&state->refs, 1); init_waitqueue_head(&state->wq); trace_alloc_extent_state(state, mask, _RET_IP_); return state; @@ -248,7 +248,7 @@ void free_extent_state(struct extent_state *state) { if (!state) return; - if (atomic_dec_and_test(&state->refs)) { + if (refcount_dec_and_test(&state->refs)) { WARN_ON(extent_state_in_tree(state)); btrfs_leak_debug_del(&state->leak_list); trace_free_extent_state(state, _RET_IP_); @@ -641,7 +641,7 @@ again: if (cached && extent_state_in_tree(cached) && cached->start <= start && cached->end > start) { if (clear) - atomic_dec(&cached->refs); + refcount_dec(&cached->refs); state = cached; goto hit_next; } @@ -793,7 +793,7 @@ process_node: if (state->state & bits) { start = state->start; - atomic_inc(&state->refs); + refcount_inc(&state->refs); wait_on_state(tree, state); free_extent_state(state); goto again; @@ -834,7 +834,7 @@ static void cache_state_if_flags(struct extent_state *state, if (cached_ptr && !(*cached_ptr)) { if (!flags || (state->state & flags)) { *cached_ptr = state; - atomic_inc(&state->refs); + refcount_inc(&state->refs); } } } @@ -1538,7 +1538,7 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree, if (!found) { *start = state->start; *cached_state = state; - atomic_inc(&state->refs); + refcount_inc(&state->refs); } found++; *end = state->end; @@ -2004,16 +2004,11 @@ int repair_io_failure(struct btrfs_inode *inode, u64 start, u64 length, u64 map_length = 0; u64 sector; struct btrfs_bio *bbio = NULL; - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; int ret; ASSERT(!(fs_info->sb->s_flags & MS_RDONLY)); BUG_ON(!mirror_num); - /* we can't repair anything in raid56 yet */ - if (btrfs_is_parity_mirror(map_tree, logical, length, mirror_num)) - return 0; - bio = btrfs_io_bio_alloc(GFP_NOFS, 1); if (!bio) return -EIO; @@ -2026,17 +2021,35 @@ int repair_io_failure(struct btrfs_inode *inode, u64 start, u64 length, * read repair operation. */ btrfs_bio_counter_inc_blocked(fs_info); - ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical, - &map_length, &bbio, mirror_num); - if (ret) { - btrfs_bio_counter_dec(fs_info); - bio_put(bio); - return -EIO; + if (btrfs_is_parity_mirror(fs_info, logical, length, mirror_num)) { + /* + * Note that we don't use BTRFS_MAP_WRITE because it's supposed + * to update all raid stripes, but here we just want to correct + * bad stripe, thus BTRFS_MAP_READ is abused to only get the bad + * stripe's dev and sector. + */ + ret = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical, + &map_length, &bbio, 0); + if (ret) { + btrfs_bio_counter_dec(fs_info); + bio_put(bio); + return -EIO; + } + ASSERT(bbio->mirror_num == 1); + } else { + ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical, + &map_length, &bbio, mirror_num); + if (ret) { + btrfs_bio_counter_dec(fs_info); + bio_put(bio); + return -EIO; + } + BUG_ON(mirror_num != bbio->mirror_num); } - BUG_ON(mirror_num != bbio->mirror_num); - sector = bbio->stripes[mirror_num-1].physical >> 9; + + sector = bbio->stripes[bbio->mirror_num - 1].physical >> 9; bio->bi_iter.bi_sector = sector; - dev = bbio->stripes[mirror_num-1].dev; + dev = bbio->stripes[bbio->mirror_num - 1].dev; btrfs_put_bbio(bbio); if (!dev || !dev->bdev || !dev->writeable) { btrfs_bio_counter_dec(fs_info); @@ -2859,7 +2872,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset, em = *em_cached; if (extent_map_in_tree(em) && start >= em->start && start < extent_map_end(em)) { - atomic_inc(&em->refs); + refcount_inc(&em->refs); return em; } @@ -2870,7 +2883,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset, em = get_extent(BTRFS_I(inode), page, pg_offset, start, len, 0); if (em_cached && !IS_ERR_OR_NULL(em)) { BUG_ON(*em_cached); - atomic_inc(&em->refs); + refcount_inc(&em->refs); *em_cached = em; } return em; diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 3e4fad4a909d..1eafa2f0ede3 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -2,6 +2,7 @@ #define __EXTENTIO__ #include <linux/rbtree.h> +#include <linux/refcount.h> #include "ulist.h" /* bits for the extent state */ @@ -14,14 +15,17 @@ #define EXTENT_DEFRAG (1U << 6) #define EXTENT_BOUNDARY (1U << 9) #define EXTENT_NODATASUM (1U << 10) -#define EXTENT_DO_ACCOUNTING (1U << 11) +#define EXTENT_CLEAR_META_RESV (1U << 11) #define EXTENT_FIRST_DELALLOC (1U << 12) #define EXTENT_NEED_WAIT (1U << 13) #define EXTENT_DAMAGED (1U << 14) #define EXTENT_NORESERVE (1U << 15) #define EXTENT_QGROUP_RESERVED (1U << 16) #define EXTENT_CLEAR_DATA_RESV (1U << 17) +#define EXTENT_DELALLOC_NEW (1U << 18) #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) +#define EXTENT_DO_ACCOUNTING (EXTENT_CLEAR_META_RESV | \ + EXTENT_CLEAR_DATA_RESV) #define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC) /* @@ -143,7 +147,7 @@ struct extent_state { /* ADD NEW ELEMENTS AFTER THIS */ wait_queue_head_t wq; - atomic_t refs; + refcount_t refs; unsigned state; struct io_failure_record *failrec; diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 26f9ac719d20..69850155870c 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -55,7 +55,7 @@ struct extent_map *alloc_extent_map(void) em->flags = 0; em->compress_type = BTRFS_COMPRESS_NONE; em->generation = 0; - atomic_set(&em->refs, 1); + refcount_set(&em->refs, 1); INIT_LIST_HEAD(&em->list); return em; } @@ -71,8 +71,8 @@ void free_extent_map(struct extent_map *em) { if (!em) return; - WARN_ON(atomic_read(&em->refs) == 0); - if (atomic_dec_and_test(&em->refs)) { + WARN_ON(refcount_read(&em->refs) == 0); + if (refcount_dec_and_test(&em->refs)) { WARN_ON(extent_map_in_tree(em)); WARN_ON(!list_empty(&em->list)); if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) @@ -322,7 +322,7 @@ static inline void setup_extent_mapping(struct extent_map_tree *tree, struct extent_map *em, int modified) { - atomic_inc(&em->refs); + refcount_inc(&em->refs); em->mod_start = em->start; em->mod_len = em->len; @@ -381,7 +381,7 @@ __lookup_extent_mapping(struct extent_map_tree *tree, if (strict && !(end > em->start && start < extent_map_end(em))) return NULL; - atomic_inc(&em->refs); + refcount_inc(&em->refs); return em; } diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index eb8b8fae036b..a67b2def5413 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -2,6 +2,7 @@ #define __EXTENTMAP__ #include <linux/rbtree.h> +#include <linux/refcount.h> #define EXTENT_MAP_LAST_BYTE ((u64)-4) #define EXTENT_MAP_HOLE ((u64)-3) @@ -41,7 +42,7 @@ struct extent_map { */ struct map_lookup *map_lookup; }; - atomic_t refs; + refcount_t refs; unsigned int compress_type; struct list_head list; }; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 520cb7230b2d..da1096eb1a40 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1404,6 +1404,47 @@ fail: } +static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode, + const u64 start, + const u64 len, + struct extent_state **cached_state) +{ + u64 search_start = start; + const u64 end = start + len - 1; + + while (search_start < end) { + const u64 search_len = end - search_start + 1; + struct extent_map *em; + u64 em_len; + int ret = 0; + + em = btrfs_get_extent(inode, NULL, 0, search_start, + search_len, 0); + if (IS_ERR(em)) + return PTR_ERR(em); + + if (em->block_start != EXTENT_MAP_HOLE) + goto next; + + em_len = em->len; + if (em->start < search_start) + em_len -= search_start - em->start; + if (em_len > search_len) + em_len = search_len; + + ret = set_extent_bit(&inode->io_tree, search_start, + search_start + em_len - 1, + EXTENT_DELALLOC_NEW, + NULL, cached_state, GFP_NOFS); +next: + search_start = extent_map_end(em); + free_extent_map(em); + if (ret) + return ret; + } + return 0; +} + /* * This function locks the extent and properly waits for data=ordered extents * to finish before allowing the pages to be modified if need. @@ -1432,8 +1473,11 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages, + round_up(pos + write_bytes - start_pos, fs_info->sectorsize) - 1; - if (start_pos < inode->vfs_inode.i_size) { + if (start_pos < inode->vfs_inode.i_size || + (inode->flags & BTRFS_INODE_PREALLOC)) { struct btrfs_ordered_extent *ordered; + unsigned int clear_bits; + lock_extent_bits(&inode->io_tree, start_pos, last_pos, cached_state); ordered = btrfs_lookup_ordered_range(inode, start_pos, @@ -1454,11 +1498,19 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages, } if (ordered) btrfs_put_ordered_extent(ordered); - + ret = btrfs_find_new_delalloc_bytes(inode, start_pos, + last_pos - start_pos + 1, + cached_state); + clear_bits = EXTENT_DIRTY | EXTENT_DELALLOC | + EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG; + if (ret) + clear_bits |= EXTENT_DELALLOC_NEW | EXTENT_LOCKED; clear_extent_bit(&inode->io_tree, start_pos, - last_pos, EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, - 0, 0, cached_state, GFP_NOFS); + last_pos, clear_bits, + (clear_bits & EXTENT_LOCKED) ? 1 : 0, + 0, cached_state, GFP_NOFS); + if (ret) + return ret; *lockstart = start_pos; *lockend = last_pos; ret = 1; @@ -2342,13 +2394,8 @@ static int find_first_non_hole(struct inode *inode, u64 *start, u64 *len) int ret = 0; em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, *start, *len, 0); - if (IS_ERR_OR_NULL(em)) { - if (!em) - ret = -ENOMEM; - else - ret = PTR_ERR(em); - return ret; - } + if (IS_ERR(em)) + return PTR_ERR(em); /* Hole or vacuum extent(only exists in no-hole mode) */ if (em->block_start == EXTENT_MAP_HOLE) { @@ -2835,11 +2882,8 @@ static long btrfs_fallocate(struct file *file, int mode, while (1) { em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, cur_offset, alloc_end - cur_offset, 0); - if (IS_ERR_OR_NULL(em)) { - if (!em) - ret = -ENOMEM; - else - ret = PTR_ERR(em); + if (IS_ERR(em)) { + ret = PTR_ERR(em); break; } last_byte = min(extent_map_end(em), alloc_end); @@ -2856,8 +2900,10 @@ static long btrfs_fallocate(struct file *file, int mode, } ret = btrfs_qgroup_reserve_data(inode, cur_offset, last_byte - cur_offset); - if (ret < 0) + if (ret < 0) { + free_extent_map(em); break; + } } else { /* * Do not need to reserve unwritten extent for this diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index da6841efac26..c5e6180cdb8c 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -355,7 +355,7 @@ static void io_ctl_map_page(struct btrfs_io_ctl *io_ctl, int clear) io_ctl->orig = io_ctl->cur; io_ctl->size = PAGE_SIZE; if (clear) - memset(io_ctl->cur, 0, PAGE_SIZE); + clear_page(io_ctl->cur); } static void io_ctl_drop_pages(struct btrfs_io_ctl *io_ctl) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5e71f1ea3391..17cbe9306faf 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -115,6 +115,31 @@ static struct extent_map *create_io_em(struct inode *inode, u64 start, u64 len, u64 ram_bytes, int compress_type, int type); +static void __endio_write_update_ordered(struct inode *inode, + const u64 offset, const u64 bytes, + const bool uptodate); + +/* + * Cleanup all submitted ordered extents in specified range to handle errors + * from the fill_dellaloc() callback. + * + * NOTE: caller must ensure that when an error happens, it can not call + * extent_clear_unlock_delalloc() to clear both the bits EXTENT_DO_ACCOUNTING + * and EXTENT_DELALLOC simultaneously, because that causes the reserved metadata + * to be released, which we want to happen only when finishing the ordered + * extent (btrfs_finish_ordered_io()). Also note that the caller of the + * fill_delalloc() callback already does proper cleanup for the first page of + * the range, that is, it invokes the callback writepage_end_io_hook() for the + * range of the first page. + */ +static inline void btrfs_cleanup_ordered_extents(struct inode *inode, + const u64 offset, + const u64 bytes) +{ + return __endio_write_update_ordered(inode, offset + PAGE_SIZE, + bytes - PAGE_SIZE, false); +} + static int btrfs_dirty_inode(struct inode *inode); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS @@ -547,7 +572,7 @@ cont: } if (ret <= 0) { unsigned long clear_flags = EXTENT_DELALLOC | - EXTENT_DEFRAG; + EXTENT_DELALLOC_NEW | EXTENT_DEFRAG; unsigned long page_error_op; clear_flags |= (ret < 0) ? EXTENT_DO_ACCOUNTING : 0; @@ -565,8 +590,10 @@ cont: PAGE_SET_WRITEBACK | page_error_op | PAGE_END_WRITEBACK); - btrfs_free_reserved_data_space_noquota(inode, start, - end - start + 1); + if (ret == 0) + btrfs_free_reserved_data_space_noquota(inode, + start, + end - start + 1); goto free_pages_out; } } @@ -852,6 +879,7 @@ out_free: async_extent->start + async_extent->ram_size - 1, NULL, EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, PAGE_UNLOCK | PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK | @@ -918,10 +946,13 @@ static noinline int cow_file_range(struct inode *inode, u64 num_bytes; unsigned long ram_size; u64 disk_num_bytes; - u64 cur_alloc_size; + u64 cur_alloc_size = 0; u64 blocksize = fs_info->sectorsize; struct btrfs_key ins; struct extent_map *em; + unsigned clear_bits; + unsigned long page_ops; + bool extent_reserved = false; int ret = 0; if (btrfs_is_free_space_inode(BTRFS_I(inode))) { @@ -944,6 +975,7 @@ static noinline int cow_file_range(struct inode *inode, extent_clear_unlock_delalloc(inode, start, end, delalloc_end, NULL, EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | EXTENT_DEFRAG, PAGE_UNLOCK | PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK); @@ -966,14 +998,14 @@ static noinline int cow_file_range(struct inode *inode, start + num_bytes - 1, 0); while (disk_num_bytes > 0) { - unsigned long op; - cur_alloc_size = disk_num_bytes; ret = btrfs_reserve_extent(root, cur_alloc_size, cur_alloc_size, fs_info->sectorsize, 0, alloc_hint, &ins, 1, 1); if (ret < 0) goto out_unlock; + cur_alloc_size = ins.offset; + extent_reserved = true; ram_size = ins.offset; em = create_io_em(inode, start, ins.offset, /* len */ @@ -988,7 +1020,6 @@ static noinline int cow_file_range(struct inode *inode, goto out_reserve; free_extent_map(em); - cur_alloc_size = ins.offset; ret = btrfs_add_ordered_extent(inode, start, ins.objectid, ram_size, cur_alloc_size, 0); if (ret) @@ -998,15 +1029,24 @@ static noinline int cow_file_range(struct inode *inode, BTRFS_DATA_RELOC_TREE_OBJECTID) { ret = btrfs_reloc_clone_csums(inode, start, cur_alloc_size); + /* + * Only drop cache here, and process as normal. + * + * We must not allow extent_clear_unlock_delalloc() + * at out_unlock label to free meta of this ordered + * extent, as its meta should be freed by + * btrfs_finish_ordered_io(). + * + * So we must continue until @start is increased to + * skip current ordered extent. + */ if (ret) - goto out_drop_extent_cache; + btrfs_drop_extent_cache(BTRFS_I(inode), start, + start + ram_size - 1, 0); } btrfs_dec_block_group_reservations(fs_info, ins.objectid); - if (disk_num_bytes < cur_alloc_size) - break; - /* we're not doing compressed IO, don't unlock the first * page (which the caller expects to stay locked), don't * clear any dirty bits and don't set any writeback bits @@ -1014,18 +1054,30 @@ static noinline int cow_file_range(struct inode *inode, * Do set the Private2 bit so we know this page was properly * setup for writepage */ - op = unlock ? PAGE_UNLOCK : 0; - op |= PAGE_SET_PRIVATE2; + page_ops = unlock ? PAGE_UNLOCK : 0; + page_ops |= PAGE_SET_PRIVATE2; extent_clear_unlock_delalloc(inode, start, start + ram_size - 1, delalloc_end, locked_page, EXTENT_LOCKED | EXTENT_DELALLOC, - op); - disk_num_bytes -= cur_alloc_size; + page_ops); + if (disk_num_bytes < cur_alloc_size) + disk_num_bytes = 0; + else + disk_num_bytes -= cur_alloc_size; num_bytes -= cur_alloc_size; alloc_hint = ins.objectid + ins.offset; start += cur_alloc_size; + extent_reserved = false; + + /* + * btrfs_reloc_clone_csums() error, since start is increased + * extent_clear_unlock_delalloc() at out_unlock label won't + * free metadata of current ordered extent, we're OK to exit. + */ + if (ret) + goto out_unlock; } out: return ret; @@ -1036,12 +1088,35 @@ out_reserve: btrfs_dec_block_group_reservations(fs_info, ins.objectid); btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 1); out_unlock: + clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV; + page_ops = PAGE_UNLOCK | PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK | + PAGE_END_WRITEBACK; + /* + * If we reserved an extent for our delalloc range (or a subrange) and + * failed to create the respective ordered extent, then it means that + * when we reserved the extent we decremented the extent's size from + * the data space_info's bytes_may_use counter and incremented the + * space_info's bytes_reserved counter by the same amount. We must make + * sure extent_clear_unlock_delalloc() does not try to decrement again + * the data space_info's bytes_may_use counter, therefore we do not pass + * it the flag EXTENT_CLEAR_DATA_RESV. + */ + if (extent_reserved) { + extent_clear_unlock_delalloc(inode, start, + start + cur_alloc_size, + start + cur_alloc_size, + locked_page, + clear_bits, + page_ops); + start += cur_alloc_size; + if (start >= end) + goto out; + } extent_clear_unlock_delalloc(inode, start, end, delalloc_end, locked_page, - EXTENT_LOCKED | EXTENT_DO_ACCOUNTING | - EXTENT_DELALLOC | EXTENT_DEFRAG, - PAGE_UNLOCK | PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK); + clear_bits | EXTENT_CLEAR_DATA_RESV, + page_ops); goto out; } @@ -1414,15 +1489,14 @@ out_check: BUG_ON(ret); /* -ENOMEM */ if (root->root_key.objectid == - BTRFS_DATA_RELOC_TREE_OBJECTID) { + BTRFS_DATA_RELOC_TREE_OBJECTID) + /* + * Error handled later, as we must prevent + * extent_clear_unlock_delalloc() in error handler + * from freeing metadata of created ordered extent. + */ ret = btrfs_reloc_clone_csums(inode, cur_offset, num_bytes); - if (ret) { - if (!nolock && nocow) - btrfs_end_write_no_snapshoting(root); - goto error; - } - } extent_clear_unlock_delalloc(inode, cur_offset, cur_offset + num_bytes - 1, end, @@ -1434,6 +1508,14 @@ out_check: if (!nolock && nocow) btrfs_end_write_no_snapshoting(root); cur_offset = extent_end; + + /* + * btrfs_reloc_clone_csums() error, now we're OK to call error + * handler, as metadata for created ordered extent will only + * be freed by btrfs_finish_ordered_io(). + */ + if (ret) + goto error; if (cur_offset > end) break; } @@ -1509,6 +1591,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, ret = cow_file_range_async(inode, locked_page, start, end, page_started, nr_written); } + if (ret) + btrfs_cleanup_ordered_extents(inode, start, end - start + 1); return ret; } @@ -1693,6 +1777,14 @@ static void btrfs_set_bit_hook(struct inode *inode, btrfs_add_delalloc_inodes(root, inode); spin_unlock(&BTRFS_I(inode)->lock); } + + if (!(state->state & EXTENT_DELALLOC_NEW) && + (*bits & EXTENT_DELALLOC_NEW)) { + spin_lock(&BTRFS_I(inode)->lock); + BTRFS_I(inode)->new_delalloc_bytes += state->end + 1 - + state->start; + spin_unlock(&BTRFS_I(inode)->lock); + } } /* @@ -1722,7 +1814,7 @@ static void btrfs_clear_bit_hook(struct btrfs_inode *inode, if (*bits & EXTENT_FIRST_DELALLOC) { *bits &= ~EXTENT_FIRST_DELALLOC; - } else if (!(*bits & EXTENT_DO_ACCOUNTING)) { + } else if (!(*bits & EXTENT_CLEAR_META_RESV)) { spin_lock(&inode->lock); inode->outstanding_extents -= num_extents; spin_unlock(&inode->lock); @@ -1733,7 +1825,7 @@ static void btrfs_clear_bit_hook(struct btrfs_inode *inode, * don't need to call dellalloc_release_metadata if there is an * error. */ - if (*bits & EXTENT_DO_ACCOUNTING && + if (*bits & EXTENT_CLEAR_META_RESV && root != fs_info->tree_root) btrfs_delalloc_release_metadata(inode, len); @@ -1741,10 +1833,9 @@ static void btrfs_clear_bit_hook(struct btrfs_inode *inode, if (btrfs_is_testing(fs_info)) return; - if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID - && do_list && !(state->state & EXTENT_NORESERVE) - && (*bits & (EXTENT_DO_ACCOUNTING | - EXTENT_CLEAR_DATA_RESV))) + if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID && + do_list && !(state->state & EXTENT_NORESERVE) && + (*bits & EXTENT_CLEAR_DATA_RESV)) btrfs_free_reserved_data_space_noquota( &inode->vfs_inode, state->start, len); @@ -1759,6 +1850,14 @@ static void btrfs_clear_bit_hook(struct btrfs_inode *inode, btrfs_del_delalloc_inode(root, inode); spin_unlock(&inode->lock); } + + if ((state->state & EXTENT_DELALLOC_NEW) && + (*bits & EXTENT_DELALLOC_NEW)) { + spin_lock(&inode->lock); + ASSERT(inode->new_delalloc_bytes >= len); + inode->new_delalloc_bytes -= len; + spin_unlock(&inode->lock); + } } /* @@ -2791,6 +2890,13 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) u64 logical_len = ordered_extent->len; bool nolock; bool truncated = false; + bool range_locked = false; + bool clear_new_delalloc_bytes = false; + + if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) && + !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags) && + !test_bit(BTRFS_ORDERED_DIRECT, &ordered_extent->flags)) + clear_new_delalloc_bytes = true; nolock = btrfs_is_free_space_inode(BTRFS_I(inode)); @@ -2839,6 +2945,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) goto out; } + range_locked = true; lock_extent_bits(io_tree, ordered_extent->file_offset, ordered_extent->file_offset + ordered_extent->len - 1, &cached_state); @@ -2864,7 +2971,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) if (IS_ERR(trans)) { ret = PTR_ERR(trans); trans = NULL; - goto out_unlock; + goto out; } trans->block_rsv = &fs_info->delalloc_block_rsv; @@ -2896,7 +3003,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) trans->transid); if (ret < 0) { btrfs_abort_transaction(trans, ret); - goto out_unlock; + goto out; } add_pending_csums(trans, inode, &ordered_extent->list); @@ -2905,14 +3012,26 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) ret = btrfs_update_inode_fallback(trans, root, inode); if (ret) { /* -ENOMEM or corruption */ btrfs_abort_transaction(trans, ret); - goto out_unlock; + goto out; } ret = 0; -out_unlock: - unlock_extent_cached(io_tree, ordered_extent->file_offset, - ordered_extent->file_offset + - ordered_extent->len - 1, &cached_state, GFP_NOFS); out: + if (range_locked || clear_new_delalloc_bytes) { + unsigned int clear_bits = 0; + + if (range_locked) + clear_bits |= EXTENT_LOCKED; + if (clear_new_delalloc_bytes) + clear_bits |= EXTENT_DELALLOC_NEW; + clear_extent_bit(&BTRFS_I(inode)->io_tree, + ordered_extent->file_offset, + ordered_extent->file_offset + + ordered_extent->len - 1, + clear_bits, + (clear_bits & EXTENT_LOCKED) ? 1 : 0, + 0, &cached_state, GFP_NOFS); + } + if (root != fs_info->tree_root) btrfs_delalloc_release_metadata(BTRFS_I(inode), ordered_extent->len); @@ -4401,9 +4520,17 @@ search_again: if (extent_type != BTRFS_FILE_EXTENT_INLINE) { item_end += btrfs_file_extent_num_bytes(leaf, fi); + + trace_btrfs_truncate_show_fi_regular( + BTRFS_I(inode), leaf, fi, + found_key.offset); } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { item_end += btrfs_file_extent_inline_len(leaf, path->slots[0], fi); + + trace_btrfs_truncate_show_fi_inline( + BTRFS_I(inode), leaf, fi, path->slots[0], + found_key.offset); } item_end--; } @@ -4603,13 +4730,6 @@ error: btrfs_free_path(path); - if (err == 0) { - /* only inline file may have last_size != new_size */ - if (new_size >= fs_info->sectorsize || - new_size > fs_info->max_inline) - ASSERT(last_size == new_size); - } - if (be_nice && bytes_deleted > SZ_32M) { unsigned long updates = trans->delayed_ref_updates; if (updates) { @@ -6735,7 +6855,6 @@ static noinline int uncompress_inline(struct btrfs_path *path, * * This also copies inline extents directly into the page. */ - struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, struct page *page, size_t pg_offset, u64 start, u64 len, @@ -6835,11 +6954,18 @@ again: found_type == BTRFS_FILE_EXTENT_PREALLOC) { extent_end = extent_start + btrfs_file_extent_num_bytes(leaf, item); + + trace_btrfs_get_extent_show_fi_regular(inode, leaf, item, + extent_start); } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { size_t size; size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); extent_end = ALIGN(extent_start + size, fs_info->sectorsize); + + trace_btrfs_get_extent_show_fi_inline(inode, leaf, item, + path->slots[0], + extent_start); } next: if (start >= extent_end) { @@ -7037,19 +7163,17 @@ struct extent_map *btrfs_get_extent_fiemap(struct btrfs_inode *inode, em = btrfs_get_extent(inode, page, pg_offset, start, len, create); if (IS_ERR(em)) return em; - if (em) { - /* - * if our em maps to - * - a hole or - * - a pre-alloc extent, - * there might actually be delalloc bytes behind it. - */ - if (em->block_start != EXTENT_MAP_HOLE && - !test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) - return em; - else - hole_em = em; - } + /* + * If our em maps to: + * - a hole or + * - a pre-alloc extent, + * there might actually be delalloc bytes behind it. + */ + if (em->block_start != EXTENT_MAP_HOLE && + !test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) + return em; + else + hole_em = em; /* check to see if we've wrapped (len == -1 or similar) */ end = start + len; @@ -8127,17 +8251,26 @@ static void btrfs_endio_direct_read(struct bio *bio) bio_put(bio); } -static void btrfs_endio_direct_write_update_ordered(struct inode *inode, - const u64 offset, - const u64 bytes, - const int uptodate) +static void __endio_write_update_ordered(struct inode *inode, + const u64 offset, const u64 bytes, + const bool uptodate) { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_ordered_extent *ordered = NULL; + struct btrfs_workqueue *wq; + btrfs_work_func_t func; u64 ordered_offset = offset; u64 ordered_bytes = bytes; int ret; + if (btrfs_is_free_space_inode(BTRFS_I(inode))) { + wq = fs_info->endio_freespace_worker; + func = btrfs_freespace_write_helper; + } else { + wq = fs_info->endio_write_workers; + func = btrfs_endio_write_helper; + } + again: ret = btrfs_dec_test_first_ordered_pending(inode, &ordered, &ordered_offset, @@ -8146,9 +8279,8 @@ again: if (!ret) goto out_test; - btrfs_init_work(&ordered->work, btrfs_endio_write_helper, - finish_ordered_fn, NULL, NULL); - btrfs_queue_work(fs_info->endio_write_workers, &ordered->work); + btrfs_init_work(&ordered->work, func, finish_ordered_fn, NULL, NULL); + btrfs_queue_work(wq, &ordered->work); out_test: /* * our bio might span multiple ordered extents. If we haven't @@ -8166,10 +8298,8 @@ static void btrfs_endio_direct_write(struct bio *bio) struct btrfs_dio_private *dip = bio->bi_private; struct bio *dio_bio = dip->dio_bio; - btrfs_endio_direct_write_update_ordered(dip->inode, - dip->logical_offset, - dip->bytes, - !bio->bi_error); + __endio_write_update_ordered(dip->inode, dip->logical_offset, + dip->bytes, !bio->bi_error); kfree(dip); @@ -8530,10 +8660,10 @@ free_ordered: io_bio = NULL; } else { if (write) - btrfs_endio_direct_write_update_ordered(inode, + __endio_write_update_ordered(inode, file_offset, dio_bio->bi_iter.bi_size, - 0); + false); else unlock_extent(&BTRFS_I(inode)->io_tree, file_offset, file_offset + dio_bio->bi_iter.bi_size - 1); @@ -8668,11 +8798,11 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) */ if (dio_data.unsubmitted_oe_range_start < dio_data.unsubmitted_oe_range_end) - btrfs_endio_direct_write_update_ordered(inode, + __endio_write_update_ordered(inode, dio_data.unsubmitted_oe_range_start, dio_data.unsubmitted_oe_range_end - dio_data.unsubmitted_oe_range_start, - 0); + false); } else if (ret >= 0 && (size_t)ret < count) btrfs_delalloc_release_space(inode, offset, count - (size_t)ret); @@ -8819,6 +8949,7 @@ again: if (!inode_evicting) clear_extent_bit(tree, start, end, EXTENT_DIRTY | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | EXTENT_LOCKED | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1, 0, &cached_state, GFP_NOFS); @@ -8876,8 +9007,8 @@ again: if (!inode_evicting) { clear_extent_bit(tree, page_start, page_end, EXTENT_LOCKED | EXTENT_DIRTY | - EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | - EXTENT_DEFRAG, 1, 1, + EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1, 1, &cached_state, GFP_NOFS); __btrfs_releasepage(page, GFP_NOFS); @@ -9248,6 +9379,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) ei->last_sub_trans = 0; ei->logged_trans = 0; ei->delalloc_bytes = 0; + ei->new_delalloc_bytes = 0; ei->defrag_bytes = 0; ei->disk_i_size = 0; ei->flags = 0; @@ -9313,6 +9445,7 @@ void btrfs_destroy_inode(struct inode *inode) WARN_ON(BTRFS_I(inode)->outstanding_extents); WARN_ON(BTRFS_I(inode)->reserved_extents); WARN_ON(BTRFS_I(inode)->delalloc_bytes); + WARN_ON(BTRFS_I(inode)->new_delalloc_bytes); WARN_ON(BTRFS_I(inode)->csum_bytes); WARN_ON(BTRFS_I(inode)->defrag_bytes); @@ -9436,7 +9569,7 @@ static int btrfs_getattr(const struct path *path, struct kstat *stat, stat->dev = BTRFS_I(inode)->root->anon_dev; spin_lock(&BTRFS_I(inode)->lock); - delalloc_bytes = BTRFS_I(inode)->delalloc_bytes; + delalloc_bytes = BTRFS_I(inode)->new_delalloc_bytes; spin_unlock(&BTRFS_I(inode)->lock); stat->blocks = (ALIGN(inode_get_bytes(inode), blocksize) + ALIGN(delalloc_bytes, blocksize)) >> 9; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 922a66fce401..e176375f374f 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1504,7 +1504,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, if (ret) return ret; - if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { + if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { mnt_drop_write_file(file); return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; } @@ -1619,7 +1619,7 @@ out_free: kfree(vol_args); out: mutex_unlock(&fs_info->volume_mutex); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); mnt_drop_write_file(file); return ret; } @@ -2661,7 +2661,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) + if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; mutex_lock(&fs_info->volume_mutex); @@ -2680,7 +2680,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) kfree(vol_args); out: mutex_unlock(&fs_info->volume_mutex); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); return ret; } @@ -2708,7 +2708,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) return -EOPNOTSUPP; - if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { + if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; goto out; } @@ -2721,7 +2721,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) ret = btrfs_rm_device(fs_info, vol_args->name, 0); } mutex_unlock(&fs_info->volume_mutex); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); if (!ret) { if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) @@ -2752,7 +2752,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) if (ret) return ret; - if (atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { + if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; goto out_drop_write; } @@ -2772,7 +2772,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) btrfs_info(fs_info, "disk deleted %s", vol_args->name); kfree(vol_args); out: - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); out_drop_write: mnt_drop_write_file(file); @@ -4439,13 +4439,11 @@ static long btrfs_ioctl_dev_replace(struct btrfs_fs_info *fs_info, ret = -EROFS; goto out; } - if (atomic_xchg( - &fs_info->mutually_exclusive_operation_running, 1)) { + if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; } else { ret = btrfs_dev_replace_by_ioctl(fs_info, p); - atomic_set( - &fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); } break; case BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS: @@ -4640,7 +4638,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) return ret; again: - if (!atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { + if (!test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->balance_mutex); need_unlock = true; @@ -4686,7 +4684,7 @@ again: } locked: - BUG_ON(!atomic_read(&fs_info->mutually_exclusive_operation_running)); + BUG_ON(!test_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)); if (arg) { bargs = memdup_user(arg, sizeof(*bargs)); @@ -4742,11 +4740,10 @@ locked: do_balance: /* - * Ownership of bctl and mutually_exclusive_operation_running + * Ownership of bctl and filesystem flag BTRFS_FS_EXCL_OP * goes to to btrfs_balance. bctl is freed in __cancel_balance, * or, if restriper was paused all the way until unmount, in - * free_fs_info. mutually_exclusive_operation_running is - * cleared in __cancel_balance. + * free_fs_info. The flag is cleared in __cancel_balance. */ need_unlock = false; @@ -4766,7 +4763,7 @@ out_unlock: mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); if (need_unlock) - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); out: mnt_drop_write_file(file); return ret; diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 9a46878ba60f..7b40e2e7292a 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -212,7 +212,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, set_bit(BTRFS_ORDERED_DIRECT, &entry->flags); /* one ref for the tree */ - atomic_set(&entry->refs, 1); + refcount_set(&entry->refs, 1); init_waitqueue_head(&entry->wait); INIT_LIST_HEAD(&entry->list); INIT_LIST_HEAD(&entry->root_extent_list); @@ -358,7 +358,7 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode, out: if (!ret && cached && entry) { *cached = entry; - atomic_inc(&entry->refs); + refcount_inc(&entry->refs); } spin_unlock_irqrestore(&tree->lock, flags); return ret == 0; @@ -425,7 +425,7 @@ have_entry: out: if (!ret && cached && entry) { *cached = entry; - atomic_inc(&entry->refs); + refcount_inc(&entry->refs); } spin_unlock_irqrestore(&tree->lock, flags); return ret == 0; @@ -456,7 +456,7 @@ void btrfs_get_logged_extents(struct btrfs_inode *inode, if (test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags)) continue; list_add(&ordered->log_list, logged_list); - atomic_inc(&ordered->refs); + refcount_inc(&ordered->refs); } spin_unlock_irq(&tree->lock); } @@ -565,7 +565,7 @@ void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry) trace_btrfs_ordered_extent_put(entry->inode, entry); - if (atomic_dec_and_test(&entry->refs)) { + if (refcount_dec_and_test(&entry->refs)) { ASSERT(list_empty(&entry->log_list)); ASSERT(list_empty(&entry->trans_list)); ASSERT(list_empty(&entry->root_extent_list)); @@ -623,7 +623,7 @@ void btrfs_remove_ordered_extent(struct inode *inode, spin_lock(&fs_info->trans_lock); trans = fs_info->running_transaction; if (trans) - atomic_inc(&trans->use_count); + refcount_inc(&trans->use_count); spin_unlock(&fs_info->trans_lock); ASSERT(trans); @@ -690,7 +690,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, list_move_tail(&ordered->root_extent_list, &root->ordered_extents); - atomic_inc(&ordered->refs); + refcount_inc(&ordered->refs); spin_unlock(&root->ordered_extent_lock); btrfs_init_work(&ordered->flush_work, @@ -870,7 +870,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, if (!offset_in_entry(entry, file_offset)) entry = NULL; if (entry) - atomic_inc(&entry->refs); + refcount_inc(&entry->refs); out: spin_unlock_irq(&tree->lock); return entry; @@ -911,7 +911,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range( } out: if (entry) - atomic_inc(&entry->refs); + refcount_inc(&entry->refs); spin_unlock_irq(&tree->lock); return entry; } @@ -948,7 +948,7 @@ btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset) goto out; entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - atomic_inc(&entry->refs); + refcount_inc(&entry->refs); out: spin_unlock_irq(&tree->lock); return entry; diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 195c93b67fe0..e0c1d5b8d859 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -113,7 +113,7 @@ struct btrfs_ordered_extent { int compress_type; /* reference count */ - atomic_t refs; + refcount_t refs; /* the inode we belong to */ struct inode *inode; diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index afbea61d957e..deffbeb74a0b 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -47,50 +47,6 @@ * - check all ioctl parameters */ -/* - * one struct for each qgroup, organized in fs_info->qgroup_tree. - */ -struct btrfs_qgroup { - u64 qgroupid; - - /* - * state - */ - u64 rfer; /* referenced */ - u64 rfer_cmpr; /* referenced compressed */ - u64 excl; /* exclusive */ - u64 excl_cmpr; /* exclusive compressed */ - - /* - * limits - */ - u64 lim_flags; /* which limits are set */ - u64 max_rfer; - u64 max_excl; - u64 rsv_rfer; - u64 rsv_excl; - - /* - * reservation tracking - */ - u64 reserved; - - /* - * lists - */ - struct list_head groups; /* groups this group is member of */ - struct list_head members; /* groups that are members of this group */ - struct list_head dirty; /* dirty groups */ - struct rb_node node; /* tree of qgroups */ - - /* - * temp variables for accounting operations - * Refer to qgroup_shared_accounting() for details. - */ - u64 old_refcnt; - u64 new_refcnt; -}; - static void btrfs_qgroup_update_old_refcnt(struct btrfs_qgroup *qg, u64 seq, int mod) { @@ -1078,6 +1034,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, qgroup->excl += sign * num_bytes; qgroup->excl_cmpr += sign * num_bytes; if (sign > 0) { + trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes); if (qgroup->reserved < num_bytes) report_reserved_underflow(fs_info, qgroup, num_bytes); else @@ -1103,6 +1060,8 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, WARN_ON(sign < 0 && qgroup->excl < num_bytes); qgroup->excl += sign * num_bytes; if (sign > 0) { + trace_qgroup_update_reserve(fs_info, qgroup, + -(s64)num_bytes); if (qgroup->reserved < num_bytes) report_reserved_underflow(fs_info, qgroup, num_bytes); @@ -2058,12 +2017,12 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans, if (!ret) { /* - * Use (u64)-1 as time_seq to do special search, which + * Use SEQ_LAST as time_seq to do special search, which * doesn't lock tree or delayed_refs and search current * root. It's safe inside commit_transaction(). */ ret = btrfs_find_all_roots(trans, fs_info, - record->bytenr, (u64)-1, &new_roots); + record->bytenr, SEQ_LAST, &new_roots); if (ret < 0) goto cleanup; if (qgroup_to_skip) @@ -2370,6 +2329,7 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce) struct btrfs_fs_info *fs_info = root->fs_info; u64 ref_root = root->root_key.objectid; int ret = 0; + int retried = 0; struct ulist_node *unode; struct ulist_iterator uiter; @@ -2378,7 +2338,7 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce) if (num_bytes == 0) return 0; - +retry: spin_lock(&fs_info->qgroup_lock); quota_root = fs_info->quota_root; if (!quota_root) @@ -2405,6 +2365,27 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce) qg = unode_aux_to_qgroup(unode); if (enforce && !qgroup_check_limits(qg, num_bytes)) { + /* + * Commit the tree and retry, since we may have + * deletions which would free up space. + */ + if (!retried && qg->reserved > 0) { + struct btrfs_trans_handle *trans; + + spin_unlock(&fs_info->qgroup_lock); + ret = btrfs_start_delalloc_inodes(root, 0); + if (ret) + return ret; + btrfs_wait_ordered_extents(root, -1, 0, (u64)-1); + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) + return PTR_ERR(trans); + ret = btrfs_commit_transaction(trans); + if (ret) + return ret; + retried++; + goto retry; + } ret = -EDQUOT; goto out; } @@ -2427,6 +2408,7 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce) qg = unode_aux_to_qgroup(unode); + trace_qgroup_update_reserve(fs_info, qg, num_bytes); qg->reserved += num_bytes; } @@ -2472,6 +2454,7 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, qg = unode_aux_to_qgroup(unode); + trace_qgroup_update_reserve(fs_info, qg, -(s64)num_bytes); if (qg->reserved < num_bytes) report_reserved_underflow(fs_info, qg, num_bytes); else @@ -2490,18 +2473,6 @@ out: spin_unlock(&fs_info->qgroup_lock); } -void assert_qgroups_uptodate(struct btrfs_trans_handle *trans) -{ - if (list_empty(&trans->qgroup_ref_list) && !trans->delayed_ref_elem.seq) - return; - btrfs_err(trans->fs_info, - "qgroups not uptodate in trans handle %p: list is%s empty, seq is %#x.%x", - trans, list_empty(&trans->qgroup_ref_list) ? "" : " not", - (u32)(trans->delayed_ref_elem.seq >> 32), - (u32)trans->delayed_ref_elem.seq); - BUG(); -} - /* * returns < 0 on error, 0 when more leafs are to be scanned. * returns 1 when done. @@ -2889,14 +2860,14 @@ static int __btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len, if (ret < 0) goto out; - if (free) { - btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info, - BTRFS_I(inode)->root->objectid, - changeset.bytes_changed); + if (free) trace_op = QGROUP_FREE; - } trace_btrfs_qgroup_release_data(inode, start, len, changeset.bytes_changed, trace_op); + if (free) + btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info, + BTRFS_I(inode)->root->objectid, + changeset.bytes_changed); out: ulist_release(&changeset.range_changed); return ret; @@ -2948,6 +2919,7 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, return 0; BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); + trace_qgroup_meta_reserve(root, (s64)num_bytes); ret = qgroup_reserve(root, num_bytes, enforce); if (ret < 0) return ret; @@ -2967,6 +2939,7 @@ void btrfs_qgroup_free_meta_all(struct btrfs_root *root) reserved = atomic64_xchg(&root->qgroup_meta_rsv, 0); if (reserved == 0) return; + trace_qgroup_meta_reserve(root, -(s64)reserved); btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved); } @@ -2981,6 +2954,7 @@ void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes) BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes); atomic64_sub(num_bytes, &root->qgroup_meta_rsv); + trace_qgroup_meta_reserve(root, -(s64)num_bytes); btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes); } diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 26932a8a1993..fe04d3f295c6 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -62,6 +62,50 @@ struct btrfs_qgroup_extent_record { }; /* + * one struct for each qgroup, organized in fs_info->qgroup_tree. + */ +struct btrfs_qgroup { + u64 qgroupid; + + /* + * state + */ + u64 rfer; /* referenced */ + u64 rfer_cmpr; /* referenced compressed */ + u64 excl; /* exclusive */ + u64 excl_cmpr; /* exclusive compressed */ + + /* + * limits + */ + u64 lim_flags; /* which limits are set */ + u64 max_rfer; + u64 max_excl; + u64 rsv_rfer; + u64 rsv_excl; + + /* + * reservation tracking + */ + u64 reserved; + + /* + * lists + */ + struct list_head groups; /* groups this group is member of */ + struct list_head members; /* groups that are members of this group */ + struct list_head dirty; /* dirty groups */ + struct rb_node node; /* tree of qgroups */ + + /* + * temp variables for accounting operations + * Refer to qgroup_shared_accounting() for details. + */ + u64 old_refcnt; + u64 new_refcnt; +}; + +/* * For qgroup event trace points only */ #define QGROUP_RESERVE (1<<0) @@ -186,17 +230,12 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, struct btrfs_qgroup_inherit *inherit); void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, u64 ref_root, u64 num_bytes); -/* - * TODO: Add proper trace point for it, as btrfs_qgroup_free() is - * called by everywhere, can't provide good trace for delayed ref case. - */ static inline void btrfs_qgroup_free_delayed_ref(struct btrfs_fs_info *fs_info, u64 ref_root, u64 num_bytes) { - btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes); trace_btrfs_qgroup_free_delayed_ref(fs_info, ref_root, num_bytes); + btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes); } -void assert_qgroups_uptodate(struct btrfs_trans_handle *trans); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 1571bf26dc07..d8ea0eb76325 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -149,7 +149,7 @@ struct btrfs_raid_bio { int generic_bio_cnt; - atomic_t refs; + refcount_t refs; atomic_t stripes_pending; @@ -389,7 +389,7 @@ static void __remove_rbio_from_cache(struct btrfs_raid_bio *rbio) if (bio_list_empty(&rbio->bio_list)) { if (!list_empty(&rbio->hash_list)) { list_del_init(&rbio->hash_list); - atomic_dec(&rbio->refs); + refcount_dec(&rbio->refs); BUG_ON(!list_empty(&rbio->plug_list)); } } @@ -480,7 +480,7 @@ static void cache_rbio(struct btrfs_raid_bio *rbio) /* bump our ref if we were not in the list before */ if (!test_and_set_bit(RBIO_CACHE_BIT, &rbio->flags)) - atomic_inc(&rbio->refs); + refcount_inc(&rbio->refs); if (!list_empty(&rbio->stripe_cache)){ list_move(&rbio->stripe_cache, &table->stripe_cache); @@ -689,7 +689,7 @@ static noinline int lock_stripe_add(struct btrfs_raid_bio *rbio) test_bit(RBIO_CACHE_BIT, &cur->flags) && !test_bit(RBIO_RMW_LOCKED_BIT, &cur->flags)) { list_del_init(&cur->hash_list); - atomic_dec(&cur->refs); + refcount_dec(&cur->refs); steal_rbio(cur, rbio); cache_drop = cur; @@ -738,7 +738,7 @@ static noinline int lock_stripe_add(struct btrfs_raid_bio *rbio) } } lockit: - atomic_inc(&rbio->refs); + refcount_inc(&rbio->refs); list_add(&rbio->hash_list, &h->hash_list); out: spin_unlock_irqrestore(&h->lock, flags); @@ -784,7 +784,7 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio) } list_del_init(&rbio->hash_list); - atomic_dec(&rbio->refs); + refcount_dec(&rbio->refs); /* * we use the plug list to hold all the rbios @@ -801,7 +801,7 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio) list_del_init(&rbio->plug_list); list_add(&next->hash_list, &h->hash_list); - atomic_inc(&next->refs); + refcount_inc(&next->refs); spin_unlock(&rbio->bio_list_lock); spin_unlock_irqrestore(&h->lock, flags); @@ -843,8 +843,7 @@ static void __free_raid_bio(struct btrfs_raid_bio *rbio) { int i; - WARN_ON(atomic_read(&rbio->refs) < 0); - if (!atomic_dec_and_test(&rbio->refs)) + if (!refcount_dec_and_test(&rbio->refs)) return; WARN_ON(!list_empty(&rbio->stripe_cache)); @@ -997,7 +996,7 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info, rbio->stripe_npages = stripe_npages; rbio->faila = -1; rbio->failb = -1; - atomic_set(&rbio->refs, 1); + refcount_set(&rbio->refs, 1); atomic_set(&rbio->error, 0); atomic_set(&rbio->stripes_pending, 0); @@ -2118,6 +2117,11 @@ int raid56_parity_recover(struct btrfs_fs_info *fs_info, struct bio *bio, struct btrfs_raid_bio *rbio; int ret; + if (generic_io) { + ASSERT(bbio->mirror_num == mirror_num); + btrfs_io_bio(bio)->mirror_num = mirror_num; + } + rbio = alloc_rbio(fs_info, bbio, stripe_len); if (IS_ERR(rbio)) { if (generic_io) @@ -2194,6 +2198,8 @@ static void read_rebuild_work(struct btrfs_work *work) /* * The following code is used to scrub/replace the parity stripe * + * Caller must have already increased bio_counter for getting @bbio. + * * Note: We need make sure all the pages that add into the scrub/replace * raid bio are correct and not be changed during the scrub/replace. That * is those pages just hold metadata or file data with checksum. @@ -2231,6 +2237,12 @@ raid56_parity_alloc_scrub_rbio(struct btrfs_fs_info *fs_info, struct bio *bio, ASSERT(rbio->stripe_npages == stripe_nsectors); bitmap_copy(rbio->dbitmap, dbitmap, stripe_nsectors); + /* + * We have already increased bio_counter when getting bbio, record it + * so we can free it at rbio_orig_end_io(). + */ + rbio->generic_bio_cnt = 1; + return rbio; } @@ -2673,6 +2685,12 @@ raid56_alloc_missing_rbio(struct btrfs_fs_info *fs_info, struct bio *bio, return NULL; } + /* + * When we get bbio, we have already increased bio_counter, record it + * so we can free it at rbio_orig_end_io() + */ + rbio->generic_bio_cnt = 1; + return rbio; } diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index e88bca87f5d2..a17e775a4a89 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -209,9 +209,9 @@ cleanup: return; } -int btree_readahead_hook(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, int err) +int btree_readahead_hook(struct extent_buffer *eb, int err) { + struct btrfs_fs_info *fs_info = eb->fs_info; int ret = 0; struct reada_extent *re; @@ -235,10 +235,10 @@ start_machine: return ret; } -static struct reada_zone *reada_find_zone(struct btrfs_fs_info *fs_info, - struct btrfs_device *dev, u64 logical, +static struct reada_zone *reada_find_zone(struct btrfs_device *dev, u64 logical, struct btrfs_bio *bbio) { + struct btrfs_fs_info *fs_info = dev->fs_info; int ret; struct reada_zone *zone; struct btrfs_block_group_cache *cache = NULL; @@ -270,6 +270,12 @@ static struct reada_zone *reada_find_zone(struct btrfs_fs_info *fs_info, if (!zone) return NULL; + ret = radix_tree_preload(GFP_KERNEL); + if (ret) { + kfree(zone); + return NULL; + } + zone->start = start; zone->end = end; INIT_LIST_HEAD(&zone->list); @@ -299,6 +305,7 @@ static struct reada_zone *reada_find_zone(struct btrfs_fs_info *fs_info, zone = NULL; } spin_unlock(&fs_info->reada_lock); + radix_tree_preload_end(); return zone; } @@ -313,7 +320,6 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info, struct btrfs_bio *bbio = NULL; struct btrfs_device *dev; struct btrfs_device *prev_dev; - u32 blocksize; u64 length; int real_stripes; int nzones = 0; @@ -334,7 +340,6 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info, if (!re) return NULL; - blocksize = fs_info->nodesize; re->logical = logical; re->top = *top; INIT_LIST_HEAD(&re->extctl); @@ -344,10 +349,10 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info, /* * map block */ - length = blocksize; + length = fs_info->nodesize; ret = btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS, logical, &length, &bbio, 0); - if (ret || !bbio || length < blocksize) + if (ret || !bbio || length < fs_info->nodesize) goto error; if (bbio->num_stripes > BTRFS_MAX_MIRRORS) { @@ -367,7 +372,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info, if (!dev->bdev) continue; - zone = reada_find_zone(fs_info, dev, logical, bbio); + zone = reada_find_zone(dev, logical, bbio); if (!zone) continue; @@ -386,6 +391,10 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info, goto error; } + ret = radix_tree_preload(GFP_KERNEL); + if (ret) + goto error; + /* insert extent in reada_tree + all per-device trees, all or nothing */ btrfs_dev_replace_lock(&fs_info->dev_replace, 0); spin_lock(&fs_info->reada_lock); @@ -395,13 +404,16 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info, re_exist->refcnt++; spin_unlock(&fs_info->reada_lock); btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); + radix_tree_preload_end(); goto error; } if (ret) { spin_unlock(&fs_info->reada_lock); btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); + radix_tree_preload_end(); goto error; } + radix_tree_preload_end(); prev_dev = NULL; dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing( &fs_info->dev_replace); @@ -639,9 +651,9 @@ static int reada_pick_zone(struct btrfs_device *dev) return 1; } -static int reada_start_machine_dev(struct btrfs_fs_info *fs_info, - struct btrfs_device *dev) +static int reada_start_machine_dev(struct btrfs_device *dev) { + struct btrfs_fs_info *fs_info = dev->fs_info; struct reada_extent *re = NULL; int mirror_num = 0; struct extent_buffer *eb = NULL; @@ -754,8 +766,7 @@ static void __reada_start_machine(struct btrfs_fs_info *fs_info) list_for_each_entry(device, &fs_devices->devices, dev_list) { if (atomic_read(&device->reada_in_flight) < MAX_IN_FLIGHT) - enqueued += reada_start_machine_dev(fs_info, - device); + enqueued += reada_start_machine_dev(device); } mutex_unlock(&fs_devices->device_list_mutex); total += enqueued; diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index a08224eab8b4..7d6bc308bf43 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -501,8 +501,9 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans, struct btrfs_root *root) { struct btrfs_root_item *item = &root->root_item; - struct timespec ct = current_fs_time(root->fs_info->sb); + struct timespec ct; + ktime_get_real_ts(&ct); spin_lock(&root->root_item_lock); btrfs_set_root_ctransid(item, trans->transid); btrfs_set_stack_timespec_sec(&item->ctime, ct.tv_sec); diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index b0251eb1239f..c7b45eb2403d 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -64,7 +64,7 @@ struct scrub_ctx; #define SCRUB_MAX_PAGES_PER_BLOCK 16 /* 64k per node/leaf/sector */ struct scrub_recover { - atomic_t refs; + refcount_t refs; struct btrfs_bio *bbio; u64 map_length; }; @@ -112,7 +112,7 @@ struct scrub_block { struct scrub_page *pagev[SCRUB_MAX_PAGES_PER_BLOCK]; int page_count; atomic_t outstanding_pages; - atomic_t refs; /* free mem on transition to zero */ + refcount_t refs; /* free mem on transition to zero */ struct scrub_ctx *sctx; struct scrub_parity *sparity; struct { @@ -140,9 +140,9 @@ struct scrub_parity { int nsectors; - int stripe_len; + u64 stripe_len; - atomic_t refs; + refcount_t refs; struct list_head spages; @@ -202,7 +202,7 @@ struct scrub_ctx { * doesn't free the scrub context before or while the workers are * doing the wakeup() call. */ - atomic_t refs; + refcount_t refs; }; struct scrub_fixup_nodatasum { @@ -240,6 +240,13 @@ struct scrub_warning { struct btrfs_device *dev; }; +struct full_stripe_lock { + struct rb_node node; + u64 logical; + u64 refs; + struct mutex mutex; +}; + static void scrub_pending_bio_inc(struct scrub_ctx *sctx); static void scrub_pending_bio_dec(struct scrub_ctx *sctx); static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx); @@ -305,7 +312,7 @@ static void scrub_put_ctx(struct scrub_ctx *sctx); static void scrub_pending_bio_inc(struct scrub_ctx *sctx) { - atomic_inc(&sctx->refs); + refcount_inc(&sctx->refs); atomic_inc(&sctx->bios_in_flight); } @@ -349,6 +356,222 @@ static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info) } /* + * Insert new full stripe lock into full stripe locks tree + * + * Return pointer to existing or newly inserted full_stripe_lock structure if + * everything works well. + * Return ERR_PTR(-ENOMEM) if we failed to allocate memory + * + * NOTE: caller must hold full_stripe_locks_root->lock before calling this + * function + */ +static struct full_stripe_lock *insert_full_stripe_lock( + struct btrfs_full_stripe_locks_tree *locks_root, + u64 fstripe_logical) +{ + struct rb_node **p; + struct rb_node *parent = NULL; + struct full_stripe_lock *entry; + struct full_stripe_lock *ret; + + WARN_ON(!mutex_is_locked(&locks_root->lock)); + + p = &locks_root->root.rb_node; + while (*p) { + parent = *p; + entry = rb_entry(parent, struct full_stripe_lock, node); + if (fstripe_logical < entry->logical) { + p = &(*p)->rb_left; + } else if (fstripe_logical > entry->logical) { + p = &(*p)->rb_right; + } else { + entry->refs++; + return entry; + } + } + + /* Insert new lock */ + ret = kmalloc(sizeof(*ret), GFP_KERNEL); + if (!ret) + return ERR_PTR(-ENOMEM); + ret->logical = fstripe_logical; + ret->refs = 1; + mutex_init(&ret->mutex); + + rb_link_node(&ret->node, parent, p); + rb_insert_color(&ret->node, &locks_root->root); + return ret; +} + +/* + * Search for a full stripe lock of a block group + * + * Return pointer to existing full stripe lock if found + * Return NULL if not found + */ +static struct full_stripe_lock *search_full_stripe_lock( + struct btrfs_full_stripe_locks_tree *locks_root, + u64 fstripe_logical) +{ + struct rb_node *node; + struct full_stripe_lock *entry; + + WARN_ON(!mutex_is_locked(&locks_root->lock)); + + node = locks_root->root.rb_node; + while (node) { + entry = rb_entry(node, struct full_stripe_lock, node); + if (fstripe_logical < entry->logical) + node = node->rb_left; + else if (fstripe_logical > entry->logical) + node = node->rb_right; + else + return entry; + } + return NULL; +} + +/* + * Helper to get full stripe logical from a normal bytenr. + * + * Caller must ensure @cache is a RAID56 block group. + */ +static u64 get_full_stripe_logical(struct btrfs_block_group_cache *cache, + u64 bytenr) +{ + u64 ret; + + /* + * Due to chunk item size limit, full stripe length should not be + * larger than U32_MAX. Just a sanity check here. + */ + WARN_ON_ONCE(cache->full_stripe_len >= U32_MAX); + + /* + * round_down() can only handle power of 2, while RAID56 full + * stripe length can be 64KiB * n, so we need to manually round down. + */ + ret = div64_u64(bytenr - cache->key.objectid, cache->full_stripe_len) * + cache->full_stripe_len + cache->key.objectid; + return ret; +} + +/* + * Lock a full stripe to avoid concurrency of recovery and read + * + * It's only used for profiles with parities (RAID5/6), for other profiles it + * does nothing. + * + * Return 0 if we locked full stripe covering @bytenr, with a mutex held. + * So caller must call unlock_full_stripe() at the same context. + * + * Return <0 if encounters error. + */ +static int lock_full_stripe(struct btrfs_fs_info *fs_info, u64 bytenr, + bool *locked_ret) +{ + struct btrfs_block_group_cache *bg_cache; + struct btrfs_full_stripe_locks_tree *locks_root; + struct full_stripe_lock *existing; + u64 fstripe_start; + int ret = 0; + + *locked_ret = false; + bg_cache = btrfs_lookup_block_group(fs_info, bytenr); + if (!bg_cache) { + ASSERT(0); + return -ENOENT; + } + + /* Profiles not based on parity don't need full stripe lock */ + if (!(bg_cache->flags & BTRFS_BLOCK_GROUP_RAID56_MASK)) + goto out; + locks_root = &bg_cache->full_stripe_locks_root; + + fstripe_start = get_full_stripe_logical(bg_cache, bytenr); + + /* Now insert the full stripe lock */ + mutex_lock(&locks_root->lock); + existing = insert_full_stripe_lock(locks_root, fstripe_start); + mutex_unlock(&locks_root->lock); + if (IS_ERR(existing)) { + ret = PTR_ERR(existing); + goto out; + } + mutex_lock(&existing->mutex); + *locked_ret = true; +out: + btrfs_put_block_group(bg_cache); + return ret; +} + +/* + * Unlock a full stripe. + * + * NOTE: Caller must ensure it's the same context calling corresponding + * lock_full_stripe(). + * + * Return 0 if we unlock full stripe without problem. + * Return <0 for error + */ +static int unlock_full_stripe(struct btrfs_fs_info *fs_info, u64 bytenr, + bool locked) +{ + struct btrfs_block_group_cache *bg_cache; + struct btrfs_full_stripe_locks_tree *locks_root; + struct full_stripe_lock *fstripe_lock; + u64 fstripe_start; + bool freeit = false; + int ret = 0; + + /* If we didn't acquire full stripe lock, no need to continue */ + if (!locked) + return 0; + + bg_cache = btrfs_lookup_block_group(fs_info, bytenr); + if (!bg_cache) { + ASSERT(0); + return -ENOENT; + } + if (!(bg_cache->flags & BTRFS_BLOCK_GROUP_RAID56_MASK)) + goto out; + + locks_root = &bg_cache->full_stripe_locks_root; + fstripe_start = get_full_stripe_logical(bg_cache, bytenr); + + mutex_lock(&locks_root->lock); + fstripe_lock = search_full_stripe_lock(locks_root, fstripe_start); + /* Unpaired unlock_full_stripe() detected */ + if (!fstripe_lock) { + WARN_ON(1); + ret = -ENOENT; + mutex_unlock(&locks_root->lock); + goto out; + } + + if (fstripe_lock->refs == 0) { + WARN_ON(1); + btrfs_warn(fs_info, "full stripe lock at %llu refcount underflow", + fstripe_lock->logical); + } else { + fstripe_lock->refs--; + } + + if (fstripe_lock->refs == 0) { + rb_erase(&fstripe_lock->node, &locks_root->root); + freeit = true; + } + mutex_unlock(&locks_root->lock); + + mutex_unlock(&fstripe_lock->mutex); + if (freeit) + kfree(fstripe_lock); +out: + btrfs_put_block_group(bg_cache); + return ret; +} + +/* * used for workers that require transaction commits (i.e., for the * NOCOW case) */ @@ -356,7 +579,7 @@ static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx) { struct btrfs_fs_info *fs_info = sctx->fs_info; - atomic_inc(&sctx->refs); + refcount_inc(&sctx->refs); /* * increment scrubs_running to prevent cancel requests from * completing as long as a worker is running. we must also @@ -447,7 +670,7 @@ static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx) static void scrub_put_ctx(struct scrub_ctx *sctx) { - if (atomic_dec_and_test(&sctx->refs)) + if (refcount_dec_and_test(&sctx->refs)) scrub_free_ctx(sctx); } @@ -462,7 +685,7 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace) sctx = kzalloc(sizeof(*sctx), GFP_KERNEL); if (!sctx) goto nomem; - atomic_set(&sctx->refs, 1); + refcount_set(&sctx->refs, 1); sctx->is_dev_replace = is_dev_replace; sctx->pages_per_rd_bio = SCRUB_PAGES_PER_RD_BIO; sctx->curr = -1; @@ -857,12 +1080,14 @@ out: static inline void scrub_get_recover(struct scrub_recover *recover) { - atomic_inc(&recover->refs); + refcount_inc(&recover->refs); } -static inline void scrub_put_recover(struct scrub_recover *recover) +static inline void scrub_put_recover(struct btrfs_fs_info *fs_info, + struct scrub_recover *recover) { - if (atomic_dec_and_test(&recover->refs)) { + if (refcount_dec_and_test(&recover->refs)) { + btrfs_bio_counter_dec(fs_info); btrfs_put_bbio(recover->bbio); kfree(recover); } @@ -892,6 +1117,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) int mirror_index; int page_num; int success; + bool full_stripe_locked; static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); @@ -917,6 +1143,24 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) have_csum = sblock_to_check->pagev[0]->have_csum; dev = sblock_to_check->pagev[0]->dev; + /* + * For RAID5/6, race can happen for a different device scrub thread. + * For data corruption, Parity and Data threads will both try + * to recovery the data. + * Race can lead to doubly added csum error, or even unrecoverable + * error. + */ + ret = lock_full_stripe(fs_info, logical, &full_stripe_locked); + if (ret < 0) { + spin_lock(&sctx->stat_lock); + if (ret == -ENOMEM) + sctx->stat.malloc_errors++; + sctx->stat.read_errors++; + sctx->stat.uncorrectable_errors++; + spin_unlock(&sctx->stat_lock); + return ret; + } + if (sctx->is_dev_replace && !is_metadata && !have_csum) { sblocks_for_recheck = NULL; goto nodatasum_case; @@ -1241,7 +1485,7 @@ out: sblock->pagev[page_index]->sblock = NULL; recover = sblock->pagev[page_index]->recover; if (recover) { - scrub_put_recover(recover); + scrub_put_recover(fs_info, recover); sblock->pagev[page_index]->recover = NULL; } @@ -1251,6 +1495,9 @@ out: kfree(sblocks_for_recheck); } + ret = unlock_full_stripe(fs_info, logical, full_stripe_locked); + if (ret < 0) + return ret; return 0; } @@ -1330,20 +1577,23 @@ static int scrub_setup_recheck_block(struct scrub_block *original_sblock, * with a length of PAGE_SIZE, each returned stripe * represents one mirror */ + btrfs_bio_counter_inc_blocked(fs_info); ret = btrfs_map_sblock(fs_info, BTRFS_MAP_GET_READ_MIRRORS, - logical, &mapped_length, &bbio, 0, 1); + logical, &mapped_length, &bbio); if (ret || !bbio || mapped_length < sublen) { btrfs_put_bbio(bbio); + btrfs_bio_counter_dec(fs_info); return -EIO; } recover = kzalloc(sizeof(struct scrub_recover), GFP_NOFS); if (!recover) { btrfs_put_bbio(bbio); + btrfs_bio_counter_dec(fs_info); return -ENOMEM; } - atomic_set(&recover->refs, 1); + refcount_set(&recover->refs, 1); recover->bbio = bbio; recover->map_length = mapped_length; @@ -1365,7 +1615,7 @@ leave_nomem: spin_lock(&sctx->stat_lock); sctx->stat.malloc_errors++; spin_unlock(&sctx->stat_lock); - scrub_put_recover(recover); + scrub_put_recover(fs_info, recover); return -ENOMEM; } scrub_page_get(page); @@ -1407,7 +1657,7 @@ leave_nomem: scrub_get_recover(recover); page->recover = recover; } - scrub_put_recover(recover); + scrub_put_recover(fs_info, recover); length -= sublen; logical += sublen; page_index++; @@ -1497,14 +1747,18 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, bio_add_page(bio, page->page, PAGE_SIZE, 0); if (!retry_failed_mirror && scrub_is_page_on_raid56(page)) { - if (scrub_submit_raid56_bio_wait(fs_info, bio, page)) + if (scrub_submit_raid56_bio_wait(fs_info, bio, page)) { + page->io_error = 1; sblock->no_io_error_seen = 0; + } } else { bio->bi_iter.bi_sector = page->physical >> 9; bio_set_op_attrs(bio, REQ_OP_READ, 0); - if (btrfsic_submit_bio_wait(bio)) + if (btrfsic_submit_bio_wait(bio)) { + page->io_error = 1; sblock->no_io_error_seen = 0; + } } bio_put(bio); @@ -1634,7 +1888,7 @@ static int scrub_write_page_to_dev_replace(struct scrub_block *sblock, if (spage->io_error) { void *mapped_buffer = kmap_atomic(spage->page); - memset(mapped_buffer, 0, PAGE_SIZE); + clear_page(mapped_buffer); flush_dcache_page(spage->page); kunmap_atomic(mapped_buffer); } @@ -1998,12 +2252,12 @@ static int scrub_checksum_super(struct scrub_block *sblock) static void scrub_block_get(struct scrub_block *sblock) { - atomic_inc(&sblock->refs); + refcount_inc(&sblock->refs); } static void scrub_block_put(struct scrub_block *sblock) { - if (atomic_dec_and_test(&sblock->refs)) { + if (refcount_dec_and_test(&sblock->refs)) { int i; if (sblock->sparity) @@ -2187,8 +2441,9 @@ static void scrub_missing_raid56_pages(struct scrub_block *sblock) int ret; int i; + btrfs_bio_counter_inc_blocked(fs_info); ret = btrfs_map_sblock(fs_info, BTRFS_MAP_GET_READ_MIRRORS, logical, - &length, &bbio, 0, 1); + &length, &bbio); if (ret || !bbio || !bbio->raid_map) goto bbio_out; @@ -2231,6 +2486,7 @@ static void scrub_missing_raid56_pages(struct scrub_block *sblock) rbio_out: bio_put(bio); bbio_out: + btrfs_bio_counter_dec(fs_info); btrfs_put_bbio(bbio); spin_lock(&sctx->stat_lock); sctx->stat.malloc_errors++; @@ -2255,7 +2511,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, /* one ref inside this function, plus one for each page added to * a bio later on */ - atomic_set(&sblock->refs, 1); + refcount_set(&sblock->refs, 1); sblock->sctx = sctx; sblock->no_io_error_seen = 1; @@ -2385,7 +2641,7 @@ static inline void __scrub_mark_bitmap(struct scrub_parity *sparity, unsigned long *bitmap, u64 start, u64 len) { - u32 offset; + u64 offset; int nsectors; int sectorsize = sparity->sctx->fs_info->sectorsize; @@ -2395,8 +2651,8 @@ static inline void __scrub_mark_bitmap(struct scrub_parity *sparity, } start -= sparity->logic_start; - start = div_u64_rem(start, sparity->stripe_len, &offset); - offset /= sectorsize; + start = div64_u64_rem(start, sparity->stripe_len, &offset); + offset = div_u64(offset, sectorsize); nsectors = (int)len / sectorsize; if (offset + nsectors <= sparity->nsectors) { @@ -2555,7 +2811,7 @@ static int scrub_pages_for_parity(struct scrub_parity *sparity, /* one ref inside this function, plus one for each page added to * a bio later on */ - atomic_set(&sblock->refs, 1); + refcount_set(&sblock->refs, 1); sblock->sctx = sctx; sblock->no_io_error_seen = 1; sblock->sparity = sparity; @@ -2694,7 +2950,7 @@ static int get_raid56_logic_offset(u64 physical, int num, for (i = 0; i < nr_data_stripes(map); i++) { *offset = last_offset + i * map->stripe_len; - stripe_nr = div_u64(*offset, map->stripe_len); + stripe_nr = div64_u64(*offset, map->stripe_len); stripe_nr = div_u64(stripe_nr, nr_data_stripes(map)); /* Work out the disk rotation on this stripe-set */ @@ -2765,7 +3021,6 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) struct btrfs_fs_info *fs_info = sctx->fs_info; struct bio *bio; struct btrfs_raid_bio *rbio; - struct scrub_page *spage; struct btrfs_bio *bbio = NULL; u64 length; int ret; @@ -2775,8 +3030,10 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) goto out; length = sparity->logic_end - sparity->logic_start; + + btrfs_bio_counter_inc_blocked(fs_info); ret = btrfs_map_sblock(fs_info, BTRFS_MAP_WRITE, sparity->logic_start, - &length, &bbio, 0, 1); + &length, &bbio); if (ret || !bbio || !bbio->raid_map) goto bbio_out; @@ -2795,9 +3052,6 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) if (!rbio) goto rbio_out; - list_for_each_entry(spage, &sparity->spages, list) - raid56_add_scrub_pages(rbio, spage->page, spage->logical); - scrub_pending_bio_inc(sctx); raid56_parity_submit_scrub_rbio(rbio); return; @@ -2805,6 +3059,7 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) rbio_out: bio_put(bio); bbio_out: + btrfs_bio_counter_dec(fs_info); btrfs_put_bbio(bbio); bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap, sparity->nsectors); @@ -2822,12 +3077,12 @@ static inline int scrub_calc_parity_bitmap_len(int nsectors) static void scrub_parity_get(struct scrub_parity *sparity) { - atomic_inc(&sparity->refs); + refcount_inc(&sparity->refs); } static void scrub_parity_put(struct scrub_parity *sparity) { - if (!atomic_dec_and_test(&sparity->refs)) + if (!refcount_dec_and_test(&sparity->refs)) return; scrub_parity_check_and_repair(sparity); @@ -2879,7 +3134,7 @@ static noinline_for_stack int scrub_raid56_parity(struct scrub_ctx *sctx, sparity->scrub_dev = sdev; sparity->logic_start = logic_start; sparity->logic_end = logic_end; - atomic_set(&sparity->refs, 1); + refcount_set(&sparity->refs, 1); INIT_LIST_HEAD(&sparity->spages); sparity->dbitmap = sparity->bitmap; sparity->ebitmap = (void *)sparity->bitmap + bitmap_len; @@ -3098,7 +3353,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, physical = map->stripes[num].physical; offset = 0; - nstripes = div_u64(length, map->stripe_len); + nstripes = div64_u64(length, map->stripe_len); if (map->type & BTRFS_BLOCK_GROUP_RAID0) { offset = map->stripe_len * num; increment = map->stripe_len * map->num_stripes; diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 3f645cd67b54..fc496a6f842a 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -5184,13 +5184,19 @@ static int is_extent_unchanged(struct send_ctx *sctx, while (key.offset < ekey->offset + left_len) { ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); right_type = btrfs_file_extent_type(eb, ei); - if (right_type != BTRFS_FILE_EXTENT_REG) { + if (right_type != BTRFS_FILE_EXTENT_REG && + right_type != BTRFS_FILE_EXTENT_INLINE) { ret = 0; goto out; } right_disknr = btrfs_file_extent_disk_bytenr(eb, ei); - right_len = btrfs_file_extent_num_bytes(eb, ei); + if (right_type == BTRFS_FILE_EXTENT_INLINE) { + right_len = btrfs_file_extent_inline_len(eb, slot, ei); + right_len = PAGE_ALIGN(right_len); + } else { + right_len = btrfs_file_extent_num_bytes(eb, ei); + } right_offset = btrfs_file_extent_offset(eb, ei); right_gen = btrfs_file_extent_generation(eb, ei); @@ -5204,6 +5210,19 @@ static int is_extent_unchanged(struct send_ctx *sctx, goto out; } + /* + * We just wanted to see if when we have an inline extent, what + * follows it is a regular extent (wanted to check the above + * condition for inline extents too). This should normally not + * happen but it's possible for example when we have an inline + * compressed extent representing data with a size matching + * the page size (currently the same as sector size). + */ + if (right_type == BTRFS_FILE_EXTENT_INLINE) { + ret = 0; + goto out; + } + left_offset_fixed = left_offset; if (key.offset < ekey->offset) { /* Fix the right offset for 2a and 7. */ diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 72a053c9a7f0..4f1cdd5058f1 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1795,8 +1795,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) } if (fs_info->fs_devices->missing_devices > - fs_info->num_tolerated_disk_barrier_failures && - !(*flags & MS_RDONLY)) { + fs_info->num_tolerated_disk_barrier_failures) { btrfs_warn(fs_info, "too many missing devices, writeable remount is not allowed"); ret = -EACCES; diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c index ea272432c930..b18ab8f327a5 100644 --- a/fs/btrfs/tests/btrfs-tests.c +++ b/fs/btrfs/tests/btrfs-tests.c @@ -237,7 +237,6 @@ void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans) { memset(trans, 0, sizeof(*trans)); trans->transid = 1; - INIT_LIST_HEAD(&trans->qgroup_ref_list); trans->type = __TRANS_DUMMY; } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 61b807de3e16..2168654c90a1 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -60,8 +60,8 @@ static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = { void btrfs_put_transaction(struct btrfs_transaction *transaction) { - WARN_ON(atomic_read(&transaction->use_count) == 0); - if (atomic_dec_and_test(&transaction->use_count)) { + WARN_ON(refcount_read(&transaction->use_count) == 0); + if (refcount_dec_and_test(&transaction->use_count)) { BUG_ON(!list_empty(&transaction->list)); WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root)); if (transaction->delayed_refs.pending_csums) @@ -207,7 +207,7 @@ loop: spin_unlock(&fs_info->trans_lock); return -EBUSY; } - atomic_inc(&cur_trans->use_count); + refcount_inc(&cur_trans->use_count); atomic_inc(&cur_trans->num_writers); extwriter_counter_inc(cur_trans, type); spin_unlock(&fs_info->trans_lock); @@ -257,7 +257,7 @@ loop: * One for this trans handle, one so it will live on until we * commit the transaction. */ - atomic_set(&cur_trans->use_count, 2); + refcount_set(&cur_trans->use_count, 2); atomic_set(&cur_trans->pending_ordered, 0); cur_trans->flags = 0; cur_trans->start_time = get_seconds(); @@ -432,7 +432,7 @@ static void wait_current_trans(struct btrfs_fs_info *fs_info) spin_lock(&fs_info->trans_lock); cur_trans = fs_info->running_transaction; if (cur_trans && is_transaction_blocked(cur_trans)) { - atomic_inc(&cur_trans->use_count); + refcount_inc(&cur_trans->use_count); spin_unlock(&fs_info->trans_lock); wait_event(fs_info->transaction_wait, @@ -572,7 +572,6 @@ again: h->type = type; h->can_flush_pending_bgs = true; - INIT_LIST_HEAD(&h->qgroup_ref_list); INIT_LIST_HEAD(&h->new_bgs); smp_mb(); @@ -744,7 +743,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid) list_for_each_entry(t, &fs_info->trans_list, list) { if (t->transid == transid) { cur_trans = t; - atomic_inc(&cur_trans->use_count); + refcount_inc(&cur_trans->use_count); ret = 0; break; } @@ -773,7 +772,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid) if (t->state == TRANS_STATE_COMPLETED) break; cur_trans = t; - atomic_inc(&cur_trans->use_count); + refcount_inc(&cur_trans->use_count); break; } } @@ -917,7 +916,6 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, wake_up_process(info->transaction_kthread); err = -EIO; } - assert_qgroups_uptodate(trans); kmem_cache_free(btrfs_trans_handle_cachep, trans); if (must_run_delayed_refs) { @@ -1839,7 +1837,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, /* take transaction reference */ cur_trans = trans->transaction; - atomic_inc(&cur_trans->use_count); + refcount_inc(&cur_trans->use_count); btrfs_end_transaction(trans); @@ -2015,7 +2013,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) spin_lock(&fs_info->trans_lock); if (cur_trans->state >= TRANS_STATE_COMMIT_START) { spin_unlock(&fs_info->trans_lock); - atomic_inc(&cur_trans->use_count); + refcount_inc(&cur_trans->use_count); ret = btrfs_end_transaction(trans); wait_for_commit(cur_trans); @@ -2035,7 +2033,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) prev_trans = list_entry(cur_trans->list.prev, struct btrfs_transaction, list); if (prev_trans->state != TRANS_STATE_COMPLETED) { - atomic_inc(&prev_trans->use_count); + refcount_inc(&prev_trans->use_count); spin_unlock(&fs_info->trans_lock); wait_for_commit(prev_trans); @@ -2130,13 +2128,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) goto scrub_continue; } - /* Reocrd old roots for later qgroup accounting */ - ret = btrfs_qgroup_prepare_account_extents(trans, fs_info); - if (ret) { - mutex_unlock(&fs_info->reloc_mutex); - goto scrub_continue; - } - /* * make sure none of the code above managed to slip in a * delayed item @@ -2179,6 +2170,24 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) btrfs_free_log_root_tree(trans, fs_info); /* + * commit_fs_roots() can call btrfs_save_ino_cache(), which generates + * new delayed refs. Must handle them or qgroup can be wrong. + */ + ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1); + if (ret) { + mutex_unlock(&fs_info->tree_log_mutex); + mutex_unlock(&fs_info->reloc_mutex); + goto scrub_continue; + } + + ret = btrfs_qgroup_prepare_account_extents(trans, fs_info); + if (ret) { + mutex_unlock(&fs_info->tree_log_mutex); + mutex_unlock(&fs_info->reloc_mutex); + goto scrub_continue; + } + + /* * Since fs roots are all committed, we can get a quite accurate * new_roots. So let's do quota accounting. */ @@ -2223,7 +2232,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) switch_commit_roots(cur_trans, fs_info); - assert_qgroups_uptodate(trans); ASSERT(list_empty(&cur_trans->dirty_bgs)); ASSERT(list_empty(&cur_trans->io_bgs)); update_super_roots(fs_info); diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 5dfb5590fff6..c55e44560103 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -18,6 +18,8 @@ #ifndef __BTRFS_TRANSACTION__ #define __BTRFS_TRANSACTION__ + +#include <linux/refcount.h> #include "btrfs_inode.h" #include "delayed-ref.h" #include "ctree.h" @@ -49,7 +51,7 @@ struct btrfs_transaction { * transaction can end */ atomic_t num_writers; - atomic_t use_count; + refcount_t use_count; atomic_t pending_ordered; unsigned long flags; @@ -125,8 +127,6 @@ struct btrfs_trans_handle { unsigned int type; struct btrfs_root *root; struct btrfs_fs_info *fs_info; - struct seq_list delayed_ref_elem; - struct list_head qgroup_ref_list; struct list_head new_bgs; }; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a59674c3e69e..ccfe9fe7754a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4196,7 +4196,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, if (em->generation <= test_gen) continue; /* Need a ref to keep it from getting evicted from cache */ - atomic_inc(&em->refs); + refcount_inc(&em->refs); set_bit(EXTENT_FLAG_LOGGING, &em->flags); list_add_tail(&em->list, &extents); num++; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index ab8a66d852f9..017b67daa3bb 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -139,6 +139,11 @@ static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info); static void __btrfs_reset_dev_stats(struct btrfs_device *dev); static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev); static void btrfs_dev_stat_print_on_load(struct btrfs_device *device); +static int __btrfs_map_block(struct btrfs_fs_info *fs_info, + enum btrfs_map_op op, + u64 logical, u64 *length, + struct btrfs_bio **bbio_ret, + int mirror_num, int need_raid_map); DEFINE_MUTEX(uuid_mutex); static LIST_HEAD(fs_uuids); @@ -1008,14 +1013,13 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, q = bdev_get_queue(bdev); if (blk_queue_discard(q)) device->can_discard = 1; + if (!blk_queue_nonrot(q)) + fs_devices->rotating = 1; device->bdev = bdev; device->in_fs_metadata = 0; device->mode = flags; - if (!blk_queue_nonrot(bdev_get_queue(bdev))) - fs_devices->rotating = 1; - fs_devices->open_devices++; if (device->writeable && device->devid != BTRFS_DEV_REPLACE_DEVID) { @@ -2417,7 +2421,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path fs_info->free_chunk_space += device->total_bytes; spin_unlock(&fs_info->free_chunk_lock); - if (!blk_queue_nonrot(bdev_get_queue(bdev))) + if (!blk_queue_nonrot(q)) fs_info->fs_devices->rotating = 1; tmp = btrfs_super_total_bytes(fs_info->super_copy); @@ -2795,10 +2799,38 @@ static int btrfs_del_sys_chunk(struct btrfs_fs_info *fs_info, return ret; } +static struct extent_map *get_chunk_map(struct btrfs_fs_info *fs_info, + u64 logical, u64 length) +{ + struct extent_map_tree *em_tree; + struct extent_map *em; + + em_tree = &fs_info->mapping_tree.map_tree; + read_lock(&em_tree->lock); + em = lookup_extent_mapping(em_tree, logical, length); + read_unlock(&em_tree->lock); + + if (!em) { + btrfs_crit(fs_info, "unable to find logical %llu length %llu", + logical, length); + return ERR_PTR(-EINVAL); + } + + if (em->start > logical || em->start + em->len < logical) { + btrfs_crit(fs_info, + "found a bad mapping, wanted %llu-%llu, found %llu-%llu", + logical, length, em->start, em->start + em->len); + free_extent_map(em); + return ERR_PTR(-EINVAL); + } + + /* callers are responsible for dropping em's ref. */ + return em; +} + int btrfs_remove_chunk(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 chunk_offset) { - struct extent_map_tree *em_tree; struct extent_map *em; struct map_lookup *map; u64 dev_extent_len = 0; @@ -2806,23 +2838,15 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, int i, ret = 0; struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - em_tree = &fs_info->mapping_tree.map_tree; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, chunk_offset, 1); - read_unlock(&em_tree->lock); - - if (!em || em->start > chunk_offset || - em->start + em->len < chunk_offset) { + em = get_chunk_map(fs_info, chunk_offset, 1); + if (IS_ERR(em)) { /* * This is a logic error, but we don't want to just rely on the * user having built with ASSERT enabled, so if ASSERT doesn't * do anything we still error out. */ ASSERT(0); - if (em) - free_extent_map(em); - return -EINVAL; + return PTR_ERR(em); } map = em->map_lookup; mutex_lock(&fs_info->chunk_mutex); @@ -3736,7 +3760,7 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info) if (ret) btrfs_handle_fs_error(fs_info, ret, NULL); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); } /* Non-zero return value signifies invalidity */ @@ -3755,6 +3779,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, struct btrfs_ioctl_balance_args *bargs) { struct btrfs_fs_info *fs_info = bctl->fs_info; + u64 meta_target, data_target; u64 allowed; int mixed = 0; int ret; @@ -3851,11 +3876,16 @@ int btrfs_balance(struct btrfs_balance_control *bctl, } } while (read_seqretry(&fs_info->profiles_lock, seq)); - if (btrfs_get_num_tolerated_disk_barrier_failures(bctl->meta.target) < - btrfs_get_num_tolerated_disk_barrier_failures(bctl->data.target)) { + /* if we're not converting, the target field is uninitialized */ + meta_target = (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) ? + bctl->meta.target : fs_info->avail_metadata_alloc_bits; + data_target = (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) ? + bctl->data.target : fs_info->avail_data_alloc_bits; + if (btrfs_get_num_tolerated_disk_barrier_failures(meta_target) < + btrfs_get_num_tolerated_disk_barrier_failures(data_target)) { btrfs_warn(fs_info, "metadata profile 0x%llx has lower redundancy than data profile 0x%llx", - bctl->meta.target, bctl->data.target); + meta_target, data_target); } if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { @@ -3910,7 +3940,7 @@ out: __cancel_balance(fs_info); else { kfree(bctl); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); } return ret; } @@ -4000,7 +4030,7 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info) btrfs_balance_sys(leaf, item, &disk_bargs); btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs); - WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); + WARN_ON(test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)); mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->balance_mutex); @@ -4785,7 +4815,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, stripe_size = div_u64(stripe_size, dev_stripes); /* align to BTRFS_STRIPE_LEN */ - stripe_size = div_u64(stripe_size, raid_stripe_len); + stripe_size = div64_u64(stripe_size, raid_stripe_len); stripe_size *= raid_stripe_len; map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); @@ -4833,7 +4863,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ret = add_extent_mapping(em_tree, em, 0); if (!ret) { list_add_tail(&em->list, &trans->transaction->pending_chunks); - atomic_inc(&em->refs); + refcount_inc(&em->refs); } write_unlock(&em_tree->lock); if (ret) { @@ -4888,7 +4918,6 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, struct btrfs_device *device; struct btrfs_chunk *chunk; struct btrfs_stripe *stripe; - struct extent_map_tree *em_tree; struct extent_map *em; struct map_lookup *map; size_t item_size; @@ -4897,24 +4926,9 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, int i = 0; int ret = 0; - em_tree = &fs_info->mapping_tree.map_tree; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, chunk_offset, chunk_size); - read_unlock(&em_tree->lock); - - if (!em) { - btrfs_crit(fs_info, "unable to find logical %Lu len %Lu", - chunk_offset, chunk_size); - return -EINVAL; - } - - if (em->start != chunk_offset || em->len != chunk_size) { - btrfs_crit(fs_info, - "found a bad mapping, wanted %Lu-%Lu, found %Lu-%Lu", - chunk_offset, chunk_size, em->start, em->len); - free_extent_map(em); - return -EINVAL; - } + em = get_chunk_map(fs_info, chunk_offset, chunk_size); + if (IS_ERR(em)) + return PTR_ERR(em); map = em->map_lookup; item_size = btrfs_chunk_item_size(map->num_stripes); @@ -5055,15 +5069,12 @@ int btrfs_chunk_readonly(struct btrfs_fs_info *fs_info, u64 chunk_offset) { struct extent_map *em; struct map_lookup *map; - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; int readonly = 0; int miss_ndevs = 0; int i; - read_lock(&map_tree->map_tree.lock); - em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1); - read_unlock(&map_tree->map_tree.lock); - if (!em) + em = get_chunk_map(fs_info, chunk_offset, 1); + if (IS_ERR(em)) return 1; map = em->map_lookup; @@ -5117,34 +5128,19 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree) int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) { - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; struct extent_map *em; struct map_lookup *map; - struct extent_map_tree *em_tree = &map_tree->map_tree; int ret; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, len); - read_unlock(&em_tree->lock); - - /* - * We could return errors for these cases, but that could get ugly and - * we'd probably do the same thing which is just not do anything else - * and exit, so return 1 so the callers don't try to use other copies. - */ - if (!em) { - btrfs_crit(fs_info, "No mapping for %Lu-%Lu", logical, - logical+len); - return 1; - } - - if (em->start > logical || em->start + em->len < logical) { - btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got %Lu-%Lu", - logical, logical+len, em->start, - em->start + em->len); - free_extent_map(em); + em = get_chunk_map(fs_info, logical, len); + if (IS_ERR(em)) + /* + * We could return errors for these cases, but that could get + * ugly and we'd probably do the same thing which is just not do + * anything else and exit, so return 1 so the callers don't try + * to use other copies. + */ return 1; - } map = em->map_lookup; if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) @@ -5160,7 +5156,8 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) free_extent_map(em); btrfs_dev_replace_lock(&fs_info->dev_replace, 0); - if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) + if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace) && + fs_info->dev_replace.tgtdev) ret++; btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); @@ -5173,15 +5170,11 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info, { struct extent_map *em; struct map_lookup *map; - struct extent_map_tree *em_tree = &map_tree->map_tree; unsigned long len = fs_info->sectorsize; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, len); - read_unlock(&em_tree->lock); - BUG_ON(!em); + em = get_chunk_map(fs_info, logical, len); + WARN_ON(IS_ERR(em)); - BUG_ON(em->start > logical || em->start + em->len < logical); map = em->map_lookup; if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) len = map->stripe_len * nr_data_stripes(map); @@ -5189,20 +5182,16 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info, return len; } -int btrfs_is_parity_mirror(struct btrfs_mapping_tree *map_tree, +int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, u64 logical, u64 len, int mirror_num) { struct extent_map *em; struct map_lookup *map; - struct extent_map_tree *em_tree = &map_tree->map_tree; int ret = 0; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, len); - read_unlock(&em_tree->lock); - BUG_ON(!em); + em = get_chunk_map(fs_info, logical, len); + WARN_ON(IS_ERR(em)); - BUG_ON(em->start > logical || em->start + em->len < logical); map = em->map_lookup; if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) ret = 1; @@ -5295,25 +5284,353 @@ static struct btrfs_bio *alloc_btrfs_bio(int total_stripes, int real_stripes) GFP_NOFS|__GFP_NOFAIL); atomic_set(&bbio->error, 0); - atomic_set(&bbio->refs, 1); + refcount_set(&bbio->refs, 1); return bbio; } void btrfs_get_bbio(struct btrfs_bio *bbio) { - WARN_ON(!atomic_read(&bbio->refs)); - atomic_inc(&bbio->refs); + WARN_ON(!refcount_read(&bbio->refs)); + refcount_inc(&bbio->refs); } void btrfs_put_bbio(struct btrfs_bio *bbio) { if (!bbio) return; - if (atomic_dec_and_test(&bbio->refs)) + if (refcount_dec_and_test(&bbio->refs)) kfree(bbio); } +/* can REQ_OP_DISCARD be sent with other REQ like REQ_OP_WRITE? */ +/* + * Please note that, discard won't be sent to target device of device + * replace. + */ +static int __btrfs_map_block_for_discard(struct btrfs_fs_info *fs_info, + u64 logical, u64 length, + struct btrfs_bio **bbio_ret) +{ + struct extent_map *em; + struct map_lookup *map; + struct btrfs_bio *bbio; + u64 offset; + u64 stripe_nr; + u64 stripe_nr_end; + u64 stripe_end_offset; + u64 stripe_cnt; + u64 stripe_len; + u64 stripe_offset; + u64 num_stripes; + u32 stripe_index; + u32 factor = 0; + u32 sub_stripes = 0; + u64 stripes_per_dev = 0; + u32 remaining_stripes = 0; + u32 last_stripe = 0; + int ret = 0; + int i; + + /* discard always return a bbio */ + ASSERT(bbio_ret); + + em = get_chunk_map(fs_info, logical, length); + if (IS_ERR(em)) + return PTR_ERR(em); + + map = em->map_lookup; + /* we don't discard raid56 yet */ + if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { + ret = -EOPNOTSUPP; + goto out; + } + + offset = logical - em->start; + length = min_t(u64, em->len - offset, length); + + stripe_len = map->stripe_len; + /* + * stripe_nr counts the total number of stripes we have to stride + * to get to this block + */ + stripe_nr = div64_u64(offset, stripe_len); + + /* stripe_offset is the offset of this block in its stripe */ + stripe_offset = offset - stripe_nr * stripe_len; + + stripe_nr_end = round_up(offset + length, map->stripe_len); + stripe_nr_end = div64_u64(stripe_nr_end, map->stripe_len); + stripe_cnt = stripe_nr_end - stripe_nr; + stripe_end_offset = stripe_nr_end * map->stripe_len - + (offset + length); + /* + * after this, stripe_nr is the number of stripes on this + * device we have to walk to find the data, and stripe_index is + * the number of our device in the stripe array + */ + num_stripes = 1; + stripe_index = 0; + if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | + BTRFS_BLOCK_GROUP_RAID10)) { + if (map->type & BTRFS_BLOCK_GROUP_RAID0) + sub_stripes = 1; + else + sub_stripes = map->sub_stripes; + + factor = map->num_stripes / sub_stripes; + num_stripes = min_t(u64, map->num_stripes, + sub_stripes * stripe_cnt); + stripe_nr = div_u64_rem(stripe_nr, factor, &stripe_index); + stripe_index *= sub_stripes; + stripes_per_dev = div_u64_rem(stripe_cnt, factor, + &remaining_stripes); + div_u64_rem(stripe_nr_end - 1, factor, &last_stripe); + last_stripe *= sub_stripes; + } else if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_DUP)) { + num_stripes = map->num_stripes; + } else { + stripe_nr = div_u64_rem(stripe_nr, map->num_stripes, + &stripe_index); + } + + bbio = alloc_btrfs_bio(num_stripes, 0); + if (!bbio) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < num_stripes; i++) { + bbio->stripes[i].physical = + map->stripes[stripe_index].physical + + stripe_offset + stripe_nr * map->stripe_len; + bbio->stripes[i].dev = map->stripes[stripe_index].dev; + + if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | + BTRFS_BLOCK_GROUP_RAID10)) { + bbio->stripes[i].length = stripes_per_dev * + map->stripe_len; + + if (i / sub_stripes < remaining_stripes) + bbio->stripes[i].length += + map->stripe_len; + + /* + * Special for the first stripe and + * the last stripe: + * + * |-------|...|-------| + * |----------| + * off end_off + */ + if (i < sub_stripes) + bbio->stripes[i].length -= + stripe_offset; + + if (stripe_index >= last_stripe && + stripe_index <= (last_stripe + + sub_stripes - 1)) + bbio->stripes[i].length -= + stripe_end_offset; + + if (i == sub_stripes - 1) + stripe_offset = 0; + } else { + bbio->stripes[i].length = length; + } + + stripe_index++; + if (stripe_index == map->num_stripes) { + stripe_index = 0; + stripe_nr++; + } + } + + *bbio_ret = bbio; + bbio->map_type = map->type; + bbio->num_stripes = num_stripes; +out: + free_extent_map(em); + return ret; +} + +/* + * In dev-replace case, for repair case (that's the only case where the mirror + * is selected explicitly when calling btrfs_map_block), blocks left of the + * left cursor can also be read from the target drive. + * + * For REQ_GET_READ_MIRRORS, the target drive is added as the last one to the + * array of stripes. + * For READ, it also needs to be supported using the same mirror number. + * + * If the requested block is not left of the left cursor, EIO is returned. This + * can happen because btrfs_num_copies() returns one more in the dev-replace + * case. + */ +static int get_extra_mirror_from_replace(struct btrfs_fs_info *fs_info, + u64 logical, u64 length, + u64 srcdev_devid, int *mirror_num, + u64 *physical) +{ + struct btrfs_bio *bbio = NULL; + int num_stripes; + int index_srcdev = 0; + int found = 0; + u64 physical_of_found = 0; + int i; + int ret = 0; + + ret = __btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS, + logical, &length, &bbio, 0, 0); + if (ret) { + ASSERT(bbio == NULL); + return ret; + } + + num_stripes = bbio->num_stripes; + if (*mirror_num > num_stripes) { + /* + * BTRFS_MAP_GET_READ_MIRRORS does not contain this mirror, + * that means that the requested area is not left of the left + * cursor + */ + btrfs_put_bbio(bbio); + return -EIO; + } + + /* + * process the rest of the function using the mirror_num of the source + * drive. Therefore look it up first. At the end, patch the device + * pointer to the one of the target drive. + */ + for (i = 0; i < num_stripes; i++) { + if (bbio->stripes[i].dev->devid != srcdev_devid) + continue; + + /* + * In case of DUP, in order to keep it simple, only add the + * mirror with the lowest physical address + */ + if (found && + physical_of_found <= bbio->stripes[i].physical) + continue; + + index_srcdev = i; + found = 1; + physical_of_found = bbio->stripes[i].physical; + } + + btrfs_put_bbio(bbio); + + ASSERT(found); + if (!found) + return -EIO; + + *mirror_num = index_srcdev + 1; + *physical = physical_of_found; + return ret; +} + +static void handle_ops_on_dev_replace(enum btrfs_map_op op, + struct btrfs_bio **bbio_ret, + struct btrfs_dev_replace *dev_replace, + int *num_stripes_ret, int *max_errors_ret) +{ + struct btrfs_bio *bbio = *bbio_ret; + u64 srcdev_devid = dev_replace->srcdev->devid; + int tgtdev_indexes = 0; + int num_stripes = *num_stripes_ret; + int max_errors = *max_errors_ret; + int i; + + if (op == BTRFS_MAP_WRITE) { + int index_where_to_add; + + /* + * duplicate the write operations while the dev replace + * procedure is running. Since the copying of the old disk to + * the new disk takes place at run time while the filesystem is + * mounted writable, the regular write operations to the old + * disk have to be duplicated to go to the new disk as well. + * + * Note that device->missing is handled by the caller, and that + * the write to the old disk is already set up in the stripes + * array. + */ + index_where_to_add = num_stripes; + for (i = 0; i < num_stripes; i++) { + if (bbio->stripes[i].dev->devid == srcdev_devid) { + /* write to new disk, too */ + struct btrfs_bio_stripe *new = + bbio->stripes + index_where_to_add; + struct btrfs_bio_stripe *old = + bbio->stripes + i; + + new->physical = old->physical; + new->length = old->length; + new->dev = dev_replace->tgtdev; + bbio->tgtdev_map[i] = index_where_to_add; + index_where_to_add++; + max_errors++; + tgtdev_indexes++; + } + } + num_stripes = index_where_to_add; + } else if (op == BTRFS_MAP_GET_READ_MIRRORS) { + int index_srcdev = 0; + int found = 0; + u64 physical_of_found = 0; + + /* + * During the dev-replace procedure, the target drive can also + * be used to read data in case it is needed to repair a corrupt + * block elsewhere. This is possible if the requested area is + * left of the left cursor. In this area, the target drive is a + * full copy of the source drive. + */ + for (i = 0; i < num_stripes; i++) { + if (bbio->stripes[i].dev->devid == srcdev_devid) { + /* + * In case of DUP, in order to keep it simple, + * only add the mirror with the lowest physical + * address + */ + if (found && + physical_of_found <= + bbio->stripes[i].physical) + continue; + index_srcdev = i; + found = 1; + physical_of_found = bbio->stripes[i].physical; + } + } + if (found) { + struct btrfs_bio_stripe *tgtdev_stripe = + bbio->stripes + num_stripes; + + tgtdev_stripe->physical = physical_of_found; + tgtdev_stripe->length = + bbio->stripes[index_srcdev].length; + tgtdev_stripe->dev = dev_replace->tgtdev; + bbio->tgtdev_map[index_srcdev] = num_stripes; + + tgtdev_indexes++; + num_stripes++; + } + } + + *num_stripes_ret = num_stripes; + *max_errors_ret = max_errors; + bbio->num_tgtdevs = tgtdev_indexes; + *bbio_ret = bbio; +} + +static bool need_full_stripe(enum btrfs_map_op op) +{ + return (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS); +} + static int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 logical, u64 *length, @@ -5322,14 +5639,9 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, { struct extent_map *em; struct map_lookup *map; - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - struct extent_map_tree *em_tree = &map_tree->map_tree; u64 offset; u64 stripe_offset; - u64 stripe_end_offset; u64 stripe_nr; - u64 stripe_nr_orig; - u64 stripe_nr_end; u64 stripe_len; u32 stripe_index; int i; @@ -5345,23 +5657,13 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, u64 physical_to_patch_in_first_stripe = 0; u64 raid56_full_stripe_start = (u64)-1; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, *length); - read_unlock(&em_tree->lock); - - if (!em) { - btrfs_crit(fs_info, "unable to find logical %llu len %llu", - logical, *length); - return -EINVAL; - } + if (op == BTRFS_MAP_DISCARD) + return __btrfs_map_block_for_discard(fs_info, logical, + *length, bbio_ret); - if (em->start > logical || em->start + em->len < logical) { - btrfs_crit(fs_info, - "found a bad mapping, wanted %Lu, found %Lu-%Lu", - logical, em->start, em->start + em->len); - free_extent_map(em); - return -EINVAL; - } + em = get_chunk_map(fs_info, logical, *length); + if (IS_ERR(em)) + return PTR_ERR(em); map = em->map_lookup; offset = logical - em->start; @@ -5400,14 +5702,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, raid56_full_stripe_start *= full_stripe_len; } - if (op == BTRFS_MAP_DISCARD) { - /* we don't discard raid56 yet */ - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - ret = -EOPNOTSUPP; - goto out; - } - *length = min_t(u64, em->len - offset, *length); - } else if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { + if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { u64 max_len; /* For writes to RAID[56], allow a full stripeset across all disks. For other RAID types and for RAID[56] reads, just allow a single @@ -5438,105 +5733,28 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, btrfs_dev_replace_set_lock_blocking(dev_replace); if (dev_replace_is_ongoing && mirror_num == map->num_stripes + 1 && - op != BTRFS_MAP_WRITE && op != BTRFS_MAP_DISCARD && - op != BTRFS_MAP_GET_READ_MIRRORS && dev_replace->tgtdev != NULL) { - /* - * in dev-replace case, for repair case (that's the only - * case where the mirror is selected explicitly when - * calling btrfs_map_block), blocks left of the left cursor - * can also be read from the target drive. - * For REQ_GET_READ_MIRRORS, the target drive is added as - * the last one to the array of stripes. For READ, it also - * needs to be supported using the same mirror number. - * If the requested block is not left of the left cursor, - * EIO is returned. This can happen because btrfs_num_copies() - * returns one more in the dev-replace case. - */ - u64 tmp_length = *length; - struct btrfs_bio *tmp_bbio = NULL; - int tmp_num_stripes; - u64 srcdev_devid = dev_replace->srcdev->devid; - int index_srcdev = 0; - int found = 0; - u64 physical_of_found = 0; - - ret = __btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS, - logical, &tmp_length, &tmp_bbio, 0, 0); - if (ret) { - WARN_ON(tmp_bbio != NULL); - goto out; - } - - tmp_num_stripes = tmp_bbio->num_stripes; - if (mirror_num > tmp_num_stripes) { - /* - * BTRFS_MAP_GET_READ_MIRRORS does not contain this - * mirror, that means that the requested area - * is not left of the left cursor - */ - ret = -EIO; - btrfs_put_bbio(tmp_bbio); - goto out; - } - - /* - * process the rest of the function using the mirror_num - * of the source drive. Therefore look it up first. - * At the end, patch the device pointer to the one of the - * target drive. - */ - for (i = 0; i < tmp_num_stripes; i++) { - if (tmp_bbio->stripes[i].dev->devid != srcdev_devid) - continue; - - /* - * In case of DUP, in order to keep it simple, only add - * the mirror with the lowest physical address - */ - if (found && - physical_of_found <= tmp_bbio->stripes[i].physical) - continue; - - index_srcdev = i; - found = 1; - physical_of_found = tmp_bbio->stripes[i].physical; - } - - btrfs_put_bbio(tmp_bbio); - - if (!found) { - WARN_ON(1); - ret = -EIO; + !need_full_stripe(op) && dev_replace->tgtdev != NULL) { + ret = get_extra_mirror_from_replace(fs_info, logical, *length, + dev_replace->srcdev->devid, + &mirror_num, + &physical_to_patch_in_first_stripe); + if (ret) goto out; - } - - mirror_num = index_srcdev + 1; - patch_the_first_stripe_for_dev_replace = 1; - physical_to_patch_in_first_stripe = physical_of_found; + else + patch_the_first_stripe_for_dev_replace = 1; } else if (mirror_num > map->num_stripes) { mirror_num = 0; } num_stripes = 1; stripe_index = 0; - stripe_nr_orig = stripe_nr; - stripe_nr_end = ALIGN(offset + *length, map->stripe_len); - stripe_nr_end = div_u64(stripe_nr_end, map->stripe_len); - stripe_end_offset = stripe_nr_end * map->stripe_len - - (offset + *length); - if (map->type & BTRFS_BLOCK_GROUP_RAID0) { - if (op == BTRFS_MAP_DISCARD) - num_stripes = min_t(u64, map->num_stripes, - stripe_nr_end - stripe_nr_orig); stripe_nr = div_u64_rem(stripe_nr, map->num_stripes, &stripe_index); - if (op != BTRFS_MAP_WRITE && op != BTRFS_MAP_DISCARD && - op != BTRFS_MAP_GET_READ_MIRRORS) + if (op != BTRFS_MAP_WRITE && op != BTRFS_MAP_GET_READ_MIRRORS) mirror_num = 1; } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) { - if (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_DISCARD || - op == BTRFS_MAP_GET_READ_MIRRORS) + if (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS) num_stripes = map->num_stripes; else if (mirror_num) stripe_index = mirror_num - 1; @@ -5549,8 +5767,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, } } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { - if (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_DISCARD || - op == BTRFS_MAP_GET_READ_MIRRORS) { + if (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS) { num_stripes = map->num_stripes; } else if (mirror_num) { stripe_index = mirror_num - 1; @@ -5566,10 +5783,6 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, if (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS) num_stripes = map->sub_stripes; - else if (op == BTRFS_MAP_DISCARD) - num_stripes = min_t(u64, map->sub_stripes * - (stripe_nr_end - stripe_nr_orig), - map->num_stripes); else if (mirror_num) stripe_index += mirror_num - 1; else { @@ -5587,7 +5800,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS || mirror_num > 1)) { /* push stripe_nr back to the start of the full stripe */ - stripe_nr = div_u64(raid56_full_stripe_start, + stripe_nr = div64_u64(raid56_full_stripe_start, stripe_len * nr_data_stripes(map)); /* RAID[56] write or recovery. Return all stripes */ @@ -5612,8 +5825,9 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, /* We distribute the parity blocks across stripes */ div_u64_rem(stripe_nr + stripe_index, map->num_stripes, &stripe_index); - if ((op != BTRFS_MAP_WRITE && op != BTRFS_MAP_DISCARD && - op != BTRFS_MAP_GET_READ_MIRRORS) && mirror_num <= 1) + if ((op != BTRFS_MAP_WRITE && + op != BTRFS_MAP_GET_READ_MIRRORS) && + mirror_num <= 1) mirror_num = 1; } } else { @@ -5635,8 +5849,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, } num_alloc_stripes = num_stripes; - if (dev_replace_is_ongoing) { - if (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_DISCARD) + if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL) { + if (op == BTRFS_MAP_WRITE) num_alloc_stripes <<= 1; if (op == BTRFS_MAP_GET_READ_MIRRORS) num_alloc_stripes++; @@ -5648,14 +5862,12 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, ret = -ENOMEM; goto out; } - if (dev_replace_is_ongoing) + if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL) bbio->tgtdev_map = (int *)(bbio->stripes + num_alloc_stripes); /* build raid_map */ - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK && - need_raid_map && - ((op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS) || - mirror_num > 1)) { + if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK && need_raid_map && + (need_full_stripe(op) || mirror_num > 1)) { u64 tmp; unsigned rot; @@ -5679,173 +5891,27 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, RAID6_Q_STRIPE; } - if (op == BTRFS_MAP_DISCARD) { - u32 factor = 0; - u32 sub_stripes = 0; - u64 stripes_per_dev = 0; - u32 remaining_stripes = 0; - u32 last_stripe = 0; - if (map->type & - (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { - if (map->type & BTRFS_BLOCK_GROUP_RAID0) - sub_stripes = 1; - else - sub_stripes = map->sub_stripes; - - factor = map->num_stripes / sub_stripes; - stripes_per_dev = div_u64_rem(stripe_nr_end - - stripe_nr_orig, - factor, - &remaining_stripes); - div_u64_rem(stripe_nr_end - 1, factor, &last_stripe); - last_stripe *= sub_stripes; - } - - for (i = 0; i < num_stripes; i++) { - bbio->stripes[i].physical = - map->stripes[stripe_index].physical + - stripe_offset + stripe_nr * map->stripe_len; - bbio->stripes[i].dev = map->stripes[stripe_index].dev; - - if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_BLOCK_GROUP_RAID10)) { - bbio->stripes[i].length = stripes_per_dev * - map->stripe_len; - - if (i / sub_stripes < remaining_stripes) - bbio->stripes[i].length += - map->stripe_len; - - /* - * Special for the first stripe and - * the last stripe: - * - * |-------|...|-------| - * |----------| - * off end_off - */ - if (i < sub_stripes) - bbio->stripes[i].length -= - stripe_offset; - - if (stripe_index >= last_stripe && - stripe_index <= (last_stripe + - sub_stripes - 1)) - bbio->stripes[i].length -= - stripe_end_offset; - - if (i == sub_stripes - 1) - stripe_offset = 0; - } else - bbio->stripes[i].length = *length; - - stripe_index++; - if (stripe_index == map->num_stripes) { - /* This could only happen for RAID0/10 */ - stripe_index = 0; - stripe_nr++; - } - } - } else { - for (i = 0; i < num_stripes; i++) { - bbio->stripes[i].physical = - map->stripes[stripe_index].physical + - stripe_offset + - stripe_nr * map->stripe_len; - bbio->stripes[i].dev = - map->stripes[stripe_index].dev; - stripe_index++; - } + for (i = 0; i < num_stripes; i++) { + bbio->stripes[i].physical = + map->stripes[stripe_index].physical + + stripe_offset + + stripe_nr * map->stripe_len; + bbio->stripes[i].dev = + map->stripes[stripe_index].dev; + stripe_index++; } - if (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS) + if (need_full_stripe(op)) max_errors = btrfs_chunk_max_errors(map); if (bbio->raid_map) sort_parity_stripes(bbio, num_stripes); - tgtdev_indexes = 0; - if (dev_replace_is_ongoing && - (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_DISCARD) && - dev_replace->tgtdev != NULL) { - int index_where_to_add; - u64 srcdev_devid = dev_replace->srcdev->devid; - - /* - * duplicate the write operations while the dev replace - * procedure is running. Since the copying of the old disk - * to the new disk takes place at run time while the - * filesystem is mounted writable, the regular write - * operations to the old disk have to be duplicated to go - * to the new disk as well. - * Note that device->missing is handled by the caller, and - * that the write to the old disk is already set up in the - * stripes array. - */ - index_where_to_add = num_stripes; - for (i = 0; i < num_stripes; i++) { - if (bbio->stripes[i].dev->devid == srcdev_devid) { - /* write to new disk, too */ - struct btrfs_bio_stripe *new = - bbio->stripes + index_where_to_add; - struct btrfs_bio_stripe *old = - bbio->stripes + i; - - new->physical = old->physical; - new->length = old->length; - new->dev = dev_replace->tgtdev; - bbio->tgtdev_map[i] = index_where_to_add; - index_where_to_add++; - max_errors++; - tgtdev_indexes++; - } - } - num_stripes = index_where_to_add; - } else if (dev_replace_is_ongoing && - op == BTRFS_MAP_GET_READ_MIRRORS && - dev_replace->tgtdev != NULL) { - u64 srcdev_devid = dev_replace->srcdev->devid; - int index_srcdev = 0; - int found = 0; - u64 physical_of_found = 0; - - /* - * During the dev-replace procedure, the target drive can - * also be used to read data in case it is needed to repair - * a corrupt block elsewhere. This is possible if the - * requested area is left of the left cursor. In this area, - * the target drive is a full copy of the source drive. - */ - for (i = 0; i < num_stripes; i++) { - if (bbio->stripes[i].dev->devid == srcdev_devid) { - /* - * In case of DUP, in order to keep it - * simple, only add the mirror with the - * lowest physical address - */ - if (found && - physical_of_found <= - bbio->stripes[i].physical) - continue; - index_srcdev = i; - found = 1; - physical_of_found = bbio->stripes[i].physical; - } - } - if (found) { - struct btrfs_bio_stripe *tgtdev_stripe = - bbio->stripes + num_stripes; - - tgtdev_stripe->physical = physical_of_found; - tgtdev_stripe->length = - bbio->stripes[index_srcdev].length; - tgtdev_stripe->dev = dev_replace->tgtdev; - bbio->tgtdev_map[index_srcdev] = num_stripes; - - tgtdev_indexes++; - num_stripes++; - } + if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL && + need_full_stripe(op)) { + handle_ops_on_dev_replace(op, &bbio, dev_replace, &num_stripes, + &max_errors); } *bbio_ret = bbio; @@ -5853,7 +5919,6 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, bbio->num_stripes = num_stripes; bbio->max_errors = max_errors; bbio->mirror_num = mirror_num; - bbio->num_tgtdevs = tgtdev_indexes; /* * this is the case that REQ_READ && dev_replace_is_ongoing && @@ -5886,19 +5951,15 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, /* For Scrub/replace */ int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 logical, u64 *length, - struct btrfs_bio **bbio_ret, int mirror_num, - int need_raid_map) + struct btrfs_bio **bbio_ret) { - return __btrfs_map_block(fs_info, op, logical, length, bbio_ret, - mirror_num, need_raid_map); + return __btrfs_map_block(fs_info, op, logical, length, bbio_ret, 0, 1); } int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start, u64 physical, u64 devid, u64 **logical, int *naddrs, int *stripe_len) { - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - struct extent_map_tree *em_tree = &map_tree->map_tree; struct extent_map *em; struct map_lookup *map; u64 *buf; @@ -5908,24 +5969,11 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 rmap_len; int i, j, nr = 0; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, chunk_start, 1); - read_unlock(&em_tree->lock); - - if (!em) { - btrfs_err(fs_info, "couldn't find em for chunk %Lu", - chunk_start); + em = get_chunk_map(fs_info, chunk_start, 1); + if (IS_ERR(em)) return -EIO; - } - if (em->start != chunk_start) { - btrfs_err(fs_info, "bad chunk start, em=%Lu, wanted=%Lu", - em->start, chunk_start); - free_extent_map(em); - return -EIO; - } map = em->map_lookup; - length = em->len; rmap_len = map->stripe_len; @@ -5949,7 +5997,7 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, continue; stripe_nr = physical - map->stripes[i].physical; - stripe_nr = div_u64(stripe_nr, map->stripe_len); + stripe_nr = div64_u64(stripe_nr, map->stripe_len); if (map->type & BTRFS_BLOCK_GROUP_RAID10) { stripe_nr = stripe_nr * map->num_stripes + i; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 59be81206dd7..c7d0fbc915ca 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -123,7 +123,6 @@ struct btrfs_device { struct list_head resized_list; /* for sending down flush barriers */ - int nobarriers; struct bio *flush_bio; struct completion flush_wait; @@ -298,7 +297,7 @@ struct btrfs_bio; typedef void (btrfs_bio_end_io_t) (struct btrfs_bio *bio, int err); struct btrfs_bio { - atomic_t refs; + refcount_t refs; atomic_t stripes_pending; struct btrfs_fs_info *fs_info; u64 map_type; /* get from map_lookup->type */ @@ -400,8 +399,7 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, struct btrfs_bio **bbio_ret, int mirror_num); int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 logical, u64 *length, - struct btrfs_bio **bbio_ret, int mirror_num, - int need_raid_map); + struct btrfs_bio **bbio_ret); int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start, u64 physical, u64 devid, u64 **logical, int *naddrs, int *stripe_len); @@ -475,7 +473,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info, struct btrfs_device *tgtdev); void btrfs_scratch_superblocks(struct block_device *bdev, const char *device_path); -int btrfs_is_parity_mirror(struct btrfs_mapping_tree *map_tree, +int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, u64 logical, u64 len, int mirror_num); unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info, struct btrfs_mapping_tree *map_tree, diff --git a/fs/buffer.c b/fs/buffer.c index c3c7455efa3f..161be58c5cb0 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -49,7 +49,6 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags, struct writeback_control *wbc); #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers) @@ -1830,7 +1829,7 @@ int __block_write_full_page(struct inode *inode, struct page *page, do { struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { - submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, 0, wbc); + submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, wbc); nr_underway++; } bh = next; @@ -1884,7 +1883,7 @@ recover: struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { clear_buffer_dirty(bh); - submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, 0, wbc); + submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, wbc); nr_underway++; } bh = next; @@ -3092,7 +3091,7 @@ void guard_bio_eod(int op, struct bio *bio) } static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags, struct writeback_control *wbc) + struct writeback_control *wbc) { struct bio *bio; @@ -3127,7 +3126,6 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, bio->bi_end_io = end_bio_bh_io_sync; bio->bi_private = bh; - bio->bi_flags |= bio_flags; /* Take care of bh's that straddle the end of the device */ guard_bio_eod(op, bio); @@ -3142,16 +3140,9 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, return 0; } -int _submit_bh(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags) +int submit_bh(int op, int op_flags, struct buffer_head *bh) { - return submit_bh_wbc(op, op_flags, bh, bio_flags, NULL); -} -EXPORT_SYMBOL_GPL(_submit_bh); - -int submit_bh(int op, int op_flags, struct buffer_head *bh) -{ - return submit_bh_wbc(op, op_flags, bh, 0, NULL); + return submit_bh_wbc(op, op_flags, bh, NULL); } EXPORT_SYMBOL(submit_bh); diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 9ecb2fd348cb..1e71e6ca5ddf 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -670,8 +670,12 @@ static void writepages_finish(struct ceph_osd_request *req) bool remove_page; dout("writepages_finish %p rc %d\n", inode, rc); - if (rc < 0) + if (rc < 0) { mapping_set_error(mapping, rc); + ceph_set_error_write(ci); + } else { + ceph_clear_error_write(ci); + } /* * We lost the cache cap, need to truncate the page before @@ -703,9 +707,6 @@ static void writepages_finish(struct ceph_osd_request *req) clear_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC); - if (rc < 0) - SetPageError(page); - ceph_put_snap_context(page_snap_context(page)); page->private = 0; ClearPagePrivate(page); @@ -1892,6 +1893,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, err = ceph_osdc_start_request(&fsc->client->osdc, rd_req, false); wr_req->r_mtime = ci->vfs_inode.i_mtime; + wr_req->r_abort_on_full = true; err2 = ceph_osdc_start_request(&fsc->client->osdc, wr_req, false); if (!err) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 68c78be19d5b..a3ebb632294e 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1015,6 +1015,7 @@ static int send_cap_msg(struct cap_msg_args *arg) void *p; size_t extra_len; struct timespec zerotime = {0}; + struct ceph_osd_client *osdc = &arg->session->s_mdsc->fsc->client->osdc; dout("send_cap_msg %s %llx %llx caps %s wanted %s dirty %s" " seq %u/%u tid %llu/%llu mseq %u follows %lld size %llu/%llu" @@ -1076,8 +1077,12 @@ static int send_cap_msg(struct cap_msg_args *arg) ceph_encode_64(&p, arg->inline_data ? 0 : CEPH_INLINE_NONE); /* inline data size */ ceph_encode_32(&p, 0); - /* osd_epoch_barrier (version 5) */ - ceph_encode_32(&p, 0); + /* + * osd_epoch_barrier (version 5) + * The epoch_barrier is protected osdc->lock, so READ_ONCE here in + * case it was recently changed + */ + ceph_encode_32(&p, READ_ONCE(osdc->epoch_barrier)); /* oldest_flush_tid (version 6) */ ceph_encode_64(&p, arg->oldest_flush_tid); @@ -1389,7 +1394,7 @@ static void __ceph_flush_snaps(struct ceph_inode_info *ci, first_tid = cf->tid + 1; capsnap = container_of(cf, struct ceph_cap_snap, cap_flush); - atomic_inc(&capsnap->nref); + refcount_inc(&capsnap->nref); spin_unlock(&ci->i_ceph_lock); dout("__flush_snaps %p capsnap %p tid %llu %s\n", @@ -2202,7 +2207,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, inode, capsnap, cf->tid, ceph_cap_string(capsnap->dirty)); - atomic_inc(&capsnap->nref); + refcount_inc(&capsnap->nref); spin_unlock(&ci->i_ceph_lock); ret = __send_flush_snap(inode, session, capsnap, cap->mseq, @@ -3633,13 +3638,19 @@ void ceph_handle_caps(struct ceph_mds_session *session, p += inline_len; } + if (le16_to_cpu(msg->hdr.version) >= 5) { + struct ceph_osd_client *osdc = &mdsc->fsc->client->osdc; + u32 epoch_barrier; + + ceph_decode_32_safe(&p, end, epoch_barrier, bad); + ceph_osdc_update_epoch_barrier(osdc, epoch_barrier); + } + if (le16_to_cpu(msg->hdr.version) >= 8) { u64 flush_tid; u32 caller_uid, caller_gid; - u32 osd_epoch_barrier; u32 pool_ns_len; - /* version >= 5 */ - ceph_decode_32_safe(&p, end, osd_epoch_barrier, bad); + /* version >= 6 */ ceph_decode_64_safe(&p, end, flush_tid, bad); /* version >= 7 */ diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 3ef11bc8d728..4e2d112c982f 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -22,20 +22,19 @@ static int mdsmap_show(struct seq_file *s, void *p) { int i; struct ceph_fs_client *fsc = s->private; + struct ceph_mdsmap *mdsmap; if (fsc->mdsc == NULL || fsc->mdsc->mdsmap == NULL) return 0; - seq_printf(s, "epoch %d\n", fsc->mdsc->mdsmap->m_epoch); - seq_printf(s, "root %d\n", fsc->mdsc->mdsmap->m_root); - seq_printf(s, "session_timeout %d\n", - fsc->mdsc->mdsmap->m_session_timeout); - seq_printf(s, "session_autoclose %d\n", - fsc->mdsc->mdsmap->m_session_autoclose); - for (i = 0; i < fsc->mdsc->mdsmap->m_max_mds; i++) { - struct ceph_entity_addr *addr = - &fsc->mdsc->mdsmap->m_info[i].addr; - int state = fsc->mdsc->mdsmap->m_info[i].state; - + mdsmap = fsc->mdsc->mdsmap; + seq_printf(s, "epoch %d\n", mdsmap->m_epoch); + seq_printf(s, "root %d\n", mdsmap->m_root); + seq_printf(s, "max_mds %d\n", mdsmap->m_max_mds); + seq_printf(s, "session_timeout %d\n", mdsmap->m_session_timeout); + seq_printf(s, "session_autoclose %d\n", mdsmap->m_session_autoclose); + for (i = 0; i < mdsmap->m_num_mds; i++) { + struct ceph_entity_addr *addr = &mdsmap->m_info[i].addr; + int state = mdsmap->m_info[i].state; seq_printf(s, "\tmds%d\t%s\t(%s)\n", i, ceph_pr_addr(&addr->in_addr), ceph_mds_state_name(state)); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 3e9ad501addf..e071d23f6148 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -294,7 +294,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) struct ceph_mds_client *mdsc = fsc->mdsc; int i; int err; - u32 ftype; + unsigned frag = -1; struct ceph_mds_reply_info_parsed *rinfo; dout("readdir %p file %p pos %llx\n", inode, file, ctx->pos); @@ -341,7 +341,6 @@ more: /* do we have the correct frag content buffered? */ if (need_send_readdir(fi, ctx->pos)) { struct ceph_mds_request *req; - unsigned frag; int op = ceph_snap(inode) == CEPH_SNAPDIR ? CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR; @@ -352,8 +351,11 @@ more: } if (is_hash_order(ctx->pos)) { - frag = ceph_choose_frag(ci, fpos_hash(ctx->pos), - NULL, NULL); + /* fragtree isn't always accurate. choose frag + * based on previous reply when possible. */ + if (frag == (unsigned)-1) + frag = ceph_choose_frag(ci, fpos_hash(ctx->pos), + NULL, NULL); } else { frag = fpos_frag(ctx->pos); } @@ -378,7 +380,11 @@ more: ceph_mdsc_put_request(req); return -ENOMEM; } + } else if (is_hash_order(ctx->pos)) { + req->r_args.readdir.offset_hash = + cpu_to_le32(fpos_hash(ctx->pos)); } + req->r_dir_release_cnt = fi->dir_release_count; req->r_dir_ordered_cnt = fi->dir_ordered_count; req->r_readdir_cache_idx = fi->readdir_cache_idx; @@ -476,6 +482,7 @@ more: struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i; struct ceph_vino vino; ino_t ino; + u32 ftype; BUG_ON(rde->offset < ctx->pos); @@ -498,15 +505,17 @@ more: ctx->pos++; } + ceph_mdsc_put_request(fi->last_readdir); + fi->last_readdir = NULL; + if (fi->next_offset > 2) { - ceph_mdsc_put_request(fi->last_readdir); - fi->last_readdir = NULL; + frag = fi->frag; goto more; } /* more frags? */ if (!ceph_frag_is_rightmost(fi->frag)) { - unsigned frag = ceph_frag_next(fi->frag); + frag = ceph_frag_next(fi->frag); if (is_hash_order(ctx->pos)) { loff_t new_pos = ceph_make_fpos(ceph_frag_value(frag), fi->next_offset, true); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 18c045e2ead6..3fdde0b283c9 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -13,6 +13,38 @@ #include "mds_client.h" #include "cache.h" +static __le32 ceph_flags_sys2wire(u32 flags) +{ + u32 wire_flags = 0; + + switch (flags & O_ACCMODE) { + case O_RDONLY: + wire_flags |= CEPH_O_RDONLY; + break; + case O_WRONLY: + wire_flags |= CEPH_O_WRONLY; + break; + case O_RDWR: + wire_flags |= CEPH_O_RDWR; + break; + } + +#define ceph_sys2wire(a) if (flags & a) { wire_flags |= CEPH_##a; flags &= ~a; } + + ceph_sys2wire(O_CREAT); + ceph_sys2wire(O_EXCL); + ceph_sys2wire(O_TRUNC); + ceph_sys2wire(O_DIRECTORY); + ceph_sys2wire(O_NOFOLLOW); + +#undef ceph_sys2wire + + if (flags) + dout("unused open flags: %x", flags); + + return cpu_to_le32(wire_flags); +} + /* * Ceph file operations * @@ -120,7 +152,7 @@ prepare_open_request(struct super_block *sb, int flags, int create_mode) if (IS_ERR(req)) goto out; req->r_fmode = ceph_flags_to_mode(flags); - req->r_args.open.flags = cpu_to_le32(flags); + req->r_args.open.flags = ceph_flags_sys2wire(flags); req->r_args.open.mode = cpu_to_le32(create_mode); out: return req; @@ -189,7 +221,7 @@ int ceph_renew_caps(struct inode *inode) spin_lock(&ci->i_ceph_lock); wanted = __ceph_caps_file_wanted(ci); if (__ceph_is_any_real_caps(ci) && - (!(wanted & CEPH_CAP_ANY_WR) == 0 || ci->i_auth_cap)) { + (!(wanted & CEPH_CAP_ANY_WR) || ci->i_auth_cap)) { int issued = __ceph_caps_issued(ci, NULL); spin_unlock(&ci->i_ceph_lock); dout("renew caps %p want %s issued %s updating mds_wanted\n", @@ -778,6 +810,7 @@ static void ceph_aio_retry_work(struct work_struct *work) req->r_callback = ceph_aio_complete_req; req->r_inode = inode; req->r_priv = aio_req; + req->r_abort_on_full = true; ret = ceph_osdc_start_request(req->r_osdc, req, false); out: @@ -1085,19 +1118,22 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos, out: ceph_osdc_put_request(req); - if (ret == 0) { - pos += len; - written += len; - - if (pos > i_size_read(inode)) { - check_caps = ceph_inode_set_size(inode, pos); - if (check_caps) - ceph_check_caps(ceph_inode(inode), - CHECK_CAPS_AUTHONLY, - NULL); - } - } else + if (ret != 0) { + ceph_set_error_write(ci); break; + } + + ceph_clear_error_write(ci); + pos += len; + written += len; + if (pos > i_size_read(inode)) { + check_caps = ceph_inode_set_size(inode, pos); + if (check_caps) + ceph_check_caps(ceph_inode(inode), + CHECK_CAPS_AUTHONLY, + NULL); + } + } if (ret != -EOLDSNAPC && written > 0) { @@ -1303,6 +1339,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) } retry_snap: + /* FIXME: not complete since it doesn't account for being at quota */ if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL)) { err = -ENOSPC; goto out; @@ -1324,7 +1361,8 @@ retry_snap: inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || - (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC)) { + (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC) || + (ci->i_ceph_flags & CEPH_I_ERROR_WRITE)) { struct ceph_snap_context *snapc; struct iov_iter data; inode_unlock(inode); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index d3119fe3ab45..dcce79b84406 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1482,10 +1482,17 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, if (test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) return readdir_prepopulate_inodes_only(req, session); - if (rinfo->hash_order && req->r_path2) { - last_hash = ceph_str_hash(ci->i_dir_layout.dl_dir_hash, - req->r_path2, strlen(req->r_path2)); - last_hash = ceph_frag_value(last_hash); + if (rinfo->hash_order) { + if (req->r_path2) { + last_hash = ceph_str_hash(ci->i_dir_layout.dl_dir_hash, + req->r_path2, + strlen(req->r_path2)); + last_hash = ceph_frag_value(last_hash); + } else if (rinfo->offset_hash) { + /* mds understands offset_hash */ + WARN_ON_ONCE(req->r_readdir_offset != 2); + last_hash = le32_to_cpu(rhead->args.readdir.offset_hash); + } } if (rinfo->dir_dir && @@ -1510,7 +1517,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, } if (ceph_frag_is_leftmost(frag) && req->r_readdir_offset == 2 && - !(rinfo->hash_order && req->r_path2)) { + !(rinfo->hash_order && last_hash)) { /* note dir version at start of readdir so we can tell * if any dentries get dropped */ req->r_dir_release_cnt = atomic64_read(&ci->i_release_count); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 1d3fa90d40b9..f38e56fa9712 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -189,6 +189,7 @@ static int parse_reply_info_dir(void **p, void *end, info->dir_end = !!(flags & CEPH_READDIR_FRAG_END); info->dir_complete = !!(flags & CEPH_READDIR_FRAG_COMPLETE); info->hash_order = !!(flags & CEPH_READDIR_HASH_ORDER); + info->offset_hash = !!(flags & CEPH_READDIR_OFFSET_HASH); } if (num == 0) goto done; @@ -378,9 +379,9 @@ const char *ceph_session_state_name(int s) static struct ceph_mds_session *get_session(struct ceph_mds_session *s) { - if (atomic_inc_not_zero(&s->s_ref)) { + if (refcount_inc_not_zero(&s->s_ref)) { dout("mdsc get_session %p %d -> %d\n", s, - atomic_read(&s->s_ref)-1, atomic_read(&s->s_ref)); + refcount_read(&s->s_ref)-1, refcount_read(&s->s_ref)); return s; } else { dout("mdsc get_session %p 0 -- FAIL", s); @@ -391,8 +392,8 @@ static struct ceph_mds_session *get_session(struct ceph_mds_session *s) void ceph_put_mds_session(struct ceph_mds_session *s) { dout("mdsc put_session %p %d -> %d\n", s, - atomic_read(&s->s_ref), atomic_read(&s->s_ref)-1); - if (atomic_dec_and_test(&s->s_ref)) { + refcount_read(&s->s_ref), refcount_read(&s->s_ref)-1); + if (refcount_dec_and_test(&s->s_ref)) { if (s->s_auth.authorizer) ceph_auth_destroy_authorizer(s->s_auth.authorizer); kfree(s); @@ -411,7 +412,7 @@ struct ceph_mds_session *__ceph_lookup_mds_session(struct ceph_mds_client *mdsc, return NULL; session = mdsc->sessions[mds]; dout("lookup_mds_session %p %d\n", session, - atomic_read(&session->s_ref)); + refcount_read(&session->s_ref)); get_session(session); return session; } @@ -441,7 +442,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, { struct ceph_mds_session *s; - if (mds >= mdsc->mdsmap->m_max_mds) + if (mds >= mdsc->mdsmap->m_num_mds) return ERR_PTR(-EINVAL); s = kzalloc(sizeof(*s), GFP_NOFS); @@ -466,7 +467,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, INIT_LIST_HEAD(&s->s_caps); s->s_nr_caps = 0; s->s_trim_caps = 0; - atomic_set(&s->s_ref, 1); + refcount_set(&s->s_ref, 1); INIT_LIST_HEAD(&s->s_waiting); INIT_LIST_HEAD(&s->s_unsafe); s->s_num_cap_releases = 0; @@ -494,7 +495,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, } mdsc->sessions[mds] = s; atomic_inc(&mdsc->num_sessions); - atomic_inc(&s->s_ref); /* one ref to sessions[], one to caller */ + refcount_inc(&s->s_ref); /* one ref to sessions[], one to caller */ ceph_con_open(&s->s_con, CEPH_ENTITY_TYPE_MDS, mds, ceph_mdsmap_get_addr(mdsc->mdsmap, mds)); @@ -1004,7 +1005,7 @@ static void __open_export_target_sessions(struct ceph_mds_client *mdsc, struct ceph_mds_session *ts; int i, mds = session->s_mds; - if (mds >= mdsc->mdsmap->m_max_mds) + if (mds >= mdsc->mdsmap->m_num_mds) return; mi = &mdsc->mdsmap->m_info[mds]; @@ -1551,9 +1552,15 @@ void ceph_send_cap_releases(struct ceph_mds_client *mdsc, struct ceph_msg *msg = NULL; struct ceph_mds_cap_release *head; struct ceph_mds_cap_item *item; + struct ceph_osd_client *osdc = &mdsc->fsc->client->osdc; struct ceph_cap *cap; LIST_HEAD(tmp_list); int num_cap_releases; + __le32 barrier, *cap_barrier; + + down_read(&osdc->lock); + barrier = cpu_to_le32(osdc->epoch_barrier); + up_read(&osdc->lock); spin_lock(&session->s_cap_lock); again: @@ -1571,7 +1578,11 @@ again: head = msg->front.iov_base; head->num = cpu_to_le32(0); msg->front.iov_len = sizeof(*head); + + msg->hdr.version = cpu_to_le16(2); + msg->hdr.compat_version = cpu_to_le16(1); } + cap = list_first_entry(&tmp_list, struct ceph_cap, session_caps); list_del(&cap->session_caps); @@ -1589,6 +1600,11 @@ again: ceph_put_cap(mdsc, cap); if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) { + // Append cap_barrier field + cap_barrier = msg->front.iov_base + msg->front.iov_len; + *cap_barrier = barrier; + msg->front.iov_len += sizeof(*cap_barrier); + msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); dout("send_cap_releases mds%d %p\n", session->s_mds, msg); ceph_con_send(&session->s_con, msg); @@ -1604,6 +1620,11 @@ again: spin_unlock(&session->s_cap_lock); if (msg) { + // Append cap_barrier field + cap_barrier = msg->front.iov_base + msg->front.iov_len; + *cap_barrier = barrier; + msg->front.iov_len += sizeof(*cap_barrier); + msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); dout("send_cap_releases mds%d %p\n", session->s_mds, msg); ceph_con_send(&session->s_con, msg); @@ -1993,7 +2014,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, if (req->r_pagelist) { struct ceph_pagelist *pagelist = req->r_pagelist; - atomic_inc(&pagelist->refcnt); + refcount_inc(&pagelist->refcnt); ceph_msg_data_add_pagelist(msg, pagelist); msg->hdr.data_len = cpu_to_le32(pagelist->length); } else { @@ -2640,8 +2661,10 @@ static void handle_session(struct ceph_mds_session *session, seq = le64_to_cpu(h->seq); mutex_lock(&mdsc->mutex); - if (op == CEPH_SESSION_CLOSE) + if (op == CEPH_SESSION_CLOSE) { + get_session(session); __unregister_session(mdsc, session); + } /* FIXME: this ttl calculation is generous */ session->s_ttl = jiffies + HZ*mdsc->mdsmap->m_session_autoclose; mutex_unlock(&mdsc->mutex); @@ -2730,6 +2753,8 @@ static void handle_session(struct ceph_mds_session *session, kick_requests(mdsc, mds); mutex_unlock(&mdsc->mutex); } + if (op == CEPH_SESSION_CLOSE) + ceph_put_mds_session(session); return; bad: @@ -3109,7 +3134,7 @@ static void check_new_map(struct ceph_mds_client *mdsc, dout("check_new_map new %u old %u\n", newmap->m_epoch, oldmap->m_epoch); - for (i = 0; i < oldmap->m_max_mds && i < mdsc->max_sessions; i++) { + for (i = 0; i < oldmap->m_num_mds && i < mdsc->max_sessions; i++) { if (mdsc->sessions[i] == NULL) continue; s = mdsc->sessions[i]; @@ -3123,15 +3148,33 @@ static void check_new_map(struct ceph_mds_client *mdsc, ceph_mdsmap_is_laggy(newmap, i) ? " (laggy)" : "", ceph_session_state_name(s->s_state)); - if (i >= newmap->m_max_mds || + if (i >= newmap->m_num_mds || memcmp(ceph_mdsmap_get_addr(oldmap, i), ceph_mdsmap_get_addr(newmap, i), sizeof(struct ceph_entity_addr))) { if (s->s_state == CEPH_MDS_SESSION_OPENING) { /* the session never opened, just close it * out now */ + get_session(s); + __unregister_session(mdsc, s); __wake_requests(mdsc, &s->s_waiting); + ceph_put_mds_session(s); + } else if (i >= newmap->m_num_mds) { + /* force close session for stopped mds */ + get_session(s); __unregister_session(mdsc, s); + __wake_requests(mdsc, &s->s_waiting); + kick_requests(mdsc, i); + mutex_unlock(&mdsc->mutex); + + mutex_lock(&s->s_mutex); + cleanup_session_requests(mdsc, s); + remove_session_caps(s); + mutex_unlock(&s->s_mutex); + + ceph_put_mds_session(s); + + mutex_lock(&mdsc->mutex); } else { /* just close it */ mutex_unlock(&mdsc->mutex); @@ -3169,7 +3212,7 @@ static void check_new_map(struct ceph_mds_client *mdsc, } } - for (i = 0; i < newmap->m_max_mds && i < mdsc->max_sessions; i++) { + for (i = 0; i < newmap->m_num_mds && i < mdsc->max_sessions; i++) { s = mdsc->sessions[i]; if (!s) continue; @@ -3883,7 +3926,7 @@ static struct ceph_connection *con_get(struct ceph_connection *con) struct ceph_mds_session *s = con->private; if (get_session(s)) { - dout("mdsc con_get %p ok (%d)\n", s, atomic_read(&s->s_ref)); + dout("mdsc con_get %p ok (%d)\n", s, refcount_read(&s->s_ref)); return con; } dout("mdsc con_get %p FAIL\n", s); @@ -3894,7 +3937,7 @@ static void con_put(struct ceph_connection *con) { struct ceph_mds_session *s = con->private; - dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref) - 1); + dout("mdsc con_put %p (%d)\n", s, refcount_read(&s->s_ref) - 1); ceph_put_mds_session(s); } diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index ac0475a2daa7..db57ae98ed34 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -7,6 +7,7 @@ #include <linux/mutex.h> #include <linux/rbtree.h> #include <linux/spinlock.h> +#include <linux/refcount.h> #include <linux/ceph/types.h> #include <linux/ceph/messenger.h> @@ -82,9 +83,10 @@ struct ceph_mds_reply_info_parsed { struct ceph_mds_reply_dirfrag *dir_dir; size_t dir_buf_size; int dir_nr; - bool dir_complete; bool dir_end; + bool dir_complete; bool hash_order; + bool offset_hash; struct ceph_mds_reply_dir_entry *dir_entries; }; @@ -104,10 +106,13 @@ struct ceph_mds_reply_info_parsed { /* * cap releases are batched and sent to the MDS en masse. + * + * Account for per-message overhead of mds_cap_release header + * and __le32 for osd epoch barrier trailing field. */ -#define CEPH_CAPS_PER_RELEASE ((PAGE_SIZE - \ +#define CEPH_CAPS_PER_RELEASE ((PAGE_SIZE - sizeof(u32) - \ sizeof(struct ceph_mds_cap_release)) / \ - sizeof(struct ceph_mds_cap_item)) + sizeof(struct ceph_mds_cap_item)) /* @@ -156,7 +161,7 @@ struct ceph_mds_session { unsigned long s_renew_requested; /* last time we sent a renew req */ u64 s_renew_seq; - atomic_t s_ref; + refcount_t s_ref; struct list_head s_waiting; /* waiting requests */ struct list_head s_unsafe; /* unsafe requests */ }; @@ -373,7 +378,7 @@ __ceph_lookup_mds_session(struct ceph_mds_client *, int mds); static inline struct ceph_mds_session * ceph_get_mds_session(struct ceph_mds_session *s) { - atomic_inc(&s->s_ref); + refcount_inc(&s->s_ref); return s; } diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c index 5454e2327a5f..1a748cf88535 100644 --- a/fs/ceph/mdsmap.c +++ b/fs/ceph/mdsmap.c @@ -22,11 +22,11 @@ int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m) int i; /* special case for one mds */ - if (1 == m->m_max_mds && m->m_info[0].state > 0) + if (1 == m->m_num_mds && m->m_info[0].state > 0) return 0; /* count */ - for (i = 0; i < m->m_max_mds; i++) + for (i = 0; i < m->m_num_mds; i++) if (m->m_info[i].state > 0) n++; if (n == 0) @@ -135,8 +135,9 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) m->m_session_autoclose = ceph_decode_32(p); m->m_max_file_size = ceph_decode_64(p); m->m_max_mds = ceph_decode_32(p); + m->m_num_mds = m->m_max_mds; - m->m_info = kcalloc(m->m_max_mds, sizeof(*m->m_info), GFP_NOFS); + m->m_info = kcalloc(m->m_num_mds, sizeof(*m->m_info), GFP_NOFS); if (m->m_info == NULL) goto nomem; @@ -207,9 +208,20 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) ceph_pr_addr(&addr.in_addr), ceph_mds_state_name(state)); - if (mds < 0 || mds >= m->m_max_mds || state <= 0) + if (mds < 0 || state <= 0) continue; + if (mds >= m->m_num_mds) { + int new_num = max(mds + 1, m->m_num_mds * 2); + void *new_m_info = krealloc(m->m_info, + new_num * sizeof(*m->m_info), + GFP_NOFS | __GFP_ZERO); + if (!new_m_info) + goto nomem; + m->m_info = new_m_info; + m->m_num_mds = new_num; + } + info = &m->m_info[mds]; info->global_id = global_id; info->state = state; @@ -229,6 +241,14 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) info->export_targets = NULL; } } + if (m->m_num_mds > m->m_max_mds) { + /* find max up mds */ + for (i = m->m_num_mds; i >= m->m_max_mds; i--) { + if (i == 0 || m->m_info[i-1].state > 0) + break; + } + m->m_num_mds = i; + } /* pg_pools */ ceph_decode_32_safe(p, end, n, bad); @@ -270,12 +290,22 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) for (i = 0; i < n; i++) { s32 mds = ceph_decode_32(p); - if (mds >= 0 && mds < m->m_max_mds) { + if (mds >= 0 && mds < m->m_num_mds) { if (m->m_info[mds].laggy) num_laggy++; } } m->m_num_laggy = num_laggy; + + if (n > m->m_num_mds) { + void *new_m_info = krealloc(m->m_info, + n * sizeof(*m->m_info), + GFP_NOFS | __GFP_ZERO); + if (!new_m_info) + goto nomem; + m->m_info = new_m_info; + } + m->m_num_mds = n; } /* inc */ @@ -341,7 +371,7 @@ void ceph_mdsmap_destroy(struct ceph_mdsmap *m) { int i; - for (i = 0; i < m->m_max_mds; i++) + for (i = 0; i < m->m_num_mds; i++) kfree(m->m_info[i].export_targets); kfree(m->m_info); kfree(m->m_data_pg_pools); @@ -357,7 +387,7 @@ bool ceph_mdsmap_is_cluster_available(struct ceph_mdsmap *m) return false; if (m->m_num_laggy > 0) return false; - for (i = 0; i < m->m_max_mds; i++) { + for (i = 0; i < m->m_num_mds; i++) { if (m->m_info[i].state == CEPH_MDS_STATE_ACTIVE) nr_active++; } diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 8f8b41c2ef0f..dab5d6732345 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -519,7 +519,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) capsnap->need_flush ? "" : "no_flush"); ihold(inode); - atomic_set(&capsnap->nref, 1); + refcount_set(&capsnap->nref, 1); INIT_LIST_HEAD(&capsnap->ci_item); capsnap->follows = old_snapc->seq; diff --git a/fs/ceph/super.c b/fs/ceph/super.c index a8c81b2052ca..8d7918ce694a 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -544,10 +544,6 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, struct ceph_options *opt) { struct ceph_fs_client *fsc; - const u64 supported_features = - CEPH_FEATURE_FLOCK | CEPH_FEATURE_DIRLAYOUTHASH | - CEPH_FEATURE_MDSENC | CEPH_FEATURE_MDS_INLINE_DATA; - const u64 required_features = 0; int page_count; size_t size; int err = -ENOMEM; @@ -556,8 +552,7 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, if (!fsc) return ERR_PTR(-ENOMEM); - fsc->client = ceph_create_client(opt, fsc, supported_features, - required_features); + fsc->client = ceph_create_client(opt, fsc); if (IS_ERR(fsc->client)) { err = PTR_ERR(fsc->client); goto fail; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 176186b12457..a973acd8beaf 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -14,6 +14,7 @@ #include <linux/writeback.h> #include <linux/slab.h> #include <linux/posix_acl.h> +#include <linux/refcount.h> #include <linux/ceph/libceph.h> @@ -160,7 +161,7 @@ struct ceph_cap_flush { * data before flushing the snapped state (tracked here) back to the MDS. */ struct ceph_cap_snap { - atomic_t nref; + refcount_t nref; struct list_head ci_item; struct ceph_cap_flush cap_flush; @@ -189,7 +190,7 @@ struct ceph_cap_snap { static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap) { - if (atomic_dec_and_test(&capsnap->nref)) { + if (refcount_dec_and_test(&capsnap->nref)) { if (capsnap->xattr_blob) ceph_buffer_put(capsnap->xattr_blob); kfree(capsnap); @@ -471,6 +472,32 @@ static inline struct inode *ceph_find_inode(struct super_block *sb, #define CEPH_I_CAP_DROPPED (1 << 8) /* caps were forcibly dropped */ #define CEPH_I_KICK_FLUSH (1 << 9) /* kick flushing caps */ #define CEPH_I_FLUSH_SNAPS (1 << 10) /* need flush snapss */ +#define CEPH_I_ERROR_WRITE (1 << 11) /* have seen write errors */ + +/* + * We set the ERROR_WRITE bit when we start seeing write errors on an inode + * and then clear it when they start succeeding. Note that we do a lockless + * check first, and only take the lock if it looks like it needs to be changed. + * The write submission code just takes this as a hint, so we're not too + * worried if a few slip through in either direction. + */ +static inline void ceph_set_error_write(struct ceph_inode_info *ci) +{ + if (!(READ_ONCE(ci->i_ceph_flags) & CEPH_I_ERROR_WRITE)) { + spin_lock(&ci->i_ceph_lock); + ci->i_ceph_flags |= CEPH_I_ERROR_WRITE; + spin_unlock(&ci->i_ceph_lock); + } +} + +static inline void ceph_clear_error_write(struct ceph_inode_info *ci) +{ + if (READ_ONCE(ci->i_ceph_flags) & CEPH_I_ERROR_WRITE) { + spin_lock(&ci->i_ceph_lock); + ci->i_ceph_flags &= ~CEPH_I_ERROR_WRITE; + spin_unlock(&ci->i_ceph_lock); + } +} static inline void __ceph_dir_set_complete(struct ceph_inode_info *ci, long long release_count, diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index febc28f9e2c2..75267cdd5dfd 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -392,6 +392,7 @@ static int __set_xattr(struct ceph_inode_info *ci, if (update_xattr) { int err = 0; + if (xattr && (flags & XATTR_CREATE)) err = -EEXIST; else if (!xattr && (flags & XATTR_REPLACE)) @@ -399,12 +400,14 @@ static int __set_xattr(struct ceph_inode_info *ci, if (err) { kfree(name); kfree(val); + kfree(*newxattr); return err; } if (update_xattr < 0) { if (xattr) __remove_xattr(ci, xattr); kfree(name); + kfree(*newxattr); return 0; } } diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 11d087b2b28e..6116d5275a3e 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -833,7 +833,7 @@ static int compat_ioctl_preallocate(struct file *file, */ #define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff) -#define COMPATIBLE_IOCTL(cmd) XFORM(cmd), +#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd), /* ioctl should not be warned about even if it's not implemented. Valid reasons to use this: - It is implemented with ->compat_ioctl on some device, but programs diff --git a/fs/dcache.c b/fs/dcache.c index 95d71eda8142..cddf39777835 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -419,6 +419,8 @@ static void dentry_lru_add(struct dentry *dentry) { if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) d_lru_add(dentry); + else if (unlikely(!(dentry->d_flags & DCACHE_REFERENCED))) + dentry->d_flags |= DCACHE_REFERENCED; } /** @@ -779,8 +781,6 @@ repeat: goto kill_it; } - if (!(dentry->d_flags & DCACHE_REFERENCED)) - dentry->d_flags |= DCACHE_REFERENCED; dentry_lru_add(dentry); dentry->d_lockref.count--; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 7fd4ec4bb214..e892ae7d89f8 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -199,7 +199,7 @@ static const struct dentry_operations debugfs_dops = { static int debug_fill_super(struct super_block *sb, void *data, int silent) { - static struct tree_descr debug_files[] = {{""}}; + static const struct tree_descr debug_files[] = {{""}}; struct debugfs_fs_info *fsi; int err; diff --git a/fs/fcntl.c b/fs/fcntl.c index 8bd81c2e89b2..f4e7267d117f 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -899,16 +899,10 @@ static int __init fcntl_init(void) * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ - BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( - O_RDONLY | O_WRONLY | O_RDWR | - O_CREAT | O_EXCL | O_NOCTTY | - O_TRUNC | O_APPEND | /* O_NONBLOCK | */ - __O_SYNC | O_DSYNC | FASYNC | - O_DIRECT | O_LARGEFILE | O_DIRECTORY | - O_NOFOLLOW | O_NOATIME | O_CLOEXEC | - __FMODE_EXEC | O_PATH | __O_TMPFILE | - __FMODE_NONOTIFY - )); + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != + HWEIGHT32( + (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | + __FMODE_EXEC | __FMODE_NONOTIFY)); fasync_cache = kmem_cache_create("fasync_cache", sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL); diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 6e22748b0704..b9ea99c5b5b3 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -292,7 +292,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) { - struct tree_descr empty_descr = {""}; + static const struct tree_descr empty_descr = {""}; struct fuse_conn *fc; int err; diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index c2d7f3a92679..c16d00e53264 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -20,6 +20,7 @@ #include <linux/pipe_fs_i.h> #include <linux/swap.h> #include <linux/splice.h> +#include <linux/sched.h> MODULE_ALIAS_MISCDEV(FUSE_MINOR); MODULE_ALIAS("devname:fuse"); @@ -45,7 +46,7 @@ static void fuse_request_init(struct fuse_req *req, struct page **pages, INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->intr_entry); init_waitqueue_head(&req->waitq); - atomic_set(&req->count, 1); + refcount_set(&req->count, 1); req->pages = pages; req->page_descs = page_descs; req->max_pages = npages; @@ -102,21 +103,20 @@ void fuse_request_free(struct fuse_req *req) void __fuse_get_request(struct fuse_req *req) { - atomic_inc(&req->count); + refcount_inc(&req->count); } /* Must be called with > 1 refcount */ static void __fuse_put_request(struct fuse_req *req) { - BUG_ON(atomic_read(&req->count) < 2); - atomic_dec(&req->count); + refcount_dec(&req->count); } -static void fuse_req_init_context(struct fuse_req *req) +static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req) { req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid()); req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid()); - req->in.h.pid = current->pid; + req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); } void fuse_set_initialized(struct fuse_conn *fc) @@ -163,7 +163,7 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, goto out; } - fuse_req_init_context(req); + fuse_req_init_context(fc, req); __set_bit(FR_WAITING, &req->flags); if (for_background) __set_bit(FR_BACKGROUND, &req->flags); @@ -256,7 +256,7 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, if (!req) req = get_reserved_req(fc, file); - fuse_req_init_context(req); + fuse_req_init_context(fc, req); __set_bit(FR_WAITING, &req->flags); __clear_bit(FR_BACKGROUND, &req->flags); return req; @@ -264,7 +264,7 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) { - if (atomic_dec_and_test(&req->count)) { + if (refcount_dec_and_test(&req->count)) { if (test_bit(FR_BACKGROUND, &req->flags)) { /* * We get here in the unlikely case that a background @@ -1222,6 +1222,9 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, struct fuse_in *in; unsigned reqsize; + if (task_active_pid_ns(current) != fc->pid_ns) + return -EIO; + restart: spin_lock(&fiq->waitq.lock); err = -EAGAIN; @@ -1820,6 +1823,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, struct fuse_req *req; struct fuse_out_header oh; + if (task_active_pid_ns(current) != fc->pid_ns) + return -EIO; + if (nbytes < sizeof(struct fuse_out_header)) return -EINVAL; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index ec238fb5a584..aa93f09ae6e6 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -58,7 +58,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) } INIT_LIST_HEAD(&ff->write_entry); - atomic_set(&ff->count, 1); + refcount_set(&ff->count, 1); RB_CLEAR_NODE(&ff->polled_node); init_waitqueue_head(&ff->poll_wait); @@ -77,7 +77,7 @@ void fuse_file_free(struct fuse_file *ff) static struct fuse_file *fuse_file_get(struct fuse_file *ff) { - atomic_inc(&ff->count); + refcount_inc(&ff->count); return ff; } @@ -88,7 +88,7 @@ static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) static void fuse_file_put(struct fuse_file *ff, bool sync) { - if (atomic_dec_and_test(&ff->count)) { + if (refcount_dec_and_test(&ff->count)) { struct fuse_req *req = ff->reserved_req; if (ff->fc->no_open) { @@ -293,7 +293,7 @@ static int fuse_release(struct inode *inode, struct file *file) void fuse_sync_release(struct fuse_file *ff, int flags) { - WARN_ON(atomic_read(&ff->count) != 1); + WARN_ON(refcount_read(&ff->count) > 1); fuse_prepare_release(ff, flags, FUSE_RELEASE); /* * iput(NULL) is a no-op and since the refcount is 1 and everything's @@ -2083,7 +2083,8 @@ static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma) return generic_file_mmap(file, vma); } -static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, +static int convert_fuse_file_lock(struct fuse_conn *fc, + const struct fuse_file_lock *ffl, struct file_lock *fl) { switch (ffl->type) { @@ -2098,7 +2099,14 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, fl->fl_start = ffl->start; fl->fl_end = ffl->end; - fl->fl_pid = ffl->pid; + + /* + * Convert pid into the caller's pid namespace. If the pid + * does not map into the namespace fl_pid will get set to 0. + */ + rcu_read_lock(); + fl->fl_pid = pid_vnr(find_pid_ns(ffl->pid, fc->pid_ns)); + rcu_read_unlock(); break; default: @@ -2147,7 +2155,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl) args.out.args[0].value = &outarg; err = fuse_simple_request(fc, &args); if (!err) - err = convert_fuse_file_lock(&outarg.lk, fl); + err = convert_fuse_file_lock(fc, &outarg.lk, fl); return err; } @@ -2159,7 +2167,8 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock) FUSE_ARGS(args); struct fuse_lk_in inarg; int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK; - pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0; + struct pid *pid = fl->fl_type != F_UNLCK ? task_tgid(current) : NULL; + pid_t pid_nr = pid_nr_ns(pid, fc->pid_ns); int err; if (fl->fl_lmops && fl->fl_lmops->lm_grant) { @@ -2171,7 +2180,10 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock) if (fl->fl_flags & FL_CLOSE) return 0; - fuse_lk_fill(&args, file, fl, opcode, pid, flock, &inarg); + if (pid && pid_nr == 0) + return -EOVERFLOW; + + fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg); err = fuse_simple_request(fc, &args); /* locking is restartable */ diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index f33341d9501a..1bd7ffdad593 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -24,6 +24,8 @@ #include <linux/workqueue.h> #include <linux/kref.h> #include <linux/xattr.h> +#include <linux/pid_namespace.h> +#include <linux/refcount.h> /** Max number of pages that can be used in a single read request */ #define FUSE_MAX_PAGES_PER_REQ 32 @@ -137,7 +139,7 @@ struct fuse_file { u64 nodeid; /** Refcount */ - atomic_t count; + refcount_t count; /** FOPEN_* flags returned by open */ u32 open_flags; @@ -306,7 +308,7 @@ struct fuse_req { struct list_head intr_entry; /** refcount */ - atomic_t count; + refcount_t count; /** Unique ID for the interrupt request */ u64 intr_unique; @@ -448,7 +450,7 @@ struct fuse_conn { spinlock_t lock; /** Refcount */ - atomic_t count; + refcount_t count; /** Number of fuse_dev's */ atomic_t dev_count; @@ -461,6 +463,9 @@ struct fuse_conn { /** The group id for this mount */ kgid_t group_id; + /** The pid namespace for this mount */ + struct pid_namespace *pid_ns; + /** Maximum read size */ unsigned max_read; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 73cf05135252..5a1b58f8fef4 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -21,6 +21,7 @@ #include <linux/sched.h> #include <linux/exportfs.h> #include <linux/posix_acl.h> +#include <linux/pid_namespace.h> MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); MODULE_DESCRIPTION("Filesystem in Userspace"); @@ -601,7 +602,7 @@ void fuse_conn_init(struct fuse_conn *fc) memset(fc, 0, sizeof(*fc)); spin_lock_init(&fc->lock); init_rwsem(&fc->killsb); - atomic_set(&fc->count, 1); + refcount_set(&fc->count, 1); atomic_set(&fc->dev_count, 1); init_waitqueue_head(&fc->blocked_waitq); init_waitqueue_head(&fc->reserved_req_waitq); @@ -619,14 +620,16 @@ void fuse_conn_init(struct fuse_conn *fc) fc->connected = 1; fc->attr_version = 1; get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); + fc->pid_ns = get_pid_ns(task_active_pid_ns(current)); } EXPORT_SYMBOL_GPL(fuse_conn_init); void fuse_conn_put(struct fuse_conn *fc) { - if (atomic_dec_and_test(&fc->count)) { + if (refcount_dec_and_test(&fc->count)) { if (fc->destroy_req) fuse_request_free(fc->destroy_req); + put_pid_ns(fc->pid_ns); fc->release(fc); } } @@ -634,7 +637,7 @@ EXPORT_SYMBOL_GPL(fuse_conn_put); struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) { - atomic_inc(&fc->count); + refcount_inc(&fc->count); return fc; } EXPORT_SYMBOL_GPL(fuse_conn_get); diff --git a/fs/inode.c b/fs/inode.c index 6ad1edb52045..db5914783a71 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -402,6 +402,8 @@ static void inode_lru_list_add(struct inode *inode) { if (list_lru_add(&inode->i_sb->s_inode_lru, &inode->i_lru)) this_cpu_inc(nr_unused); + else + inode->i_state |= I_REFERENCED; } /* @@ -1489,7 +1491,6 @@ static void iput_final(struct inode *inode) drop = generic_drop_inode(inode); if (!drop && (sb->s_flags & MS_ACTIVE)) { - inode->i_state |= I_REFERENCED; inode_add_lru(inode); spin_unlock(&inode->i_lock); return; diff --git a/fs/internal.h b/fs/internal.h index 076751d90ba2..9676fe11c093 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -126,8 +126,6 @@ static inline bool atime_needs_update_rcu(const struct path *path, return __atime_needs_update(path, inode, true); } -extern bool atime_needs_update_rcu(const struct path *, struct inode *); - /* * fs-writeback.c */ diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 5a0245e36240..ebad34266bcf 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -2363,7 +2363,7 @@ static int jbd2_journal_init_journal_head_cache(void) jbd2_journal_head_cache = kmem_cache_create("jbd2_journal_head", sizeof(struct journal_head), 0, /* offset */ - SLAB_TEMPORARY | SLAB_DESTROY_BY_RCU, + SLAB_TEMPORARY | SLAB_TYPESAFE_BY_RCU, NULL); /* ctor */ retval = 0; if (!jbd2_journal_head_cache) { diff --git a/fs/libfs.c b/fs/libfs.c index a8b62e5d43a9..a04395334bb1 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -507,7 +507,7 @@ EXPORT_SYMBOL(simple_write_end); * to pass it an appropriate max_reserved value to avoid collisions. */ int simple_fill_super(struct super_block *s, unsigned long magic, - struct tree_descr *files) + const struct tree_descr *files) { struct inode *inode; struct dentry *root; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 8bf8f667a8cf..6493df6b1bd5 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1146,7 +1146,7 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size) static int nfsd_fill_super(struct super_block * sb, void * data, int silent) { - static struct tree_descr nfsd_files[] = { + static const struct tree_descr nfsd_files[] = { [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO}, [NFSD_Export_features] = {"export_features", &export_features_operations, S_IRUGO}, diff --git a/fs/open.c b/fs/open.c index 4d23f729dcc6..6d2d2b33ac54 100644 --- a/fs/open.c +++ b/fs/open.c @@ -193,7 +193,8 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) goto out_putf; error = -EPERM; - if (IS_APPEND(inode)) + /* Check IS_APPEND on real upper inode */ + if (IS_APPEND(file_inode(f.file))) goto out_putf; sb_start_write(inode->i_sb); @@ -900,6 +901,12 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o int lookup_flags = 0; int acc_mode = ACC_MODE(flags); + /* + * Clear out all open flags we don't know about so that we don't report + * them in fcntl(F_GETFD) or similar interfaces. + */ + flags &= VALID_OPEN_FLAGS; + if (flags & (O_CREAT | __O_TMPFILE)) op->mode = (mode & S_IALLUGO) | S_IFREG; else diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 906ea6c93260..9008ab9fbd2e 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -20,6 +20,7 @@ #include <linux/namei.h> #include <linux/fdtable.h> #include <linux/ratelimit.h> +#include <linux/exportfs.h> #include "overlayfs.h" #include "ovl_entry.h" @@ -232,6 +233,79 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat) return err; } +static struct ovl_fh *ovl_encode_fh(struct dentry *lower, uuid_be *uuid) +{ + struct ovl_fh *fh; + int fh_type, fh_len, dwords; + void *buf; + int buflen = MAX_HANDLE_SZ; + + buf = kmalloc(buflen, GFP_TEMPORARY); + if (!buf) + return ERR_PTR(-ENOMEM); + + /* + * We encode a non-connectable file handle for non-dir, because we + * only need to find the lower inode number and we don't want to pay + * the price or reconnecting the dentry. + */ + dwords = buflen >> 2; + fh_type = exportfs_encode_fh(lower, buf, &dwords, 0); + buflen = (dwords << 2); + + fh = ERR_PTR(-EIO); + if (WARN_ON(fh_type < 0) || + WARN_ON(buflen > MAX_HANDLE_SZ) || + WARN_ON(fh_type == FILEID_INVALID)) + goto out; + + BUILD_BUG_ON(MAX_HANDLE_SZ + offsetof(struct ovl_fh, fid) > 255); + fh_len = offsetof(struct ovl_fh, fid) + buflen; + fh = kmalloc(fh_len, GFP_KERNEL); + if (!fh) { + fh = ERR_PTR(-ENOMEM); + goto out; + } + + fh->version = OVL_FH_VERSION; + fh->magic = OVL_FH_MAGIC; + fh->type = fh_type; + fh->flags = OVL_FH_FLAG_CPU_ENDIAN; + fh->len = fh_len; + fh->uuid = *uuid; + memcpy(fh->fid, buf, buflen); + +out: + kfree(buf); + return fh; +} + +static int ovl_set_origin(struct dentry *dentry, struct dentry *lower, + struct dentry *upper) +{ + struct super_block *sb = lower->d_sb; + uuid_be *uuid = (uuid_be *) &sb->s_uuid; + const struct ovl_fh *fh = NULL; + int err; + + /* + * When lower layer doesn't support export operations store a 'null' fh, + * so we can use the overlay.origin xattr to distignuish between a copy + * up and a pure upper inode. + */ + if (sb->s_export_op && sb->s_export_op->fh_to_dentry && + uuid_be_cmp(*uuid, NULL_UUID_BE)) { + fh = ovl_encode_fh(lower, uuid); + if (IS_ERR(fh)) + return PTR_ERR(fh); + } + + err = ovl_do_setxattr(upper, OVL_XATTR_ORIGIN, fh, fh ? fh->len : 0, 0); + kfree(fh); + + return err; +} + static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, struct dentry *dentry, struct path *lowerpath, struct kstat *stat, const char *link, @@ -316,6 +390,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, if (err) goto out_cleanup; + /* + * Store identifier of lower inode in upper inode xattr to + * allow lookup of the copy up origin inode. + */ + err = ovl_set_origin(dentry, lowerpath->dentry, temp); + if (err) + goto out_cleanup; + if (tmpfile) err = ovl_do_link(temp, udir, upper, true); else diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 6515796460df..723b98b90698 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -138,36 +138,6 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) return err; } -static int ovl_dir_getattr(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int flags) -{ - struct dentry *dentry = path->dentry; - int err; - enum ovl_path_type type; - struct path realpath; - const struct cred *old_cred; - - type = ovl_path_real(dentry, &realpath); - old_cred = ovl_override_creds(dentry->d_sb); - err = vfs_getattr(&realpath, stat, request_mask, flags); - revert_creds(old_cred); - if (err) - return err; - - stat->dev = dentry->d_sb->s_dev; - stat->ino = dentry->d_inode->i_ino; - - /* - * It's probably not worth it to count subdirs to get the - * correct link count. nlink=1 seems to pacify 'find' and - * other utilities. - */ - if (OVL_TYPE_MERGE(type)) - stat->nlink = 1; - - return 0; -} - /* Common operations required to be done after creation of file on upper */ static void ovl_instantiate(struct dentry *dentry, struct inode *inode, struct dentry *newdentry, bool hardlink) @@ -182,6 +152,9 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode, inc_nlink(inode); } d_instantiate(dentry, inode); + /* Force lookup of new upper hardlink to find its lower */ + if (hardlink) + d_drop(dentry); } static bool ovl_type_merge(struct dentry *dentry) @@ -210,7 +183,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, if (err) goto out_dput; - if (ovl_type_merge(dentry->d_parent)) { + if (ovl_type_merge(dentry->d_parent) && d_is_dir(newdentry)) { /* Setting opaque here is just an optimization, allow to fail */ ovl_set_opaque(dentry, newdentry); } @@ -1070,7 +1043,7 @@ const struct inode_operations ovl_dir_inode_operations = { .create = ovl_create, .mknod = ovl_mknod, .permission = ovl_permission, - .getattr = ovl_dir_getattr, + .getattr = ovl_getattr, .listxattr = ovl_listxattr, .get_acl = ovl_get_acl, .update_time = ovl_update_time, diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index f8fe6bf2036d..ad9547f82da5 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -57,18 +57,78 @@ out: return err; } -static int ovl_getattr(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int flags) +int ovl_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int flags) { struct dentry *dentry = path->dentry; + enum ovl_path_type type; struct path realpath; const struct cred *old_cred; + bool is_dir = S_ISDIR(dentry->d_inode->i_mode); int err; - ovl_path_real(dentry, &realpath); + type = ovl_path_real(dentry, &realpath); old_cred = ovl_override_creds(dentry->d_sb); err = vfs_getattr(&realpath, stat, request_mask, flags); + if (err) + goto out; + + /* + * When all layers are on the same fs, all real inode number are + * unique, so we use the overlay st_dev, which is friendly to du -x. + * + * We also use st_ino of the copy up origin, if we know it. + * This guaranties constant st_dev/st_ino across copy up. + * + * If filesystem supports NFS export ops, this also guaranties + * persistent st_ino across mount cycle. + */ + if (ovl_same_sb(dentry->d_sb)) { + if (OVL_TYPE_ORIGIN(type)) { + struct kstat lowerstat; + u32 lowermask = STATX_INO | (!is_dir ? STATX_NLINK : 0); + + ovl_path_lower(dentry, &realpath); + err = vfs_getattr(&realpath, &lowerstat, + lowermask, flags); + if (err) + goto out; + + WARN_ON_ONCE(stat->dev != lowerstat.dev); + /* + * Lower hardlinks are broken on copy up to different + * upper files, so we cannot use the lower origin st_ino + * for those different files, even for the same fs case. + */ + if (is_dir || lowerstat.nlink == 1) + stat->ino = lowerstat.ino; + } + stat->dev = dentry->d_sb->s_dev; + } else if (is_dir) { + /* + * If not all layers are on the same fs the pair {real st_ino; + * overlay st_dev} is not unique, so use the non persistent + * overlay st_ino. + * + * Always use the overlay st_dev for directories, so 'find + * -xdev' will scan the entire overlay mount and won't cross the + * overlay mount boundaries. + */ + stat->dev = dentry->d_sb->s_dev; + stat->ino = dentry->d_inode->i_ino; + } + + /* + * It's probably not worth it to count subdirs to get the + * correct link count. nlink=1 seems to pacify 'find' and + * other utilities. + */ + if (is_dir && OVL_TYPE_MERGE(type)) + stat->nlink = 1; + +out: revert_creds(old_cred); + return err; } @@ -303,6 +363,41 @@ static const struct inode_operations ovl_symlink_inode_operations = { .update_time = ovl_update_time, }; +/* + * It is possible to stack overlayfs instance on top of another + * overlayfs instance as lower layer. We need to annonate the + * stackable i_mutex locks according to stack level of the super + * block instance. An overlayfs instance can never be in stack + * depth 0 (there is always a real fs below it). An overlayfs + * inode lock will use the lockdep annotaion ovl_i_mutex_key[depth]. + * + * For example, here is a snip from /proc/lockdep_chains after + * dir_iterate of nested overlayfs: + * + * [...] &ovl_i_mutex_dir_key[depth] (stack_depth=2) + * [...] &ovl_i_mutex_dir_key[depth]#2 (stack_depth=1) + * [...] &type->i_mutex_dir_key (stack_depth=0) + */ +#define OVL_MAX_NESTING FILESYSTEM_MAX_STACK_DEPTH + +static inline void ovl_lockdep_annotate_inode_mutex_key(struct inode *inode) +{ +#ifdef CONFIG_LOCKDEP + static struct lock_class_key ovl_i_mutex_key[OVL_MAX_NESTING]; + static struct lock_class_key ovl_i_mutex_dir_key[OVL_MAX_NESTING]; + + int depth = inode->i_sb->s_stack_depth - 1; + + if (WARN_ON_ONCE(depth < 0 || depth >= OVL_MAX_NESTING)) + depth = 0; + + if (S_ISDIR(inode->i_mode)) + lockdep_set_class(&inode->i_rwsem, &ovl_i_mutex_dir_key[depth]); + else + lockdep_set_class(&inode->i_rwsem, &ovl_i_mutex_key[depth]); +#endif +} + static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev) { inode->i_ino = get_next_ino(); @@ -312,6 +407,8 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev) inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE; #endif + ovl_lockdep_annotate_inode_mutex_key(inode); + switch (mode & S_IFMT) { case S_IFREG: inode->i_op = &ovl_file_inode_operations; diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index b8b077821fb0..bad0f665a635 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -12,6 +12,8 @@ #include <linux/namei.h> #include <linux/xattr.h> #include <linux/ratelimit.h> +#include <linux/mount.h> +#include <linux/exportfs.h> #include "overlayfs.h" #include "ovl_entry.h" @@ -81,6 +83,90 @@ invalid: goto err_free; } +static int ovl_acceptable(void *ctx, struct dentry *dentry) +{ + return 1; +} + +static struct dentry *ovl_get_origin(struct dentry *dentry, + struct vfsmount *mnt) +{ + int res; + struct ovl_fh *fh = NULL; + struct dentry *origin = NULL; + int bytes; + + res = vfs_getxattr(dentry, OVL_XATTR_ORIGIN, NULL, 0); + if (res < 0) { + if (res == -ENODATA || res == -EOPNOTSUPP) + return NULL; + goto fail; + } + /* Zero size value means "copied up but origin unknown" */ + if (res == 0) + return NULL; + + fh = kzalloc(res, GFP_TEMPORARY); + if (!fh) + return ERR_PTR(-ENOMEM); + + res = vfs_getxattr(dentry, OVL_XATTR_ORIGIN, fh, res); + if (res < 0) + goto fail; + + if (res < sizeof(struct ovl_fh) || res < fh->len) + goto invalid; + + if (fh->magic != OVL_FH_MAGIC) + goto invalid; + + /* Treat larger version and unknown flags as "origin unknown" */ + if (fh->version > OVL_FH_VERSION || fh->flags & ~OVL_FH_FLAG_ALL) + goto out; + + /* Treat endianness mismatch as "origin unknown" */ + if (!(fh->flags & OVL_FH_FLAG_ANY_ENDIAN) && + (fh->flags & OVL_FH_FLAG_BIG_ENDIAN) != OVL_FH_FLAG_CPU_ENDIAN) + goto out; + + bytes = (fh->len - offsetof(struct ovl_fh, fid)); + + /* + * Make sure that the stored uuid matches the uuid of the lower + * layer where file handle will be decoded. + */ + if (uuid_be_cmp(fh->uuid, *(uuid_be *) &mnt->mnt_sb->s_uuid)) + goto out; + + origin = exportfs_decode_fh(mnt, (struct fid *)fh->fid, + bytes >> 2, (int)fh->type, + ovl_acceptable, NULL); + if (IS_ERR(origin)) { + /* Treat stale file handle as "origin unknown" */ + if (origin == ERR_PTR(-ESTALE)) + origin = NULL; + goto out; + } + + if (ovl_dentry_weird(origin) || + ((d_inode(origin)->i_mode ^ d_inode(dentry)->i_mode) & S_IFMT)) { + dput(origin); + origin = NULL; + goto invalid; + } + +out: + kfree(fh); + return origin; + +fail: + pr_warn_ratelimited("overlayfs: failed to get origin (%i)\n", res); + goto out; +invalid: + pr_warn_ratelimited("overlayfs: invalid origin (%*phN)\n", res, fh); + goto out; +} + static bool ovl_is_opaquedir(struct dentry *dentry) { int res; @@ -192,6 +278,45 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, return 0; } + +static int ovl_check_origin(struct dentry *dentry, struct dentry *upperdentry, + struct path **stackp, unsigned int *ctrp) +{ + struct super_block *same_sb = ovl_same_sb(dentry->d_sb); + struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata; + struct vfsmount *mnt; + struct dentry *origin; + + if (!same_sb || !roe->numlower) + return 0; + + /* + * Since all layers are on the same fs, we use the first layer for + * decoding the file handle. We may get a disconnected dentry, + * which is fine, because we only need to hold the origin inode in + * cache and use its inode number. We may even get a connected dentry, + * that is not under the first layer's root. That is also fine for + * using it's inode number - it's the same as if we held a reference + * to a dentry in first layer that was moved under us. + */ + mnt = roe->lowerstack[0].mnt; + + origin = ovl_get_origin(upperdentry, mnt); + if (IS_ERR_OR_NULL(origin)) + return PTR_ERR(origin); + + BUG_ON(*stackp || *ctrp); + *stackp = kmalloc(sizeof(struct path), GFP_TEMPORARY); + if (!*stackp) { + dput(origin); + return -ENOMEM; + } + **stackp = (struct path) { .dentry = origin, .mnt = mnt }; + *ctrp = 1; + + return 0; +} + /* * Returns next layer in stack starting from top. * Returns -1 if this is the last layer. @@ -220,6 +345,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, const struct cred *old_cred; struct ovl_fs *ofs = dentry->d_sb->s_fs_info; struct ovl_entry *poe = dentry->d_parent->d_fsdata; + struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata; struct path *stack = NULL; struct dentry *upperdir, *upperdentry = NULL; unsigned int ctr = 0; @@ -253,13 +379,20 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, err = -EREMOTE; goto out; } + if (upperdentry && !d.is_dir) { + BUG_ON(!d.stop || d.redirect); + err = ovl_check_origin(dentry, upperdentry, + &stack, &ctr); + if (err) + goto out; + } if (d.redirect) { upperredirect = kstrdup(d.redirect, GFP_KERNEL); if (!upperredirect) goto out_put_upper; if (d.redirect[0] == '/') - poe = dentry->d_sb->s_root->d_fsdata; + poe = roe; } upperopaque = d.opaque; } @@ -290,10 +423,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, if (d.stop) break; - if (d.redirect && - d.redirect[0] == '/' && - poe != dentry->d_sb->s_root->d_fsdata) { - poe = dentry->d_sb->s_root->d_fsdata; + if (d.redirect && d.redirect[0] == '/' && poe != roe) { + poe = roe; /* Find the current layer on the root dentry */ for (i = 0; i < poe->numlower; i++) diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 741dc0b6931f..caa36cb9c46d 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -8,18 +8,56 @@ */ #include <linux/kernel.h> +#include <linux/uuid.h> enum ovl_path_type { __OVL_PATH_UPPER = (1 << 0), __OVL_PATH_MERGE = (1 << 1), + __OVL_PATH_ORIGIN = (1 << 2), }; #define OVL_TYPE_UPPER(type) ((type) & __OVL_PATH_UPPER) #define OVL_TYPE_MERGE(type) ((type) & __OVL_PATH_MERGE) +#define OVL_TYPE_ORIGIN(type) ((type) & __OVL_PATH_ORIGIN) #define OVL_XATTR_PREFIX XATTR_TRUSTED_PREFIX "overlay." #define OVL_XATTR_OPAQUE OVL_XATTR_PREFIX "opaque" #define OVL_XATTR_REDIRECT OVL_XATTR_PREFIX "redirect" +#define OVL_XATTR_ORIGIN OVL_XATTR_PREFIX "origin" + +/* + * The tuple (fh,uuid) is a universal unique identifier for a copy up origin, + * where: + * origin.fh - exported file handle of the lower file + * origin.uuid - uuid of the lower filesystem + */ +#define OVL_FH_VERSION 0 +#define OVL_FH_MAGIC 0xfb + +/* CPU byte order required for fid decoding: */ +#define OVL_FH_FLAG_BIG_ENDIAN (1 << 0) +#define OVL_FH_FLAG_ANY_ENDIAN (1 << 1) + +#define OVL_FH_FLAG_ALL (OVL_FH_FLAG_BIG_ENDIAN | OVL_FH_FLAG_ANY_ENDIAN) + +#if defined(__LITTLE_ENDIAN) +#define OVL_FH_FLAG_CPU_ENDIAN 0 +#elif defined(__BIG_ENDIAN) +#define OVL_FH_FLAG_CPU_ENDIAN OVL_FH_FLAG_BIG_ENDIAN +#else +#error Endianness not defined +#endif + +/* On-disk and in-memeory format for redirect by file handle */ +struct ovl_fh { + u8 version; /* 0 */ + u8 magic; /* 0xfb */ + u8 len; /* size of this header + size of fid */ + u8 flags; /* OVL_FH_FLAG_* */ + u8 type; /* fid_type of fid */ + uuid_be uuid; /* uuid of filesystem */ + u8 fid[0]; /* file identifier */ +} __packed; #define OVL_ISUPPER_MASK 1UL @@ -151,6 +189,7 @@ int ovl_want_write(struct dentry *dentry); void ovl_drop_write(struct dentry *dentry); struct dentry *ovl_workdir(struct dentry *dentry); const struct cred *ovl_override_creds(struct super_block *sb); +struct super_block *ovl_same_sb(struct super_block *sb); struct ovl_entry *ovl_alloc_entry(unsigned int numlower); bool ovl_dentry_remote(struct dentry *dentry); bool ovl_dentry_weird(struct dentry *dentry); @@ -197,6 +236,8 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt, /* inode.c */ int ovl_setattr(struct dentry *dentry, struct iattr *attr); +int ovl_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int flags); int ovl_permission(struct inode *inode, int mask); int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 59614faa14c3..b2023ddb8532 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -29,6 +29,8 @@ struct ovl_fs { const struct cred *creator_cred; bool tmpfile; wait_queue_head_t copyup_wq; + /* sb common to all layers */ + struct super_block *same_sb; }; /* private information held for every overlayfs dentry */ diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index c9e70d39c1ea..9828b7de8999 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -49,11 +49,28 @@ static void ovl_dentry_release(struct dentry *dentry) } } +static int ovl_check_append_only(struct inode *inode, int flag) +{ + /* + * This test was moot in vfs may_open() because overlay inode does + * not have the S_APPEND flag, so re-check on real upper inode + */ + if (IS_APPEND(inode)) { + if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND)) + return -EPERM; + if (flag & O_TRUNC) + return -EPERM; + } + + return 0; +} + static struct dentry *ovl_d_real(struct dentry *dentry, const struct inode *inode, unsigned int open_flags) { struct dentry *real; + int err; if (!d_is_reg(dentry)) { if (!inode || inode == d_inode(dentry)) @@ -65,15 +82,20 @@ static struct dentry *ovl_d_real(struct dentry *dentry, return dentry; if (open_flags) { - int err = ovl_open_maybe_copy_up(dentry, open_flags); - + err = ovl_open_maybe_copy_up(dentry, open_flags); if (err) return ERR_PTR(err); } real = ovl_dentry_upper(dentry); - if (real && (!inode || inode == d_inode(real))) + if (real && (!inode || inode == d_inode(real))) { + if (!inode) { + err = ovl_check_append_only(d_inode(real), open_flags); + if (err) + return ERR_PTR(err); + } return real; + } real = ovl_dentry_lower(dentry); if (!real) @@ -709,8 +731,8 @@ static const struct xattr_handler *ovl_xattr_handlers[] = { static int ovl_fill_super(struct super_block *sb, void *data, int silent) { - struct path upperpath = { NULL, NULL }; - struct path workpath = { NULL, NULL }; + struct path upperpath = { }; + struct path workpath = { }; struct dentry *root_dentry; struct inode *realinode; struct ovl_entry *oe; @@ -892,11 +914,19 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ufs->lower_mnt[ufs->numlower] = mnt; ufs->numlower++; + + /* Check if all lower layers are on same sb */ + if (i == 0) + ufs->same_sb = mnt->mnt_sb; + else if (ufs->same_sb != mnt->mnt_sb) + ufs->same_sb = NULL; } /* If the upper fs is nonexistent, we mark overlayfs r/o too */ if (!ufs->upper_mnt) sb->s_flags |= MS_RDONLY; + else if (ufs->upper_mnt->mnt_sb != ufs->same_sb) + ufs->same_sb = NULL; if (remote) sb->s_d_op = &ovl_reval_dentry_operations; diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 6e610a205e15..cfdea47313a1 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -40,6 +40,13 @@ const struct cred *ovl_override_creds(struct super_block *sb) return override_creds(ofs->creator_cred); } +struct super_block *ovl_same_sb(struct super_block *sb) +{ + struct ovl_fs *ofs = sb->s_fs_info; + + return ofs->same_sb; +} + struct ovl_entry *ovl_alloc_entry(unsigned int numlower) { size_t size = offsetof(struct ovl_entry, lowerstack[numlower]); @@ -75,11 +82,13 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry) type = __OVL_PATH_UPPER; /* - * Non-dir dentry can hold lower dentry from previous - * location. + * Non-dir dentry can hold lower dentry of its copy up origin. */ - if (oe->numlower && d_is_dir(dentry)) - type |= __OVL_PATH_MERGE; + if (oe->numlower) { + type |= __OVL_PATH_ORIGIN; + if (d_is_dir(dentry)) + type |= __OVL_PATH_MERGE; + } } else { if (oe->numlower > 1) type |= __OVL_PATH_MERGE; @@ -100,7 +109,7 @@ void ovl_path_lower(struct dentry *dentry, struct path *path) { struct ovl_entry *oe = dentry->d_fsdata; - *path = oe->numlower ? oe->lowerstack[0] : (struct path) { NULL, NULL }; + *path = oe->numlower ? oe->lowerstack[0] : (struct path) { }; } enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) diff --git a/fs/proc/base.c b/fs/proc/base.c index 9e3ac5c11780..45f6bf68fff3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -821,10 +821,7 @@ static ssize_t mem_rw(struct file *file, char __user *buf, if (!mmget_not_zero(mm)) goto free; - /* Maybe we should limit FOLL_FORCE to actual ptrace users? */ - flags = FOLL_FORCE; - if (write) - flags |= FOLL_WRITE; + flags = write ? FOLL_WRITE : 0; while (count > 0) { int this_len = min_t(int, count, PAGE_SIZE); diff --git a/fs/signalfd.c b/fs/signalfd.c index 270221fcef42..7e3d71109f51 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -38,7 +38,7 @@ void signalfd_cleanup(struct sighand_struct *sighand) /* * The lockless check can race with remove_wait_queue() in progress, * but in this case its caller should run under rcu_read_lock() and - * sighand_cachep is SLAB_DESTROY_BY_RCU, we can safely return. + * sighand_cachep is SLAB_TYPESAFE_BY_RCU, we can safely return. */ if (likely(!waitqueue_active(wqh))) return; diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 21d36d284735..328e89c2cf83 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -266,7 +266,7 @@ static const struct super_operations tracefs_super_operations = { static int trace_fill_super(struct super_block *sb, void *data, int silent) { - static struct tree_descr trace_files[] = {{""}}; + static const struct tree_descr trace_files[] = {{""}}; struct tracefs_fs_info *fsi; int err; diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 07740072da55..6db3b4668b1a 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -78,6 +78,7 @@ #define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */ #define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */ #define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */ +#define ACPI_MAX_COMMENT_CACHE_DEPTH 96 /* Comments for the -ca option */ /* * Should the subsystem abort the loading of an ACPI table if the diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 2fc678e08d8d..197f3fffc9a7 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -577,7 +577,7 @@ struct acpi_pci_root { bool acpi_dma_supported(struct acpi_device *adev); enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev); -void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr); +int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr); void acpi_dma_deconfigure(struct device *dev); struct acpi_device *acpi_find_child_device(struct acpi_device *parent, @@ -588,6 +588,15 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); int acpi_disable_wakeup_device_power(struct acpi_device *dev); +#ifdef CONFIG_X86 +bool acpi_device_always_present(struct acpi_device *adev); +#else +static inline bool acpi_device_always_present(struct acpi_device *adev) +{ + return false; +} +#endif + #ifdef CONFIG_PM acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, void (*work_func)(struct work_struct *work)); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 3795386ea706..15c86ce4df53 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20170119 +#define ACPI_CA_VERSION 0x20170303 #include <acpi/acconfig.h> #include <acpi/actypes.h> diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 0ff3c64ce924..faa9f2c0d5de 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -87,6 +87,7 @@ #define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */ #define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */ #define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */ +#define ACPI_SIG_XXXX "XXXX" /* Intermediate AML header for ASL/ASL+ converter */ #ifdef ACPI_UNDEFINED_TABLES /* @@ -783,6 +784,15 @@ struct acpi_iort_smmu { #define ACPI_IORT_SMMU_DVM_SUPPORTED (1) #define ACPI_IORT_SMMU_COHERENT_WALK (1<<1) +/* Global interrupt format */ + +struct acpi_iort_smmu_gsi { + u32 nsg_irpt; + u32 nsg_irpt_flags; + u32 nsg_cfg_irpt; + u32 nsg_cfg_irpt_flags; +}; + struct acpi_iort_smmu_v3 { u64 base_address; /* SMMUv3 base address */ u32 flags; diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 3558f4eb1a86..314a0b9219c6 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -566,7 +566,6 @@ IRQCHIP_OF_MATCH_TABLE() \ ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(clksrc) \ - ACPI_PROBE_TABLE(iort) \ EARLYCON_TABLE() #define INIT_TEXT \ diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h index 63f4c2c44a1f..3190e30b9398 100644 --- a/include/dt-bindings/clock/gxbb-clkc.h +++ b/include/dt-bindings/clock/gxbb-clkc.h @@ -10,6 +10,7 @@ #define CLKID_FCLK_DIV2 4 #define CLKID_FCLK_DIV3 5 #define CLKID_FCLK_DIV4 6 +#define CLKID_GP0_PLL 9 #define CLKID_CLK81 12 #define CLKID_MPLL2 15 #define CLKID_I2C 22 @@ -17,6 +18,10 @@ #define CLKID_RNG0 25 #define CLKID_SPI 34 #define CLKID_ETH 36 +#define CLKID_AIU_GLUE 38 +#define CLKID_I2S_OUT 40 +#define CLKID_MIXER_IFACE 44 +#define CLKID_AIU 47 #define CLKID_USB0 50 #define CLKID_USB1 51 #define CLKID_USB 55 @@ -25,11 +30,17 @@ #define CLKID_USB0_DDR_BRIDGE 65 #define CLKID_SANA 69 #define CLKID_GCLK_VENCI_INT0 77 +#define CLKID_AOCLK_GATE 80 #define CLKID_AO_I2C 93 #define CLKID_SD_EMMC_A 94 #define CLKID_SD_EMMC_B 95 #define CLKID_SD_EMMC_C 96 #define CLKID_SAR_ADC_CLK 97 #define CLKID_SAR_ADC_SEL 98 +#define CLKID_MALI_0_SEL 100 +#define CLKID_MALI_0 102 +#define CLKID_MALI_1_SEL 103 +#define CLKID_MALI_1 105 +#define CLKID_MALI 106 #endif /* __GXBB_CLKC_H */ diff --git a/include/dt-bindings/clock/r7s72100-clock.h b/include/dt-bindings/clock/r7s72100-clock.h index ce09915c298f..bc256d31099a 100644 --- a/include/dt-bindings/clock/r7s72100-clock.h +++ b/include/dt-bindings/clock/r7s72100-clock.h @@ -29,6 +29,9 @@ #define R7S72100_CLK_OSTM0 1 #define R7S72100_CLK_OSTM1 0 +/* MSTP6 */ +#define R7S72100_CLK_RTC 0 + /* MSTP7 */ #define R7S72100_CLK_ETHER 4 @@ -49,7 +52,9 @@ #define R7S72100_CLK_SPI4 3 /* MSTP12 */ -#define R7S72100_CLK_SDHI0 3 -#define R7S72100_CLK_SDHI1 2 +#define R7S72100_CLK_SDHI00 3 +#define R7S72100_CLK_SDHI01 2 +#define R7S72100_CLK_SDHI10 1 +#define R7S72100_CLK_SDHI11 0 #endif /* __DT_BINDINGS_CLOCK_R7S72100_H__ */ diff --git a/include/dt-bindings/clock/r8a73a4-clock.h b/include/dt-bindings/clock/r8a73a4-clock.h index dd11ecdf837e..4b3668157257 100644 --- a/include/dt-bindings/clock/r8a73a4-clock.h +++ b/include/dt-bindings/clock/r8a73a4-clock.h @@ -54,6 +54,7 @@ #define R8A73A4_CLK_IIC3 11 #define R8A73A4_CLK_IIC4 10 #define R8A73A4_CLK_IIC5 9 +#define R8A73A4_CLK_INTC_SYS 8 #define R8A73A4_CLK_IRQC 7 /* MSTP5 */ diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index fa5e8da809f2..20641fa68e73 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -82,6 +82,7 @@ /* MSTP4 */ #define R8A7790_CLK_IRQC 7 +#define R8A7790_CLK_INTC_SYS 8 /* MSTP5 */ #define R8A7790_CLK_AUDIO_DMAC1 1 diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h index ffa11379b3f0..adc50dc31ab3 100644 --- a/include/dt-bindings/clock/r8a7791-clock.h +++ b/include/dt-bindings/clock/r8a7791-clock.h @@ -72,6 +72,7 @@ /* MSTP4 */ #define R8A7791_CLK_IRQC 7 +#define R8A7791_CLK_INTC_SYS 8 /* MSTP5 */ #define R8A7791_CLK_AUDIO_DMAC1 1 diff --git a/include/dt-bindings/clock/r8a7792-clock.h b/include/dt-bindings/clock/r8a7792-clock.h index 9a8b392ceb00..5be90bc23bd7 100644 --- a/include/dt-bindings/clock/r8a7792-clock.h +++ b/include/dt-bindings/clock/r8a7792-clock.h @@ -17,7 +17,6 @@ #define R8A7792_CLK_PLL3 3 #define R8A7792_CLK_LB 4 #define R8A7792_CLK_QSPI 5 -#define R8A7792_CLK_Z 6 /* MSTP0 */ #define R8A7792_CLK_MSIOF0 0 @@ -45,6 +44,7 @@ /* MSTP4 */ #define R8A7792_CLK_IRQC 7 +#define R8A7792_CLK_INTC_SYS 8 /* MSTP5 */ #define R8A7792_CLK_AUDIO_DMAC0 2 diff --git a/include/dt-bindings/clock/r8a7793-clock.h b/include/dt-bindings/clock/r8a7793-clock.h index efcbc594fe82..7318d45d4e7e 100644 --- a/include/dt-bindings/clock/r8a7793-clock.h +++ b/include/dt-bindings/clock/r8a7793-clock.h @@ -77,10 +77,11 @@ /* MSTP4 */ #define R8A7793_CLK_IRQC 7 +#define R8A7793_CLK_INTC_SYS 8 /* MSTP5 */ -#define R8A7793_CLK_AUDIO_DMAC1 1 -#define R8A7793_CLK_AUDIO_DMAC0 2 +#define R8A7793_CLK_AUDIO_DMAC1 1 +#define R8A7793_CLK_AUDIO_DMAC0 2 #define R8A7793_CLK_ADSP_MOD 6 #define R8A7793_CLK_THERMAL 22 #define R8A7793_CLK_PWM 23 diff --git a/include/dt-bindings/clock/r8a7794-clock.h b/include/dt-bindings/clock/r8a7794-clock.h index 88e64846cf37..93e99c3ffc8d 100644 --- a/include/dt-bindings/clock/r8a7794-clock.h +++ b/include/dt-bindings/clock/r8a7794-clock.h @@ -64,6 +64,7 @@ /* MSTP4 */ #define R8A7794_CLK_IRQC 7 +#define R8A7794_CLK_INTC_SYS 8 /* MSTP5 */ #define R8A7794_CLK_AUDIO_DMAC0 2 @@ -81,6 +82,7 @@ #define R8A7794_CLK_SCIF2 19 #define R8A7794_CLK_SCIF1 20 #define R8A7794_CLK_SCIF0 21 +#define R8A7794_CLK_DU1 23 #define R8A7794_CLK_DU0 24 /* MSTP8 */ diff --git a/include/dt-bindings/genpd/k2g.h b/include/dt-bindings/genpd/k2g.h new file mode 100644 index 000000000000..1f31f17e19eb --- /dev/null +++ b/include/dt-bindings/genpd/k2g.h @@ -0,0 +1,90 @@ +/* + * TI K2G SoC Device definitions + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 _DT_BINDINGS_GENPD_K2G_H +#define _DT_BINDINGS_GENPD_K2G_H + +/* Documented in http://processors.wiki.ti.com/index.php/TISCI */ + +#define K2G_DEV_PMMC0 0x0000 +#define K2G_DEV_MLB0 0x0001 +#define K2G_DEV_DSS0 0x0002 +#define K2G_DEV_MCBSP0 0x0003 +#define K2G_DEV_MCASP0 0x0004 +#define K2G_DEV_MCASP1 0x0005 +#define K2G_DEV_MCASP2 0x0006 +#define K2G_DEV_DCAN0 0x0008 +#define K2G_DEV_DCAN1 0x0009 +#define K2G_DEV_EMIF0 0x000a +#define K2G_DEV_MMCHS0 0x000b +#define K2G_DEV_MMCHS1 0x000c +#define K2G_DEV_GPMC0 0x000d +#define K2G_DEV_ELM0 0x000e +#define K2G_DEV_SPI0 0x0010 +#define K2G_DEV_SPI1 0x0011 +#define K2G_DEV_SPI2 0x0012 +#define K2G_DEV_SPI3 0x0013 +#define K2G_DEV_ICSS0 0x0014 +#define K2G_DEV_ICSS1 0x0015 +#define K2G_DEV_USB0 0x0016 +#define K2G_DEV_USB1 0x0017 +#define K2G_DEV_NSS0 0x0018 +#define K2G_DEV_PCIE0 0x0019 +#define K2G_DEV_GPIO0 0x001b +#define K2G_DEV_GPIO1 0x001c +#define K2G_DEV_TIMER64_0 0x001d +#define K2G_DEV_TIMER64_1 0x001e +#define K2G_DEV_TIMER64_2 0x001f +#define K2G_DEV_TIMER64_3 0x0020 +#define K2G_DEV_TIMER64_4 0x0021 +#define K2G_DEV_TIMER64_5 0x0022 +#define K2G_DEV_TIMER64_6 0x0023 +#define K2G_DEV_MSGMGR0 0x0025 +#define K2G_DEV_BOOTCFG0 0x0026 +#define K2G_DEV_ARM_BOOTROM0 0x0027 +#define K2G_DEV_DSP_BOOTROM0 0x0029 +#define K2G_DEV_DEBUGSS0 0x002b +#define K2G_DEV_UART0 0x002c +#define K2G_DEV_UART1 0x002d +#define K2G_DEV_UART2 0x002e +#define K2G_DEV_EHRPWM0 0x002f +#define K2G_DEV_EHRPWM1 0x0030 +#define K2G_DEV_EHRPWM2 0x0031 +#define K2G_DEV_EHRPWM3 0x0032 +#define K2G_DEV_EHRPWM4 0x0033 +#define K2G_DEV_EHRPWM5 0x0034 +#define K2G_DEV_EQEP0 0x0035 +#define K2G_DEV_EQEP1 0x0036 +#define K2G_DEV_EQEP2 0x0037 +#define K2G_DEV_ECAP0 0x0038 +#define K2G_DEV_ECAP1 0x0039 +#define K2G_DEV_I2C0 0x003a +#define K2G_DEV_I2C1 0x003b +#define K2G_DEV_I2C2 0x003c +#define K2G_DEV_EDMA0 0x003f +#define K2G_DEV_SEMAPHORE0 0x0040 +#define K2G_DEV_INTC0 0x0041 +#define K2G_DEV_GIC0 0x0042 +#define K2G_DEV_QSPI0 0x0043 +#define K2G_DEV_ARM_64B_COUNTER0 0x0044 +#define K2G_DEV_TETRIS0 0x0045 +#define K2G_DEV_CGEM0 0x0046 +#define K2G_DEV_MSMC0 0x0047 +#define K2G_DEV_CBASS0 0x0049 +#define K2G_DEV_BOARD0 0x004c +#define K2G_DEV_EDMA1 0x004f + +#endif diff --git a/include/dt-bindings/mfd/stm32f7-rcc.h b/include/dt-bindings/mfd/stm32f7-rcc.h new file mode 100644 index 000000000000..e36cc69959c7 --- /dev/null +++ b/include/dt-bindings/mfd/stm32f7-rcc.h @@ -0,0 +1,112 @@ +/* + * This header provides constants for the STM32F7 RCC IP + */ + +#ifndef _DT_BINDINGS_MFD_STM32F7_RCC_H +#define _DT_BINDINGS_MFD_STM32F7_RCC_H + +/* AHB1 */ +#define STM32F7_RCC_AHB1_GPIOA 0 +#define STM32F7_RCC_AHB1_GPIOB 1 +#define STM32F7_RCC_AHB1_GPIOC 2 +#define STM32F7_RCC_AHB1_GPIOD 3 +#define STM32F7_RCC_AHB1_GPIOE 4 +#define STM32F7_RCC_AHB1_GPIOF 5 +#define STM32F7_RCC_AHB1_GPIOG 6 +#define STM32F7_RCC_AHB1_GPIOH 7 +#define STM32F7_RCC_AHB1_GPIOI 8 +#define STM32F7_RCC_AHB1_GPIOJ 9 +#define STM32F7_RCC_AHB1_GPIOK 10 +#define STM32F7_RCC_AHB1_CRC 12 +#define STM32F7_RCC_AHB1_BKPSRAM 18 +#define STM32F7_RCC_AHB1_DTCMRAM 20 +#define STM32F7_RCC_AHB1_DMA1 21 +#define STM32F7_RCC_AHB1_DMA2 22 +#define STM32F7_RCC_AHB1_DMA2D 23 +#define STM32F7_RCC_AHB1_ETHMAC 25 +#define STM32F7_RCC_AHB1_ETHMACTX 26 +#define STM32F7_RCC_AHB1_ETHMACRX 27 +#define STM32FF_RCC_AHB1_ETHMACPTP 28 +#define STM32F7_RCC_AHB1_OTGHS 29 +#define STM32F7_RCC_AHB1_OTGHSULPI 30 + +#define STM32F7_AHB1_RESET(bit) (STM32F7_RCC_AHB1_##bit + (0x10 * 8)) +#define STM32F7_AHB1_CLOCK(bit) (STM32F7_RCC_AHB1_##bit) + + +/* AHB2 */ +#define STM32F7_RCC_AHB2_DCMI 0 +#define STM32F7_RCC_AHB2_CRYP 4 +#define STM32F7_RCC_AHB2_HASH 5 +#define STM32F7_RCC_AHB2_RNG 6 +#define STM32F7_RCC_AHB2_OTGFS 7 + +#define STM32F7_AHB2_RESET(bit) (STM32F7_RCC_AHB2_##bit + (0x14 * 8)) +#define STM32F7_AHB2_CLOCK(bit) (STM32F7_RCC_AHB2_##bit + 0x20) + +/* AHB3 */ +#define STM32F7_RCC_AHB3_FMC 0 +#define STM32F7_RCC_AHB3_QSPI 1 + +#define STM32F7_AHB3_RESET(bit) (STM32F7_RCC_AHB3_##bit + (0x18 * 8)) +#define STM32F7_AHB3_CLOCK(bit) (STM32F7_RCC_AHB3_##bit + 0x40) + +/* APB1 */ +#define STM32F7_RCC_APB1_TIM2 0 +#define STM32F7_RCC_APB1_TIM3 1 +#define STM32F7_RCC_APB1_TIM4 2 +#define STM32F7_RCC_APB1_TIM5 3 +#define STM32F7_RCC_APB1_TIM6 4 +#define STM32F7_RCC_APB1_TIM7 5 +#define STM32F7_RCC_APB1_TIM12 6 +#define STM32F7_RCC_APB1_TIM13 7 +#define STM32F7_RCC_APB1_TIM14 8 +#define STM32F7_RCC_APB1_LPTIM1 9 +#define STM32F7_RCC_APB1_WWDG 11 +#define STM32F7_RCC_APB1_SPI2 14 +#define STM32F7_RCC_APB1_SPI3 15 +#define STM32F7_RCC_APB1_SPDIFRX 16 +#define STM32F7_RCC_APB1_UART2 17 +#define STM32F7_RCC_APB1_UART3 18 +#define STM32F7_RCC_APB1_UART4 19 +#define STM32F7_RCC_APB1_UART5 20 +#define STM32F7_RCC_APB1_I2C1 21 +#define STM32F7_RCC_APB1_I2C2 22 +#define STM32F7_RCC_APB1_I2C3 23 +#define STM32F7_RCC_APB1_I2C4 24 +#define STM32F7_RCC_APB1_CAN1 25 +#define STM32F7_RCC_APB1_CAN2 26 +#define STM32F7_RCC_APB1_CEC 27 +#define STM32F7_RCC_APB1_PWR 28 +#define STM32F7_RCC_APB1_DAC 29 +#define STM32F7_RCC_APB1_UART7 30 +#define STM32F7_RCC_APB1_UART8 31 + +#define STM32F7_APB1_RESET(bit) (STM32F7_RCC_APB1_##bit + (0x20 * 8)) +#define STM32F7_APB1_CLOCK(bit) (STM32F7_RCC_APB1_##bit + 0x80) + +/* APB2 */ +#define STM32F7_RCC_APB2_TIM1 0 +#define STM32F7_RCC_APB2_TIM8 1 +#define STM32F7_RCC_APB2_USART1 4 +#define STM32F7_RCC_APB2_USART6 5 +#define STM32F7_RCC_APB2_ADC1 8 +#define STM32F7_RCC_APB2_ADC2 9 +#define STM32F7_RCC_APB2_ADC3 10 +#define STM32F7_RCC_APB2_SDMMC1 11 +#define STM32F7_RCC_APB2_SPI1 12 +#define STM32F7_RCC_APB2_SPI4 13 +#define STM32F7_RCC_APB2_SYSCFG 14 +#define STM32F7_RCC_APB2_TIM9 16 +#define STM32F7_RCC_APB2_TIM10 17 +#define STM32F7_RCC_APB2_TIM11 18 +#define STM32F7_RCC_APB2_SPI5 20 +#define STM32F7_RCC_APB2_SPI6 21 +#define STM32F7_RCC_APB2_SAI1 22 +#define STM32F7_RCC_APB2_SAI2 23 +#define STM32F7_RCC_APB2_LTDC 26 + +#define STM32F7_APB2_RESET(bit) (STM32F7_RCC_APB2_##bit + (0x24 * 8)) +#define STM32F7_APB2_CLOCK(bit) (STM32F7_RCC_APB2_##bit + 0xA0) + +#endif /* _DT_BINDINGS_MFD_STM32F7_RCC_H */ diff --git a/include/dt-bindings/pinctrl/hisi.h b/include/dt-bindings/pinctrl/hisi.h index 38f1ea879ea1..0359bfdc9119 100644 --- a/include/dt-bindings/pinctrl/hisi.h +++ b/include/dt-bindings/pinctrl/hisi.h @@ -56,4 +56,19 @@ #define DRIVE4_08MA (4 << 4) #define DRIVE4_10MA (6 << 4) +/* drive strength definition for hi3660 */ +#define DRIVE6_MASK (15 << 4) +#define DRIVE6_04MA (0 << 4) +#define DRIVE6_12MA (4 << 4) +#define DRIVE6_19MA (8 << 4) +#define DRIVE6_27MA (10 << 4) +#define DRIVE6_32MA (15 << 4) +#define DRIVE7_02MA (0 << 4) +#define DRIVE7_04MA (1 << 4) +#define DRIVE7_06MA (2 << 4) +#define DRIVE7_08MA (3 << 4) +#define DRIVE7_10MA (4 << 4) +#define DRIVE7_12MA (5 << 4) +#define DRIVE7_14MA (6 << 4) +#define DRIVE7_16MA (7 << 4) #endif diff --git a/include/dt-bindings/power/imx7-power.h b/include/dt-bindings/power/imx7-power.h new file mode 100644 index 000000000000..3a181e410517 --- /dev/null +++ b/include/dt-bindings/power/imx7-power.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2017 Impinj + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DT_BINDINGS_IMX7_POWER_H__ +#define __DT_BINDINGS_IMX7_POWER_H__ + +#define IMX7_POWER_DOMAIN_MIPI_PHY 0 +#define IMX7_POWER_DOMAIN_PCIE_PHY 1 +#define IMX7_POWER_DOMAIN_USB_HSIC_PHY 2 + +#endif diff --git a/include/dt-bindings/power/r8a7795-sysc.h b/include/dt-bindings/power/r8a7795-sysc.h index ee2e26ba605e..ad679eeda137 100644 --- a/include/dt-bindings/power/r8a7795-sysc.h +++ b/include/dt-bindings/power/r8a7795-sysc.h @@ -33,7 +33,7 @@ #define R8A7795_PD_CA53_SCU 21 #define R8A7795_PD_3DG_E 22 #define R8A7795_PD_A3IR 24 -#define R8A7795_PD_A2VC0 25 +#define R8A7795_PD_A2VC0 25 /* ES1.x only */ #define R8A7795_PD_A2VC1 26 /* Always-on power area */ diff --git a/include/dt-bindings/reset/altr,rst-mgr-a10sr.h b/include/dt-bindings/reset/altr,rst-mgr-a10sr.h new file mode 100644 index 000000000000..9855925e5256 --- /dev/null +++ b/include/dt-bindings/reset/altr,rst-mgr-a10sr.h @@ -0,0 +1,33 @@ +/* + * Copyright Intel Corporation (C) 2017. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + * Reset binding definitions for Altera Arria10 MAX5 System Resource Chip + * + * Adapted from altr,rst-mgr-a10.h + */ + +#ifndef _DT_BINDINGS_RESET_ALTR_RST_MGR_A10SR_H +#define _DT_BINDINGS_RESET_ALTR_RST_MGR_A10SR_H + +/* Peripheral PHY resets */ +#define A10SR_RESET_ENET_HPS 0 +#define A10SR_RESET_PCIE 1 +#define A10SR_RESET_FILE 2 +#define A10SR_RESET_BQSPI 3 +#define A10SR_RESET_USB 4 + +#define A10SR_RESET_NUM 5 + +#endif diff --git a/include/dt-bindings/reset/imx7-reset.h b/include/dt-bindings/reset/imx7-reset.h new file mode 100644 index 000000000000..63948170c7b2 --- /dev/null +++ b/include/dt-bindings/reset/imx7-reset.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 Impinj, Inc. + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DT_BINDING_RESET_IMX7_H +#define DT_BINDING_RESET_IMX7_H + +#define IMX7_RESET_A7_CORE_POR_RESET0 0 +#define IMX7_RESET_A7_CORE_POR_RESET1 1 +#define IMX7_RESET_A7_CORE_RESET0 2 +#define IMX7_RESET_A7_CORE_RESET1 3 +#define IMX7_RESET_A7_DBG_RESET0 4 +#define IMX7_RESET_A7_DBG_RESET1 5 +#define IMX7_RESET_A7_ETM_RESET0 6 +#define IMX7_RESET_A7_ETM_RESET1 7 +#define IMX7_RESET_A7_SOC_DBG_RESET 8 +#define IMX7_RESET_A7_L2RESET 9 +#define IMX7_RESET_SW_M4C_RST 10 +#define IMX7_RESET_SW_M4P_RST 11 +#define IMX7_RESET_EIM_RST 12 +#define IMX7_RESET_HSICPHY_PORT_RST 13 +#define IMX7_RESET_USBPHY1_POR 14 +#define IMX7_RESET_USBPHY1_PORT_RST 15 +#define IMX7_RESET_USBPHY2_POR 16 +#define IMX7_RESET_USBPHY2_PORT_RST 17 +#define IMX7_RESET_MIPI_PHY_MRST 18 +#define IMX7_RESET_MIPI_PHY_SRST 19 + +/* + * IMX7_RESET_PCIEPHY is a logical reset line combining PCIEPHY_BTN + * and PCIEPHY_G_RST + */ +#define IMX7_RESET_PCIEPHY 20 +#define IMX7_RESET_PCIEPHY_PERST 21 + +/* + * IMX7_RESET_PCIE_CTRL_APPS_EN is not strictly a reset line, but it + * can be used to inhibit PCIe LTTSM, so, in a way, it can be thoguht + * of as one + */ +#define IMX7_RESET_PCIE_CTRL_APPS_EN 22 +#define IMX7_RESET_DDRC_PRST 23 +#define IMX7_RESET_DDRC_CORE_RST 24 + +#define IMX7_RESET_NUM 25 + +#endif + diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 0f9de30d725f..137e4a3d89c5 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -770,8 +770,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NOT_SUPPORTED; } -static inline void acpi_dma_configure(struct device *dev, - enum dev_dma_attr attr) { } +static inline int acpi_dma_configure(struct device *dev, + enum dev_dma_attr attr) +{ + return 0; +} static inline void acpi_dma_deconfigure(struct device *dev) { } diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 26e25d85eb3e..3ff9acea8616 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -55,7 +55,4 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) { return NULL; } #endif -#define IORT_ACPI_DECLARE(name, table_id, fn) \ - ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn) - #endif /* __ACPI_IORT_H__ */ diff --git a/include/linux/amba/pl080.h b/include/linux/amba/pl080.h index 91b84a7f0539..580b5323a717 100644 --- a/include/linux/amba/pl080.h +++ b/include/linux/amba/pl080.h @@ -38,24 +38,16 @@ #define PL080_SOFT_LSREQ (0x2C) #define PL080_CONFIG (0x30) -#define PL080_CONFIG_M2_BE (1 << 2) -#define PL080_CONFIG_M1_BE (1 << 1) -#define PL080_CONFIG_ENABLE (1 << 0) +#define PL080_CONFIG_M2_BE BIT(2) +#define PL080_CONFIG_M1_BE BIT(1) +#define PL080_CONFIG_ENABLE BIT(0) #define PL080_SYNC (0x34) /* Per channel configuration registers */ -#define PL080_Cx_STRIDE (0x20) +/* Per channel configuration registers */ #define PL080_Cx_BASE(x) ((0x100 + (x * 0x20))) -#define PL080_Cx_SRC_ADDR(x) ((0x100 + (x * 0x20))) -#define PL080_Cx_DST_ADDR(x) ((0x104 + (x * 0x20))) -#define PL080_Cx_LLI(x) ((0x108 + (x * 0x20))) -#define PL080_Cx_CONTROL(x) ((0x10C + (x * 0x20))) -#define PL080_Cx_CONFIG(x) ((0x110 + (x * 0x20))) -#define PL080S_Cx_CONTROL2(x) ((0x110 + (x * 0x20))) -#define PL080S_Cx_CONFIG(x) ((0x114 + (x * 0x20))) - #define PL080_CH_SRC_ADDR (0x00) #define PL080_CH_DST_ADDR (0x04) #define PL080_CH_LLI (0x08) @@ -66,18 +58,18 @@ #define PL080_LLI_ADDR_MASK (0x3fffffff << 2) #define PL080_LLI_ADDR_SHIFT (2) -#define PL080_LLI_LM_AHB2 (1 << 0) +#define PL080_LLI_LM_AHB2 BIT(0) -#define PL080_CONTROL_TC_IRQ_EN (1 << 31) +#define PL080_CONTROL_TC_IRQ_EN BIT(31) #define PL080_CONTROL_PROT_MASK (0x7 << 28) #define PL080_CONTROL_PROT_SHIFT (28) -#define PL080_CONTROL_PROT_CACHE (1 << 30) -#define PL080_CONTROL_PROT_BUFF (1 << 29) -#define PL080_CONTROL_PROT_SYS (1 << 28) -#define PL080_CONTROL_DST_INCR (1 << 27) -#define PL080_CONTROL_SRC_INCR (1 << 26) -#define PL080_CONTROL_DST_AHB2 (1 << 25) -#define PL080_CONTROL_SRC_AHB2 (1 << 24) +#define PL080_CONTROL_PROT_CACHE BIT(30) +#define PL080_CONTROL_PROT_BUFF BIT(29) +#define PL080_CONTROL_PROT_SYS BIT(28) +#define PL080_CONTROL_DST_INCR BIT(27) +#define PL080_CONTROL_SRC_INCR BIT(26) +#define PL080_CONTROL_DST_AHB2 BIT(25) +#define PL080_CONTROL_SRC_AHB2 BIT(24) #define PL080_CONTROL_DWIDTH_MASK (0x7 << 21) #define PL080_CONTROL_DWIDTH_SHIFT (21) #define PL080_CONTROL_SWIDTH_MASK (0x7 << 18) @@ -103,20 +95,20 @@ #define PL080_WIDTH_16BIT (0x1) #define PL080_WIDTH_32BIT (0x2) -#define PL080N_CONFIG_ITPROT (1 << 20) -#define PL080N_CONFIG_SECPROT (1 << 19) -#define PL080_CONFIG_HALT (1 << 18) -#define PL080_CONFIG_ACTIVE (1 << 17) /* RO */ -#define PL080_CONFIG_LOCK (1 << 16) -#define PL080_CONFIG_TC_IRQ_MASK (1 << 15) -#define PL080_CONFIG_ERR_IRQ_MASK (1 << 14) +#define PL080N_CONFIG_ITPROT BIT(20) +#define PL080N_CONFIG_SECPROT BIT(19) +#define PL080_CONFIG_HALT BIT(18) +#define PL080_CONFIG_ACTIVE BIT(17) /* RO */ +#define PL080_CONFIG_LOCK BIT(16) +#define PL080_CONFIG_TC_IRQ_MASK BIT(15) +#define PL080_CONFIG_ERR_IRQ_MASK BIT(14) #define PL080_CONFIG_FLOW_CONTROL_MASK (0x7 << 11) #define PL080_CONFIG_FLOW_CONTROL_SHIFT (11) #define PL080_CONFIG_DST_SEL_MASK (0xf << 6) #define PL080_CONFIG_DST_SEL_SHIFT (6) #define PL080_CONFIG_SRC_SEL_MASK (0xf << 1) #define PL080_CONFIG_SRC_SEL_SHIFT (1) -#define PL080_CONFIG_ENABLE (1 << 0) +#define PL080_CONFIG_ENABLE BIT(0) #define PL080_FLOW_MEM2MEM (0x0) #define PL080_FLOW_MEM2PER (0x1) diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h deleted file mode 100644 index fe93758e8403..000000000000 --- a/include/linux/amba/pl330.h +++ /dev/null @@ -1,35 +0,0 @@ -/* linux/include/linux/amba/pl330.h - * - * Copyright (C) 2010 Samsung Electronics Co. Ltd. - * Jaswinder Singh <jassi.brar@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __AMBA_PL330_H_ -#define __AMBA_PL330_H_ - -#include <linux/dmaengine.h> - -struct dma_pl330_platdata { - /* - * Number of valid peripherals connected to DMAC. - * This may be different from the value read from - * CR0, as the PL330 implementation might have 'holes' - * in the peri list or the peri could also be reached - * from another DMAC which the platform prefers. - */ - u8 nr_valid_peri; - /* Array of valid peripherals */ - u8 *peri_id; - /* Operational capabilities */ - dma_cap_mask_t cap_mask; - /* Bytes to allocate for MC buffer */ - unsigned mcbuf_sz; -}; - -extern bool pl330_filter(struct dma_chan *chan, void *param); -#endif /* __AMBA_PL330_H_ */ diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 79591c3660cc..bd029e52ef5e 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -196,8 +196,6 @@ void ll_rw_block(int, int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); int __sync_dirty_buffer(struct buffer_head *bh, int op_flags); void write_dirty_buffer(struct buffer_head *bh, int op_flags); -int _submit_bh(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags); int submit_bh(int, int, struct buffer_head *); void write_boundary_block(struct block_device *bdev, sector_t bblock, unsigned blocksize); diff --git a/include/linux/ceph/ceph_features.h b/include/linux/ceph/ceph_features.h index ae2f66833762..fd8b2953c78f 100644 --- a/include/linux/ceph/ceph_features.h +++ b/include/linux/ceph/ceph_features.h @@ -105,8 +105,10 @@ static inline u64 ceph_sanitize_features(u64 features) */ #define CEPH_FEATURES_SUPPORTED_DEFAULT \ (CEPH_FEATURE_NOSRCADDR | \ + CEPH_FEATURE_FLOCK | \ CEPH_FEATURE_SUBSCRIBE2 | \ CEPH_FEATURE_RECONNECT_SEQ | \ + CEPH_FEATURE_DIRLAYOUTHASH | \ CEPH_FEATURE_PGID64 | \ CEPH_FEATURE_PGPOOL3 | \ CEPH_FEATURE_OSDENC | \ @@ -114,11 +116,13 @@ static inline u64 ceph_sanitize_features(u64 features) CEPH_FEATURE_MSG_AUTH | \ CEPH_FEATURE_CRUSH_TUNABLES2 | \ CEPH_FEATURE_REPLY_CREATE_INODE | \ + CEPH_FEATURE_MDSENC | \ CEPH_FEATURE_OSDHASHPSPOOL | \ CEPH_FEATURE_OSD_CACHEPOOL | \ CEPH_FEATURE_CRUSH_V2 | \ CEPH_FEATURE_EXPORT_PEER | \ CEPH_FEATURE_OSDMAP_ENC | \ + CEPH_FEATURE_MDS_INLINE_DATA | \ CEPH_FEATURE_CRUSH_TUNABLES3 | \ CEPH_FEATURE_OSD_PRIMARY_AFFINITY | \ CEPH_FEATURE_MSGR_KEEPALIVE2 | \ diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index f4b2ee18f38c..ad078ebe25d6 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -365,6 +365,19 @@ extern const char *ceph_mds_op_name(int op); #define CEPH_READDIR_FRAG_END (1<<0) #define CEPH_READDIR_FRAG_COMPLETE (1<<8) #define CEPH_READDIR_HASH_ORDER (1<<9) +#define CEPH_READDIR_OFFSET_HASH (1<<10) + +/* + * open request flags + */ +#define CEPH_O_RDONLY 00000000 +#define CEPH_O_WRONLY 00000001 +#define CEPH_O_RDWR 00000002 +#define CEPH_O_CREAT 00000100 +#define CEPH_O_EXCL 00000200 +#define CEPH_O_TRUNC 00001000 +#define CEPH_O_DIRECTORY 00200000 +#define CEPH_O_NOFOLLOW 00400000 union ceph_mds_request_args { struct { @@ -384,6 +397,7 @@ union ceph_mds_request_args { __le32 max_entries; /* how many dentries to grab */ __le32 max_bytes; __le16 flags; + __le32 offset_hash; } __attribute__ ((packed)) readdir; struct { __le32 mode; diff --git a/include/linux/ceph/cls_lock_client.h b/include/linux/ceph/cls_lock_client.h index 84884d8d4710..0594d3bba774 100644 --- a/include/linux/ceph/cls_lock_client.h +++ b/include/linux/ceph/cls_lock_client.h @@ -37,6 +37,11 @@ int ceph_cls_break_lock(struct ceph_osd_client *osdc, struct ceph_object_locator *oloc, char *lock_name, char *cookie, struct ceph_entity_name *locker); +int ceph_cls_set_cookie(struct ceph_osd_client *osdc, + struct ceph_object_id *oid, + struct ceph_object_locator *oloc, + char *lock_name, u8 type, char *old_cookie, + char *tag, char *new_cookie); void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers); diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 88cd5dc8e238..3229ae6c7846 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -14,6 +14,7 @@ #include <linux/wait.h> #include <linux/writeback.h> #include <linux/slab.h> +#include <linux/refcount.h> #include <linux/ceph/types.h> #include <linux/ceph/messenger.h> @@ -161,7 +162,7 @@ struct ceph_client { * dirtied. */ struct ceph_snap_context { - atomic_t nref; + refcount_t nref; u64 seq; u32 num_snaps; u64 snaps[]; @@ -262,10 +263,7 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client); extern void ceph_destroy_options(struct ceph_options *opt); extern int ceph_compare_options(struct ceph_options *new_opt, struct ceph_client *client); -extern struct ceph_client *ceph_create_client(struct ceph_options *opt, - void *private, - u64 supported_features, - u64 required_features); +struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private); struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client); u64 ceph_client_gid(struct ceph_client *client); extern void ceph_destroy_client(struct ceph_client *client); diff --git a/include/linux/ceph/mdsmap.h b/include/linux/ceph/mdsmap.h index 8ed5dc505fbb..d5f783f3226a 100644 --- a/include/linux/ceph/mdsmap.h +++ b/include/linux/ceph/mdsmap.h @@ -25,6 +25,7 @@ struct ceph_mdsmap { u32 m_session_autoclose; /* seconds */ u64 m_max_file_size; u32 m_max_mds; /* size of m_addr, m_state arrays */ + int m_num_mds; struct ceph_mds_info *m_info; /* which object pools file data can be stored in */ @@ -40,7 +41,7 @@ struct ceph_mdsmap { static inline struct ceph_entity_addr * ceph_mdsmap_get_addr(struct ceph_mdsmap *m, int w) { - if (w >= m->m_max_mds) + if (w >= m->m_num_mds) return NULL; return &m->m_info[w].addr; } @@ -48,14 +49,14 @@ ceph_mdsmap_get_addr(struct ceph_mdsmap *m, int w) static inline int ceph_mdsmap_get_state(struct ceph_mdsmap *m, int w) { BUG_ON(w < 0); - if (w >= m->m_max_mds) + if (w >= m->m_num_mds) return CEPH_MDS_STATE_DNE; return m->m_info[w].state; } static inline bool ceph_mdsmap_is_laggy(struct ceph_mdsmap *m, int w) { - if (w >= 0 && w < m->m_max_mds) + if (w >= 0 && w < m->m_num_mds) return m->m_info[w].laggy; return false; } diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index c125b5d9e13c..85650b415e73 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -5,6 +5,7 @@ #include <linux/kref.h> #include <linux/mempool.h> #include <linux/rbtree.h> +#include <linux/refcount.h> #include <linux/ceph/types.h> #include <linux/ceph/osdmap.h> @@ -27,7 +28,7 @@ typedef void (*ceph_osdc_callback_t)(struct ceph_osd_request *); /* a given osd we're communicating with */ struct ceph_osd { - atomic_t o_ref; + refcount_t o_ref; struct ceph_osd_client *o_osdc; int o_osd; int o_incarnation; @@ -186,12 +187,12 @@ struct ceph_osd_request { struct timespec r_mtime; /* ditto */ u64 r_data_offset; /* ditto */ bool r_linger; /* don't resend on failure */ + bool r_abort_on_full; /* return ENOSPC when full */ /* internal */ unsigned long r_stamp; /* jiffies, send or check time */ unsigned long r_start_stamp; /* jiffies */ int r_attempts; - struct ceph_eversion r_replay_version; /* aka reassert_version */ u32 r_last_force_resend; u32 r_map_dne_bound; @@ -266,6 +267,7 @@ struct ceph_osd_client { struct rb_root osds; /* osds */ struct list_head osd_lru; /* idle osds */ spinlock_t osd_lru_lock; + u32 epoch_barrier; struct ceph_osd homeless_osd; atomic64_t last_tid; /* tid of last request */ u64 last_linger_id; @@ -304,6 +306,7 @@ extern void ceph_osdc_handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg); extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg); +void ceph_osdc_update_epoch_barrier(struct ceph_osd_client *osdc, u32 eb); extern void osd_req_op_init(struct ceph_osd_request *osd_req, unsigned int which, u16 opcode, u32 flags); diff --git a/include/linux/ceph/pagelist.h b/include/linux/ceph/pagelist.h index 13d71fe18b0c..75a7db21457d 100644 --- a/include/linux/ceph/pagelist.h +++ b/include/linux/ceph/pagelist.h @@ -2,7 +2,7 @@ #define __FS_CEPH_PAGELIST_H #include <asm/byteorder.h> -#include <linux/atomic.h> +#include <linux/refcount.h> #include <linux/list.h> #include <linux/types.h> @@ -13,7 +13,7 @@ struct ceph_pagelist { size_t room; struct list_head free_list; size_t num_pages_free; - atomic_t refcnt; + refcount_t refcnt; }; struct ceph_pagelist_cursor { @@ -30,7 +30,7 @@ static inline void ceph_pagelist_init(struct ceph_pagelist *pl) pl->room = 0; INIT_LIST_HEAD(&pl->free_list); pl->num_pages_free = 0; - atomic_set(&pl->refcnt, 1); + refcount_set(&pl->refcnt, 1); } extern void ceph_pagelist_release(struct ceph_pagelist *pl); diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 6048fa404e57..a5195a7d6f77 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -229,7 +229,7 @@ static inline struct dma_fence *dma_fence_get_rcu(struct dma_fence *fence) * * Function returns NULL if no refcount could be obtained, or the fence. * This function handles acquiring a reference to a fence that may be - * reallocated within the RCU grace period (such as with SLAB_DESTROY_BY_RCU), + * reallocated within the RCU grace period (such as with SLAB_TYPESAFE_BY_RCU), * so long as the caller is using RCU on the pointer to the fence. * * An alternative mechanism is to employ a seqlock to protect a bunch of @@ -257,7 +257,7 @@ dma_fence_get_rcu_safe(struct dma_fence * __rcu *fencep) * have successfully acquire a reference to it. If it no * longer matches, we are holding a reference to some other * reallocated pointer. This is possible if the allocator - * is using a freelist like SLAB_DESTROY_BY_RCU where the + * is using a freelist like SLAB_TYPESAFE_BY_RCU where the * fence remains valid for the RCU grace period, but it * may be reallocated. When using such allocators, we are * responsible for ensuring the reference we get is to diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h index 5725c94b1f12..4eac2670bfa1 100644 --- a/include/linux/dma-iommu.h +++ b/include/linux/dma-iommu.h @@ -20,6 +20,7 @@ #include <asm/errno.h> #ifdef CONFIG_IOMMU_DMA +#include <linux/dma-mapping.h> #include <linux/iommu.h> #include <linux/msi.h> @@ -71,6 +72,7 @@ int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); /* The DMA API isn't _quite_ the whole story, though... */ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg); +void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); #else @@ -100,6 +102,10 @@ static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) { } +static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) +{ +} + #endif /* CONFIG_IOMMU_DMA */ #endif /* __KERNEL__ */ #endif /* __DMA_IOMMU_H */ diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 0977317c6835..4f3eecedca2d 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -728,6 +728,18 @@ dma_mark_declared_memory_occupied(struct device *dev, } #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ +#ifdef CONFIG_HAS_DMA +int dma_configure(struct device *dev); +void dma_deconfigure(struct device *dev); +#else +static inline int dma_configure(struct device *dev) +{ + return 0; +} + +static inline void dma_deconfigure(struct device *dev) {} +#endif + /* * Managed DMA API */ diff --git a/include/linux/dma_remapping.h b/include/linux/dma_remapping.h index 187c10299722..90884072fa73 100644 --- a/include/linux/dma_remapping.h +++ b/include/linux/dma_remapping.h @@ -39,6 +39,7 @@ extern int iommu_calculate_agaw(struct intel_iommu *iommu); extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu); extern int dmar_disabled; extern int intel_iommu_enabled; +extern int intel_iommu_tboot_noforce; #else static inline int iommu_calculate_agaw(struct intel_iommu *iommu) { diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index 76ce329e656d..1b48d9c9a561 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h @@ -3,6 +3,12 @@ #include <uapi/linux/fcntl.h> +/* list of all valid flags for the open/openat flags argument: */ +#define VALID_OPEN_FLAGS \ + (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ + O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \ + FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) #ifndef force_o_largefile #define force_o_largefile() (BITS_PER_LONG != 32) diff --git a/include/linux/firmware/meson/meson_sm.h b/include/linux/firmware/meson/meson_sm.h index 8e953c6f394a..37a5eaea69dd 100644 --- a/include/linux/firmware/meson/meson_sm.h +++ b/include/linux/firmware/meson/meson_sm.h @@ -25,7 +25,7 @@ int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); int meson_sm_call_write(void *buffer, unsigned int b_size, unsigned int cmd_index, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); -int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0, u32 arg1, - u32 arg2, u32 arg3, u32 arg4); +int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index, + u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); #endif /* _MESON_SM_FW_H_ */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 249dad4e8d26..26488b419965 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -29,7 +29,6 @@ #include <linux/lockdep.h> #include <linux/percpu-rwsem.h> #include <linux/workqueue.h> -#include <linux/percpu-rwsem.h> #include <linux/delayed_call.h> #include <asm/byteorder.h> @@ -2925,17 +2924,19 @@ extern int vfs_statx_fd(unsigned int, struct kstat *, u32, unsigned int); static inline int vfs_stat(const char __user *filename, struct kstat *stat) { - return vfs_statx(AT_FDCWD, filename, 0, stat, STATX_BASIC_STATS); + return vfs_statx(AT_FDCWD, filename, AT_NO_AUTOMOUNT, + stat, STATX_BASIC_STATS); } static inline int vfs_lstat(const char __user *name, struct kstat *stat) { - return vfs_statx(AT_FDCWD, name, AT_SYMLINK_NOFOLLOW, + return vfs_statx(AT_FDCWD, name, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, stat, STATX_BASIC_STATS); } static inline int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, int flags) { - return vfs_statx(dfd, filename, flags, stat, STATX_BASIC_STATS); + return vfs_statx(dfd, filename, flags | AT_NO_AUTOMOUNT, + stat, STATX_BASIC_STATS); } static inline int vfs_fstat(int fd, struct kstat *stat) { @@ -3000,9 +3001,10 @@ extern const struct file_operations simple_dir_operations; extern const struct inode_operations simple_dir_inode_operations; extern void make_empty_dir_inode(struct inode *inode); extern bool is_empty_dir_inode(struct inode *inode); -struct tree_descr { char *name; const struct file_operations *ops; int mode; }; +struct tree_descr { const char *name; const struct file_operations *ops; int mode; }; struct dentry *d_alloc_name(struct dentry *, const char *); -extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); +extern int simple_fill_super(struct super_block *, unsigned long, + const struct tree_descr *); extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count); extern void simple_release_fs(struct vfsmount **mount, int *count); diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index c573a52ae440..485a5b48f038 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -30,6 +30,8 @@ #include <linux/mmu_notifier.h> #include <linux/list.h> #include <linux/iommu.h> +#include <linux/io-64-nonatomic-lo-hi.h> + #include <asm/cacheflush.h> #include <asm/iommu.h> @@ -72,24 +74,8 @@ #define OFFSET_STRIDE (9) -#ifdef CONFIG_64BIT #define dmar_readq(a) readq(a) #define dmar_writeq(a,v) writeq(v,a) -#else -static inline u64 dmar_readq(void __iomem *addr) -{ - u32 lo, hi; - lo = readl(addr); - hi = readl(addr + 4); - return (((u64) hi) << 32) + lo; -} - -static inline void dmar_writeq(void __iomem *addr, u64 val) -{ - writel((u32)val, addr); - writel((u32)(val >> 32), addr + 4); -} -#endif #define DMAR_VER_MAJOR(v) (((v) & 0xf0) >> 4) #define DMAR_VER_MINOR(v) ((v) & 0x0f) diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 2e4de0deee53..2cb54adc4a33 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -19,12 +19,12 @@ #ifndef __LINUX_IOMMU_H #define __LINUX_IOMMU_H +#include <linux/scatterlist.h> +#include <linux/device.h> +#include <linux/types.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/of.h> -#include <linux/types.h> -#include <linux/scatterlist.h> -#include <trace/events/iommu.h> #define IOMMU_READ (1 << 0) #define IOMMU_WRITE (1 << 1) @@ -32,10 +32,13 @@ #define IOMMU_NOEXEC (1 << 3) #define IOMMU_MMIO (1 << 4) /* e.g. things like MSI doorbells */ /* - * This is to make the IOMMU API setup privileged - * mapppings accessible by the master only at higher - * privileged execution level and inaccessible at - * less privileged levels. + * Where the bus hardware includes a privilege level as part of its access type + * markings, and certain devices are capable of issuing transactions marked as + * either 'supervisor' or 'user', the IOMMU_PRIV flag requests that the other + * given permission flags only apply to accesses at the higher privilege level, + * and that unprivileged transactions should have as little access as possible. + * This would usually imply the same permissions as kernel mappings on the CPU, + * if the IOMMU page table format is equivalent. */ #define IOMMU_PRIV (1 << 5) @@ -336,46 +339,9 @@ extern int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr, phys_addr_t offset, u64 size, int prot); extern void iommu_domain_window_disable(struct iommu_domain *domain, u32 wnd_nr); -/** - * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework - * @domain: the iommu domain where the fault has happened - * @dev: the device where the fault has happened - * @iova: the faulting address - * @flags: mmu fault flags (e.g. IOMMU_FAULT_READ/IOMMU_FAULT_WRITE/...) - * - * This function should be called by the low-level IOMMU implementations - * whenever IOMMU faults happen, to allow high-level users, that are - * interested in such events, to know about them. - * - * This event may be useful for several possible use cases: - * - mere logging of the event - * - dynamic TLB/PTE loading - * - if restarting of the faulting device is required - * - * Returns 0 on success and an appropriate error code otherwise (if dynamic - * PTE/TLB loading will one day be supported, implementations will be able - * to tell whether it succeeded or not according to this return value). - * - * Specifically, -ENOSYS is returned if a fault handler isn't installed - * (though fault handlers can also return -ENOSYS, in case they want to - * elicit the default behavior of the IOMMU drivers). - */ -static inline int report_iommu_fault(struct iommu_domain *domain, - struct device *dev, unsigned long iova, int flags) -{ - int ret = -ENOSYS; - - /* - * if upper layers showed interest and installed a fault handler, - * invoke it. - */ - if (domain->handler) - ret = domain->handler(domain, dev, iova, flags, - domain->handler_token); - trace_io_page_fault(dev, iova, flags); - return ret; -} +extern int report_iommu_fault(struct iommu_domain *domain, struct device *dev, + unsigned long iova, int flags); static inline size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, struct scatterlist *sg, diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 9ff201b63512..8c0664309815 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -384,8 +384,6 @@ struct kvm { struct mutex slots_lock; struct mm_struct *mm; /* userspace tied to this vm */ struct kvm_memslots *memslots[KVM_ADDRESS_SPACE_NUM]; - struct srcu_struct srcu; - struct srcu_struct irq_srcu; struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; /* @@ -438,6 +436,8 @@ struct kvm { struct list_head devices; struct dentry *debugfs_dentry; struct kvm_stat_data **debugfs_stat_data; + struct srcu_struct srcu; + struct srcu_struct irq_srcu; }; #define kvm_err(fmt, ...) \ diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 169ea0bd8eb4..b4ad8b4f8506 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -54,7 +54,8 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) return of_node_get(cpu_dev->of_node); } -void of_dma_configure(struct device *dev, struct device_node *np); +int of_dma_configure(struct device *dev, struct device_node *np); +void of_dma_deconfigure(struct device *dev); #else /* CONFIG_OF */ static inline int of_driver_match_device(struct device *dev, @@ -102,7 +103,12 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) { return NULL; } -static inline void of_dma_configure(struct device *dev, struct device_node *np) + +static inline int of_dma_configure(struct device *dev, struct device_node *np) +{ + return 0; +} +static inline void of_dma_deconfigure(struct device *dev) {} #endif /* CONFIG_OF */ diff --git a/include/linux/platform_data/iommu-omap.h b/include/linux/platform_data/iommu-omap.h index 0496d171700a..e8b12dbf6170 100644 --- a/include/linux/platform_data/iommu-omap.h +++ b/include/linux/platform_data/iommu-omap.h @@ -12,28 +12,8 @@ #include <linux/platform_device.h> -#define MMU_REG_SIZE 256 - -/** - * struct iommu_arch_data - omap iommu private data - * @name: name of the iommu device - * @iommu_dev: handle of the iommu device - * - * This is an omap iommu private data object, which binds an iommu user - * to its iommu device. This object should be placed at the iommu user's - * dev_archdata so generic IOMMU API can be used without having to - * utilize omap-specific plumbing anymore. - */ -struct omap_iommu_arch_data { - const char *name; - struct omap_iommu *iommu_dev; -}; - struct iommu_platform_data { - const char *name; const char *reset_name; - int nr_tlb_entries; - int (*assert_reset)(struct platform_device *pdev, const char *name); int (*deassert_reset)(struct platform_device *pdev, const char *name); }; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 9b6abe632587..b7803a251044 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -118,6 +118,7 @@ struct generic_pm_domain_data { struct pm_domain_data base; struct gpd_timing_data td; struct notifier_block nb; + void *data; }; #ifdef CONFIG_PM_GENERIC_DOMAINS diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index a3447932df1f..4c2cba7ec1d4 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -106,8 +106,8 @@ extern void __pm_stay_awake(struct wakeup_source *ws); extern void pm_stay_awake(struct device *dev); extern void __pm_relax(struct wakeup_source *ws); extern void pm_relax(struct device *dev); -extern void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec); -extern void pm_wakeup_event(struct device *dev, unsigned int msec); +extern void pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard); +extern void pm_wakeup_dev_event(struct device *dev, unsigned int msec, bool hard); #else /* !CONFIG_PM_SLEEP */ @@ -182,9 +182,11 @@ static inline void __pm_relax(struct wakeup_source *ws) {} static inline void pm_relax(struct device *dev) {} -static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) {} +static inline void pm_wakeup_ws_event(struct wakeup_source *ws, + unsigned int msec, bool hard) {} -static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {} +static inline void pm_wakeup_dev_event(struct device *dev, unsigned int msec, + bool hard) {} #endif /* !CONFIG_PM_SLEEP */ @@ -201,4 +203,19 @@ static inline void wakeup_source_trash(struct wakeup_source *ws) wakeup_source_drop(ws); } +static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) +{ + return pm_wakeup_ws_event(ws, msec, false); +} + +static inline void pm_wakeup_event(struct device *dev, unsigned int msec) +{ + return pm_wakeup_dev_event(dev, msec, false); +} + +static inline void pm_wakeup_hard_event(struct device *dev) +{ + return pm_wakeup_dev_event(dev, 0, true); +} + #endif /* _LINUX_PM_WAKEUP_H */ diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index d32f6f1a5225..e5380471c2cd 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -40,6 +40,9 @@ extern int qcom_scm_pas_shutdown(u32 peripheral); extern void qcom_scm_cpu_power_down(u32 flags); extern u32 qcom_scm_get_version(void); extern int qcom_scm_set_remote_state(u32 state, u32 id); +extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare); +extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size); +extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare); #else static inline int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) @@ -67,5 +70,8 @@ static inline void qcom_scm_cpu_power_down(u32 flags) {} static inline u32 qcom_scm_get_version(void) { return 0; } static inline u32 qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; } +static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; } +static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; } +static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; } #endif #endif diff --git a/include/linux/rcu_node_tree.h b/include/linux/rcu_node_tree.h new file mode 100644 index 000000000000..4b766b61e1a0 --- /dev/null +++ b/include/linux/rcu_node_tree.h @@ -0,0 +1,99 @@ +/* + * RCU node combining tree definitions. These are used to compute + * global attributes while avoiding common-case global contention. A key + * property that these computations rely on is a tournament-style approach + * where only one of the tasks contending a lower level in the tree need + * advance to the next higher level. If properly configured, this allows + * unlimited scalability while maintaining a constant level of contention + * on the root node. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright IBM Corporation, 2017 + * + * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> + */ + +#ifndef __LINUX_RCU_NODE_TREE_H +#define __LINUX_RCU_NODE_TREE_H + +/* + * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and + * CONFIG_RCU_FANOUT_LEAF. + * In theory, it should be possible to add more levels straightforwardly. + * In practice, this did work well going from three levels to four. + * Of course, your mileage may vary. + */ + +#ifdef CONFIG_RCU_FANOUT +#define RCU_FANOUT CONFIG_RCU_FANOUT +#else /* #ifdef CONFIG_RCU_FANOUT */ +# ifdef CONFIG_64BIT +# define RCU_FANOUT 64 +# else +# define RCU_FANOUT 32 +# endif +#endif /* #else #ifdef CONFIG_RCU_FANOUT */ + +#ifdef CONFIG_RCU_FANOUT_LEAF +#define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF +#else /* #ifdef CONFIG_RCU_FANOUT_LEAF */ +#define RCU_FANOUT_LEAF 16 +#endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */ + +#define RCU_FANOUT_1 (RCU_FANOUT_LEAF) +#define RCU_FANOUT_2 (RCU_FANOUT_1 * RCU_FANOUT) +#define RCU_FANOUT_3 (RCU_FANOUT_2 * RCU_FANOUT) +#define RCU_FANOUT_4 (RCU_FANOUT_3 * RCU_FANOUT) + +#if NR_CPUS <= RCU_FANOUT_1 +# define RCU_NUM_LVLS 1 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_NODES NUM_RCU_LVL_0 +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 } +# define RCU_NODE_NAME_INIT { "rcu_node_0" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" } +#elif NR_CPUS <= RCU_FANOUT_2 +# define RCU_NUM_LVLS 2 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) +# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1) +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 } +# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" } +#elif NR_CPUS <= RCU_FANOUT_3 +# define RCU_NUM_LVLS 3 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) +# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) +# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2) +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 } +# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" } +#elif NR_CPUS <= RCU_FANOUT_4 +# define RCU_NUM_LVLS 4 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3) +# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) +# define NUM_RCU_LVL_3 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) +# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 } +# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" } +#else +# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" +#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */ + +#endif /* __LINUX_RCU_NODE_TREE_H */ diff --git a/include/linux/rcu_segcblist.h b/include/linux/rcu_segcblist.h new file mode 100644 index 000000000000..ba4d2621d9ca --- /dev/null +++ b/include/linux/rcu_segcblist.h @@ -0,0 +1,90 @@ +/* + * RCU segmented callback lists + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright IBM Corporation, 2017 + * + * Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> + */ + +#ifndef __INCLUDE_LINUX_RCU_SEGCBLIST_H +#define __INCLUDE_LINUX_RCU_SEGCBLIST_H + +/* Simple unsegmented callback lists. */ +struct rcu_cblist { + struct rcu_head *head; + struct rcu_head **tail; + long len; + long len_lazy; +}; + +#define RCU_CBLIST_INITIALIZER(n) { .head = NULL, .tail = &n.head } + +/* Complicated segmented callback lists. ;-) */ + +/* + * Index values for segments in rcu_segcblist structure. + * + * The segments are as follows: + * + * [head, *tails[RCU_DONE_TAIL]): + * Callbacks whose grace period has elapsed, and thus can be invoked. + * [*tails[RCU_DONE_TAIL], *tails[RCU_WAIT_TAIL]): + * Callbacks waiting for the current GP from the current CPU's viewpoint. + * [*tails[RCU_WAIT_TAIL], *tails[RCU_NEXT_READY_TAIL]): + * Callbacks that arrived before the next GP started, again from + * the current CPU's viewpoint. These can be handled by the next GP. + * [*tails[RCU_NEXT_READY_TAIL], *tails[RCU_NEXT_TAIL]): + * Callbacks that might have arrived after the next GP started. + * There is some uncertainty as to when a given GP starts and + * ends, but a CPU knows the exact times if it is the one starting + * or ending the GP. Other CPUs know that the previous GP ends + * before the next one starts. + * + * Note that RCU_WAIT_TAIL cannot be empty unless RCU_NEXT_READY_TAIL is also + * empty. + * + * The ->gp_seq[] array contains the grace-period number at which the + * corresponding segment of callbacks will be ready to invoke. A given + * element of this array is meaningful only when the corresponding segment + * is non-empty, and it is never valid for RCU_DONE_TAIL (whose callbacks + * are already ready to invoke) or for RCU_NEXT_TAIL (whose callbacks have + * not yet been assigned a grace-period number). + */ +#define RCU_DONE_TAIL 0 /* Also RCU_WAIT head. */ +#define RCU_WAIT_TAIL 1 /* Also RCU_NEXT_READY head. */ +#define RCU_NEXT_READY_TAIL 2 /* Also RCU_NEXT head. */ +#define RCU_NEXT_TAIL 3 +#define RCU_CBLIST_NSEGS 4 + +struct rcu_segcblist { + struct rcu_head *head; + struct rcu_head **tails[RCU_CBLIST_NSEGS]; + unsigned long gp_seq[RCU_CBLIST_NSEGS]; + long len; + long len_lazy; +}; + +#define RCU_SEGCBLIST_INITIALIZER(n) \ +{ \ + .head = NULL, \ + .tails[RCU_DONE_TAIL] = &n.head, \ + .tails[RCU_WAIT_TAIL] = &n.head, \ + .tails[RCU_NEXT_READY_TAIL] = &n.head, \ + .tails[RCU_NEXT_TAIL] = &n.head, \ +} + +#endif /* __INCLUDE_LINUX_RCU_SEGCBLIST_H */ diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 4f7a9561b8c4..b1fd8bf85fdc 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -509,7 +509,8 @@ static inline void hlist_add_tail_rcu(struct hlist_node *n, { struct hlist_node *i, *last = NULL; - for (i = hlist_first_rcu(h); i; i = hlist_next_rcu(i)) + /* Note: write side code, so rcu accessors are not needed. */ + for (i = h->first; i; i = i->next) last = i; if (last) { diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index dea8f17b2fe3..e1e5d002fdb9 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -368,15 +368,20 @@ static inline void rcu_init_nohz(void) #ifdef CONFIG_TASKS_RCU #define TASKS_RCU(x) x extern struct srcu_struct tasks_rcu_exit_srcu; -#define rcu_note_voluntary_context_switch(t) \ +#define rcu_note_voluntary_context_switch_lite(t) \ do { \ - rcu_all_qs(); \ if (READ_ONCE((t)->rcu_tasks_holdout)) \ WRITE_ONCE((t)->rcu_tasks_holdout, false); \ } while (0) +#define rcu_note_voluntary_context_switch(t) \ + do { \ + rcu_all_qs(); \ + rcu_note_voluntary_context_switch_lite(t); \ + } while (0) #else /* #ifdef CONFIG_TASKS_RCU */ #define TASKS_RCU(x) do { } while (0) -#define rcu_note_voluntary_context_switch(t) rcu_all_qs() +#define rcu_note_voluntary_context_switch_lite(t) do { } while (0) +#define rcu_note_voluntary_context_switch(t) rcu_all_qs() #endif /* #else #ifdef CONFIG_TASKS_RCU */ /** @@ -1132,11 +1137,11 @@ do { \ * if the UNLOCK and LOCK are executed by the same CPU or if the * UNLOCK and LOCK operate on the same lock variable. */ -#ifdef CONFIG_PPC +#ifdef CONFIG_ARCH_WEAK_RELEASE_ACQUIRE #define smp_mb__after_unlock_lock() smp_mb() /* Full ordering for lock. */ -#else /* #ifdef CONFIG_PPC */ +#else /* #ifdef CONFIG_ARCH_WEAK_RELEASE_ACQUIRE */ #define smp_mb__after_unlock_lock() do { } while (0) -#endif /* #else #ifdef CONFIG_PPC */ +#endif /* #else #ifdef CONFIG_ARCH_WEAK_RELEASE_ACQUIRE */ #endif /* __LINUX_RCUPDATE_H */ diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index b452953e21c8..74d9c3a1feee 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -33,6 +33,11 @@ static inline int rcu_dynticks_snap(struct rcu_dynticks *rdtp) return 0; } +static inline bool rcu_eqs_special_set(int cpu) +{ + return false; /* Never flag non-existent other CPUs! */ +} + static inline unsigned long get_state_synchronize_rcu(void) { return 0; @@ -87,10 +92,11 @@ static inline void kfree_call_rcu(struct rcu_head *head, call_rcu(head, func); } -static inline void rcu_note_context_switch(void) -{ - rcu_sched_qs(); -} +#define rcu_note_context_switch(preempt) \ + do { \ + rcu_sched_qs(); \ + rcu_note_voluntary_context_switch_lite(current); \ + } while (0) /* * Take advantage of the fact that there is only one CPU, which @@ -212,14 +218,14 @@ static inline void exit_rcu(void) { } -#ifdef CONFIG_DEBUG_LOCK_ALLOC +#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SRCU) extern int rcu_scheduler_active __read_mostly; void rcu_scheduler_starting(void); -#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +#else /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SRCU) */ static inline void rcu_scheduler_starting(void) { } -#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +#endif /* #else #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SRCU) */ #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) @@ -237,6 +243,10 @@ static inline bool rcu_is_watching(void) #endif /* #else defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */ +static inline void rcu_request_urgent_qs_task(struct task_struct *t) +{ +} + static inline void rcu_all_qs(void) { barrier(); /* Avoid RCU read-side critical sections leaking across. */ diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 63a4e4cf40a5..0bacb6b2af69 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -30,7 +30,7 @@ #ifndef __LINUX_RCUTREE_H #define __LINUX_RCUTREE_H -void rcu_note_context_switch(void); +void rcu_note_context_switch(bool preempt); int rcu_needs_cpu(u64 basem, u64 *nextevt); void rcu_cpu_stall_reset(void); @@ -41,7 +41,7 @@ void rcu_cpu_stall_reset(void); */ static inline void rcu_virt_note_context_switch(int cpu) { - rcu_note_context_switch(); + rcu_note_context_switch(false); } void synchronize_rcu_bh(void); @@ -108,6 +108,7 @@ void rcu_scheduler_starting(void); extern int rcu_scheduler_active __read_mostly; bool rcu_is_watching(void); +void rcu_request_urgent_qs_task(struct task_struct *t); void rcu_all_qs(void); diff --git a/include/linux/slab.h b/include/linux/slab.h index 3c37a8c51921..04a7f7993e67 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -28,7 +28,7 @@ #define SLAB_STORE_USER 0x00010000UL /* DEBUG: Store the last owner for bug hunting */ #define SLAB_PANIC 0x00040000UL /* Panic if kmem_cache_create() fails */ /* - * SLAB_DESTROY_BY_RCU - **WARNING** READ THIS! + * SLAB_TYPESAFE_BY_RCU - **WARNING** READ THIS! * * This delays freeing the SLAB page by a grace period, it does _NOT_ * delay object freeing. This means that if you do kmem_cache_free() @@ -61,8 +61,10 @@ * * rcu_read_lock before reading the address, then rcu_read_unlock after * taking the spinlock within the structure expected at that address. + * + * Note that SLAB_TYPESAFE_BY_RCU was originally named SLAB_DESTROY_BY_RCU. */ -#define SLAB_DESTROY_BY_RCU 0x00080000UL /* Defer freeing slabs to RCU */ +#define SLAB_TYPESAFE_BY_RCU 0x00080000UL /* Defer freeing slabs to RCU */ #define SLAB_MEM_SPREAD 0x00100000UL /* Spread some memory over cpuset */ #define SLAB_TRACE 0x00200000UL /* Trace allocations and frees */ diff --git a/include/linux/srcu.h b/include/linux/srcu.h index a598cf3ac70c..167ad8831aaf 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -22,7 +22,7 @@ * Lai Jiangshan <laijs@cn.fujitsu.com> * * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt + * Documentation/RCU/ *.txt * */ @@ -32,35 +32,9 @@ #include <linux/mutex.h> #include <linux/rcupdate.h> #include <linux/workqueue.h> +#include <linux/rcu_segcblist.h> -struct srcu_array { - unsigned long lock_count[2]; - unsigned long unlock_count[2]; -}; - -struct rcu_batch { - struct rcu_head *head, **tail; -}; - -#define RCU_BATCH_INIT(name) { NULL, &(name.head) } - -struct srcu_struct { - unsigned long completed; - struct srcu_array __percpu *per_cpu_ref; - spinlock_t queue_lock; /* protect ->batch_queue, ->running */ - bool running; - /* callbacks just queued */ - struct rcu_batch batch_queue; - /* callbacks try to do the first check_zero */ - struct rcu_batch batch_check0; - /* callbacks done with the first check_zero and the flip */ - struct rcu_batch batch_check1; - struct rcu_batch batch_done; - struct delayed_work work; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ -}; +struct srcu_struct; #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -82,46 +56,15 @@ int init_srcu_struct(struct srcu_struct *sp); #define __SRCU_DEP_MAP_INIT(srcu_name) #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ -void process_srcu(struct work_struct *work); - -#define __SRCU_STRUCT_INIT(name) \ - { \ - .completed = -300, \ - .per_cpu_ref = &name##_srcu_array, \ - .queue_lock = __SPIN_LOCK_UNLOCKED(name.queue_lock), \ - .running = false, \ - .batch_queue = RCU_BATCH_INIT(name.batch_queue), \ - .batch_check0 = RCU_BATCH_INIT(name.batch_check0), \ - .batch_check1 = RCU_BATCH_INIT(name.batch_check1), \ - .batch_done = RCU_BATCH_INIT(name.batch_done), \ - .work = __DELAYED_WORK_INITIALIZER(name.work, process_srcu, 0),\ - __SRCU_DEP_MAP_INIT(name) \ - } - -/* - * Define and initialize a srcu struct at build time. - * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it. - * - * Note that although DEFINE_STATIC_SRCU() hides the name from other - * files, the per-CPU variable rules nevertheless require that the - * chosen name be globally unique. These rules also prohibit use of - * DEFINE_STATIC_SRCU() within a function. If these rules are too - * restrictive, declare the srcu_struct manually. For example, in - * each file: - * - * static struct srcu_struct my_srcu; - * - * Then, before the first use of each my_srcu, manually initialize it: - * - * init_srcu_struct(&my_srcu); - * - * See include/linux/percpu-defs.h for the rules on per-CPU variables. - */ -#define __DEFINE_SRCU(name, is_static) \ - static DEFINE_PER_CPU(struct srcu_array, name##_srcu_array);\ - is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name) -#define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */) -#define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static) +#ifdef CONFIG_TINY_SRCU +#include <linux/srcutiny.h> +#elif defined(CONFIG_TREE_SRCU) +#include <linux/srcutree.h> +#elif defined(CONFIG_CLASSIC_SRCU) +#include <linux/srcuclassic.h> +#else +#error "Unknown SRCU implementation specified to kernel configuration" +#endif /** * call_srcu() - Queue a callback for invocation after an SRCU grace period @@ -147,9 +90,6 @@ void cleanup_srcu_struct(struct srcu_struct *sp); int __srcu_read_lock(struct srcu_struct *sp) __acquires(sp); void __srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); void synchronize_srcu(struct srcu_struct *sp); -void synchronize_srcu_expedited(struct srcu_struct *sp); -unsigned long srcu_batches_completed(struct srcu_struct *sp); -void srcu_barrier(struct srcu_struct *sp); #ifdef CONFIG_DEBUG_LOCK_ALLOC diff --git a/include/linux/srcuclassic.h b/include/linux/srcuclassic.h new file mode 100644 index 000000000000..5753f7322262 --- /dev/null +++ b/include/linux/srcuclassic.h @@ -0,0 +1,115 @@ +/* + * Sleepable Read-Copy Update mechanism for mutual exclusion, + * classic v4.11 variant. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (C) IBM Corporation, 2017 + * + * Author: Paul McKenney <paulmck@us.ibm.com> + */ + +#ifndef _LINUX_SRCU_CLASSIC_H +#define _LINUX_SRCU_CLASSIC_H + +struct srcu_array { + unsigned long lock_count[2]; + unsigned long unlock_count[2]; +}; + +struct rcu_batch { + struct rcu_head *head, **tail; +}; + +#define RCU_BATCH_INIT(name) { NULL, &(name.head) } + +struct srcu_struct { + unsigned long completed; + struct srcu_array __percpu *per_cpu_ref; + spinlock_t queue_lock; /* protect ->batch_queue, ->running */ + bool running; + /* callbacks just queued */ + struct rcu_batch batch_queue; + /* callbacks try to do the first check_zero */ + struct rcu_batch batch_check0; + /* callbacks done with the first check_zero and the flip */ + struct rcu_batch batch_check1; + struct rcu_batch batch_done; + struct delayed_work work; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +}; + +void process_srcu(struct work_struct *work); + +#define __SRCU_STRUCT_INIT(name) \ + { \ + .completed = -300, \ + .per_cpu_ref = &name##_srcu_array, \ + .queue_lock = __SPIN_LOCK_UNLOCKED(name.queue_lock), \ + .running = false, \ + .batch_queue = RCU_BATCH_INIT(name.batch_queue), \ + .batch_check0 = RCU_BATCH_INIT(name.batch_check0), \ + .batch_check1 = RCU_BATCH_INIT(name.batch_check1), \ + .batch_done = RCU_BATCH_INIT(name.batch_done), \ + .work = __DELAYED_WORK_INITIALIZER(name.work, process_srcu, 0),\ + __SRCU_DEP_MAP_INIT(name) \ + } + +/* + * Define and initialize a srcu struct at build time. + * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it. + * + * Note that although DEFINE_STATIC_SRCU() hides the name from other + * files, the per-CPU variable rules nevertheless require that the + * chosen name be globally unique. These rules also prohibit use of + * DEFINE_STATIC_SRCU() within a function. If these rules are too + * restrictive, declare the srcu_struct manually. For example, in + * each file: + * + * static struct srcu_struct my_srcu; + * + * Then, before the first use of each my_srcu, manually initialize it: + * + * init_srcu_struct(&my_srcu); + * + * See include/linux/percpu-defs.h for the rules on per-CPU variables. + */ +#define __DEFINE_SRCU(name, is_static) \ + static DEFINE_PER_CPU(struct srcu_array, name##_srcu_array);\ + is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name) +#define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */) +#define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static) + +void synchronize_srcu_expedited(struct srcu_struct *sp); +void srcu_barrier(struct srcu_struct *sp); +unsigned long srcu_batches_completed(struct srcu_struct *sp); + +static inline void srcutorture_get_gp_data(enum rcutorture_type test_type, + struct srcu_struct *sp, int *flags, + unsigned long *gpnum, + unsigned long *completed) +{ + if (test_type != SRCU_FLAVOR) + return; + *flags = 0; + *completed = sp->completed; + *gpnum = *completed; + if (sp->batch_queue.head || sp->batch_check0.head || sp->batch_check0.head) + (*gpnum)++; +} + +#endif diff --git a/include/linux/srcutiny.h b/include/linux/srcutiny.h new file mode 100644 index 000000000000..42311ee0334f --- /dev/null +++ b/include/linux/srcutiny.h @@ -0,0 +1,93 @@ +/* + * Sleepable Read-Copy Update mechanism for mutual exclusion, + * tiny variant. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (C) IBM Corporation, 2017 + * + * Author: Paul McKenney <paulmck@us.ibm.com> + */ + +#ifndef _LINUX_SRCU_TINY_H +#define _LINUX_SRCU_TINY_H + +#include <linux/swait.h> + +struct srcu_struct { + int srcu_lock_nesting[2]; /* srcu_read_lock() nesting depth. */ + struct swait_queue_head srcu_wq; + /* Last srcu_read_unlock() wakes GP. */ + unsigned long srcu_gp_seq; /* GP seq # for callback tagging. */ + struct rcu_segcblist srcu_cblist; + /* Pending SRCU callbacks. */ + int srcu_idx; /* Current reader array element. */ + bool srcu_gp_running; /* GP workqueue running? */ + bool srcu_gp_waiting; /* GP waiting for readers? */ + struct work_struct srcu_work; /* For driving grace periods. */ +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +}; + +void srcu_drive_gp(struct work_struct *wp); + +#define __SRCU_STRUCT_INIT(name) \ +{ \ + .srcu_wq = __SWAIT_QUEUE_HEAD_INITIALIZER(name.srcu_wq), \ + .srcu_cblist = RCU_SEGCBLIST_INITIALIZER(name.srcu_cblist), \ + .srcu_work = __WORK_INITIALIZER(name.srcu_work, srcu_drive_gp), \ + __SRCU_DEP_MAP_INIT(name) \ +} + +/* + * This odd _STATIC_ arrangement is needed for API compatibility with + * Tree SRCU, which needs some per-CPU data. + */ +#define DEFINE_SRCU(name) \ + struct srcu_struct name = __SRCU_STRUCT_INIT(name) +#define DEFINE_STATIC_SRCU(name) \ + static struct srcu_struct name = __SRCU_STRUCT_INIT(name) + +void synchronize_srcu(struct srcu_struct *sp); + +static inline void synchronize_srcu_expedited(struct srcu_struct *sp) +{ + synchronize_srcu(sp); +} + +static inline void srcu_barrier(struct srcu_struct *sp) +{ + synchronize_srcu(sp); +} + +static inline unsigned long srcu_batches_completed(struct srcu_struct *sp) +{ + return 0; +} + +static inline void srcutorture_get_gp_data(enum rcutorture_type test_type, + struct srcu_struct *sp, int *flags, + unsigned long *gpnum, + unsigned long *completed) +{ + if (test_type != SRCU_FLAVOR) + return; + *flags = 0; + *completed = sp->srcu_gp_seq; + *gpnum = *completed; +} + +#endif diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h new file mode 100644 index 000000000000..32e86d85fd11 --- /dev/null +++ b/include/linux/srcutree.h @@ -0,0 +1,150 @@ +/* + * Sleepable Read-Copy Update mechanism for mutual exclusion, + * tree variant. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (C) IBM Corporation, 2017 + * + * Author: Paul McKenney <paulmck@us.ibm.com> + */ + +#ifndef _LINUX_SRCU_TREE_H +#define _LINUX_SRCU_TREE_H + +#include <linux/rcu_node_tree.h> +#include <linux/completion.h> + +struct srcu_node; +struct srcu_struct; + +/* + * Per-CPU structure feeding into leaf srcu_node, similar in function + * to rcu_node. + */ +struct srcu_data { + /* Read-side state. */ + unsigned long srcu_lock_count[2]; /* Locks per CPU. */ + unsigned long srcu_unlock_count[2]; /* Unlocks per CPU. */ + + /* Update-side state. */ + spinlock_t lock ____cacheline_internodealigned_in_smp; + struct rcu_segcblist srcu_cblist; /* List of callbacks.*/ + unsigned long srcu_gp_seq_needed; /* Furthest future GP needed. */ + unsigned long srcu_gp_seq_needed_exp; /* Furthest future exp GP. */ + bool srcu_cblist_invoking; /* Invoking these CBs? */ + struct delayed_work work; /* Context for CB invoking. */ + struct rcu_head srcu_barrier_head; /* For srcu_barrier() use. */ + struct srcu_node *mynode; /* Leaf srcu_node. */ + unsigned long grpmask; /* Mask for leaf srcu_node */ + /* ->srcu_data_have_cbs[]. */ + int cpu; + struct srcu_struct *sp; +}; + +/* + * Node in SRCU combining tree, similar in function to rcu_data. + */ +struct srcu_node { + spinlock_t lock; + unsigned long srcu_have_cbs[4]; /* GP seq for children */ + /* having CBs, but only */ + /* is > ->srcu_gq_seq. */ + unsigned long srcu_data_have_cbs[4]; /* Which srcu_data structs */ + /* have CBs for given GP? */ + unsigned long srcu_gp_seq_needed_exp; /* Furthest future exp GP. */ + struct srcu_node *srcu_parent; /* Next up in tree. */ + int grplo; /* Least CPU for node. */ + int grphi; /* Biggest CPU for node. */ +}; + +/* + * Per-SRCU-domain structure, similar in function to rcu_state. + */ +struct srcu_struct { + struct srcu_node node[NUM_RCU_NODES]; /* Combining tree. */ + struct srcu_node *level[RCU_NUM_LVLS + 1]; + /* First node at each level. */ + struct mutex srcu_cb_mutex; /* Serialize CB preparation. */ + spinlock_t gp_lock; /* protect ->srcu_cblist */ + struct mutex srcu_gp_mutex; /* Serialize GP work. */ + unsigned int srcu_idx; /* Current rdr array element. */ + unsigned long srcu_gp_seq; /* Grace-period seq #. */ + unsigned long srcu_gp_seq_needed; /* Latest gp_seq needed. */ + unsigned long srcu_gp_seq_needed_exp; /* Furthest future exp GP. */ + unsigned long srcu_last_gp_end; /* Last GP end timestamp (ns) */ + struct srcu_data __percpu *sda; /* Per-CPU srcu_data array. */ + unsigned long srcu_barrier_seq; /* srcu_barrier seq #. */ + struct mutex srcu_barrier_mutex; /* Serialize barrier ops. */ + struct completion srcu_barrier_completion; + /* Awaken barrier rq at end. */ + atomic_t srcu_barrier_cpu_cnt; /* # CPUs not yet posting a */ + /* callback for the barrier */ + /* operation. */ + struct delayed_work work; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +}; + +/* Values for state variable (bottom bits of ->srcu_gp_seq). */ +#define SRCU_STATE_IDLE 0 +#define SRCU_STATE_SCAN1 1 +#define SRCU_STATE_SCAN2 2 + +void process_srcu(struct work_struct *work); + +#define __SRCU_STRUCT_INIT(name) \ + { \ + .sda = &name##_srcu_data, \ + .gp_lock = __SPIN_LOCK_UNLOCKED(name.gp_lock), \ + .srcu_gp_seq_needed = 0 - 1, \ + __SRCU_DEP_MAP_INIT(name) \ + } + +/* + * Define and initialize a srcu struct at build time. + * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it. + * + * Note that although DEFINE_STATIC_SRCU() hides the name from other + * files, the per-CPU variable rules nevertheless require that the + * chosen name be globally unique. These rules also prohibit use of + * DEFINE_STATIC_SRCU() within a function. If these rules are too + * restrictive, declare the srcu_struct manually. For example, in + * each file: + * + * static struct srcu_struct my_srcu; + * + * Then, before the first use of each my_srcu, manually initialize it: + * + * init_srcu_struct(&my_srcu); + * + * See include/linux/percpu-defs.h for the rules on per-CPU variables. + */ +#define __DEFINE_SRCU(name, is_static) \ + static DEFINE_PER_CPU(struct srcu_data, name##_srcu_data);\ + is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name) +#define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */) +#define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static) + +void synchronize_srcu_expedited(struct srcu_struct *sp); +void srcu_barrier(struct srcu_struct *sp); +unsigned long srcu_batches_completed(struct srcu_struct *sp); + +void srcutorture_get_gp_data(enum rcutorture_type test_type, + struct srcu_struct *sp, int *flags, + unsigned long *gpnum, unsigned long *completed); + +#endif diff --git a/include/linux/suspend.h b/include/linux/suspend.h index d9718378a8be..0b1cf32edfd7 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -189,6 +189,8 @@ struct platform_suspend_ops { struct platform_freeze_ops { int (*begin)(void); int (*prepare)(void); + void (*wake)(void); + void (*sync)(void); void (*restore)(void); void (*end)(void); }; @@ -428,7 +430,8 @@ extern unsigned int pm_wakeup_irq; extern bool pm_wakeup_pending(void); extern void pm_system_wakeup(void); -extern void pm_wakeup_clear(void); +extern void pm_system_cancel_wakeup(void); +extern void pm_wakeup_clear(bool reset); extern void pm_system_irq_wakeup(unsigned int irq_number); extern bool pm_get_wakeup_count(unsigned int *count, bool block); extern bool pm_save_wakeup_count(unsigned int count); @@ -478,7 +481,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb) static inline bool pm_wakeup_pending(void) { return false; } static inline void pm_system_wakeup(void) {} -static inline void pm_wakeup_clear(void) {} +static inline void pm_wakeup_clear(bool reset) {} static inline void pm_system_irq_wakeup(unsigned int irq_number) {} static inline void lock_system_sleep(void) {} diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h new file mode 100644 index 000000000000..0f175b8f6456 --- /dev/null +++ b/include/linux/tee_drv.h @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 __TEE_DRV_H +#define __TEE_DRV_H + +#include <linux/types.h> +#include <linux/idr.h> +#include <linux/list.h> +#include <linux/tee.h> + +/* + * The file describes the API provided by the generic TEE driver to the + * specific TEE driver. + */ + +#define TEE_SHM_MAPPED 0x1 /* Memory mapped by the kernel */ +#define TEE_SHM_DMA_BUF 0x2 /* Memory with dma-buf handle */ + +struct tee_device; +struct tee_shm; +struct tee_shm_pool; + +/** + * struct tee_context - driver specific context on file pointer data + * @teedev: pointer to this drivers struct tee_device + * @list_shm: List of shared memory object owned by this context + * @data: driver specific context data, managed by the driver + */ +struct tee_context { + struct tee_device *teedev; + struct list_head list_shm; + void *data; +}; + +struct tee_param_memref { + size_t shm_offs; + size_t size; + struct tee_shm *shm; +}; + +struct tee_param_value { + u64 a; + u64 b; + u64 c; +}; + +struct tee_param { + u64 attr; + union { + struct tee_param_memref memref; + struct tee_param_value value; + } u; +}; + +/** + * struct tee_driver_ops - driver operations vtable + * @get_version: returns version of driver + * @open: called when the device file is opened + * @release: release this open file + * @open_session: open a new session + * @close_session: close a session + * @invoke_func: invoke a trusted function + * @cancel_req: request cancel of an ongoing invoke or open + * @supp_revc: called for supplicant to get a command + * @supp_send: called for supplicant to send a response + */ +struct tee_driver_ops { + void (*get_version)(struct tee_device *teedev, + struct tee_ioctl_version_data *vers); + int (*open)(struct tee_context *ctx); + void (*release)(struct tee_context *ctx); + int (*open_session)(struct tee_context *ctx, + struct tee_ioctl_open_session_arg *arg, + struct tee_param *param); + int (*close_session)(struct tee_context *ctx, u32 session); + int (*invoke_func)(struct tee_context *ctx, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param); + int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session); + int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params, + struct tee_param *param); + int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params, + struct tee_param *param); +}; + +/** + * struct tee_desc - Describes the TEE driver to the subsystem + * @name: name of driver + * @ops: driver operations vtable + * @owner: module providing the driver + * @flags: Extra properties of driver, defined by TEE_DESC_* below + */ +#define TEE_DESC_PRIVILEGED 0x1 +struct tee_desc { + const char *name; + const struct tee_driver_ops *ops; + struct module *owner; + u32 flags; +}; + +/** + * tee_device_alloc() - Allocate a new struct tee_device instance + * @teedesc: Descriptor for this driver + * @dev: Parent device for this device + * @pool: Shared memory pool, NULL if not used + * @driver_data: Private driver data for this device + * + * Allocates a new struct tee_device instance. The device is + * removed by tee_device_unregister(). + * + * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure + */ +struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, + struct device *dev, + struct tee_shm_pool *pool, + void *driver_data); + +/** + * tee_device_register() - Registers a TEE device + * @teedev: Device to register + * + * tee_device_unregister() need to be called to remove the @teedev if + * this function fails. + * + * @returns < 0 on failure + */ +int tee_device_register(struct tee_device *teedev); + +/** + * tee_device_unregister() - Removes a TEE device + * @teedev: Device to unregister + * + * This function should be called to remove the @teedev even if + * tee_device_register() hasn't been called yet. Does nothing if + * @teedev is NULL. + */ +void tee_device_unregister(struct tee_device *teedev); + +/** + * struct tee_shm_pool_mem_info - holds information needed to create a shared + * memory pool + * @vaddr: Virtual address of start of pool + * @paddr: Physical address of start of pool + * @size: Size in bytes of the pool + */ +struct tee_shm_pool_mem_info { + unsigned long vaddr; + phys_addr_t paddr; + size_t size; +}; + +/** + * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved + * memory range + * @priv_info: Information for driver private shared memory pool + * @dmabuf_info: Information for dma-buf shared memory pool + * + * Start and end of pools will must be page aligned. + * + * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied + * in @dmabuf, others will use the range provided by @priv. + * + * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. + */ +struct tee_shm_pool * +tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info, + struct tee_shm_pool_mem_info *dmabuf_info); + +/** + * tee_shm_pool_free() - Free a shared memory pool + * @pool: The shared memory pool to free + * + * The must be no remaining shared memory allocated from this pool when + * this function is called. + */ +void tee_shm_pool_free(struct tee_shm_pool *pool); + +/** + * tee_get_drvdata() - Return driver_data pointer + * @returns the driver_data pointer supplied to tee_register(). + */ +void *tee_get_drvdata(struct tee_device *teedev); + +/** + * tee_shm_alloc() - Allocate shared memory + * @ctx: Context that allocates the shared memory + * @size: Requested size of shared memory + * @flags: Flags setting properties for the requested shared memory. + * + * Memory allocated as global shared memory is automatically freed when the + * TEE file pointer is closed. The @flags field uses the bits defined by + * TEE_SHM_* above. TEE_SHM_MAPPED must currently always be set. If + * TEE_SHM_DMA_BUF global shared memory will be allocated and associated + * with a dma-buf handle, else driver private memory. + * + * @returns a pointer to 'struct tee_shm' + */ +struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags); + +/** + * tee_shm_free() - Free shared memory + * @shm: Handle to shared memory to free + */ +void tee_shm_free(struct tee_shm *shm); + +/** + * tee_shm_put() - Decrease reference count on a shared memory handle + * @shm: Shared memory handle + */ +void tee_shm_put(struct tee_shm *shm); + +/** + * tee_shm_va2pa() - Get physical address of a virtual address + * @shm: Shared memory handle + * @va: Virtual address to tranlsate + * @pa: Returned physical address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa); + +/** + * tee_shm_pa2va() - Get virtual address of a physical address + * @shm: Shared memory handle + * @pa: Physical address to tranlsate + * @va: Returned virtual address + * @returns 0 on success and < 0 on failure + */ +int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va); + +/** + * tee_shm_get_va() - Get virtual address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @returns virtual address of the shared memory + offs if offs is within + * the bounds of this shared memory, else an ERR_PTR + */ +void *tee_shm_get_va(struct tee_shm *shm, size_t offs); + +/** + * tee_shm_get_pa() - Get physical address of a shared memory plus an offset + * @shm: Shared memory handle + * @offs: Offset from start of this shared memory + * @pa: Physical address to return + * @returns 0 if offs is within the bounds of this shared memory, else an + * error code. + */ +int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa); + +/** + * tee_shm_get_id() - Get id of a shared memory object + * @shm: Shared memory handle + * @returns id + */ +int tee_shm_get_id(struct tee_shm *shm); + +/** + * tee_shm_get_from_id() - Find shared memory object and increase reference + * count + * @ctx: Context owning the shared memory + * @id: Id of shared memory object + * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure + */ +struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id); + +#endif /*__TEE_DRV_H*/ diff --git a/include/linux/types.h b/include/linux/types.h index 1e7bd24848fc..258099a4ed82 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -209,7 +209,7 @@ struct ustat { * naturally due ABI requirements, but some architectures (like CRIS) have * weird ABI and we need to ask it explicitly. * - * The alignment is required to guarantee that bits 0 and 1 of @next will be + * The alignment is required to guarantee that bit 0 of @next will be * clear under normal conditions -- as long as we use call_rcu(), * call_rcu_bh(), call_rcu_sched(), or call_srcu() to queue callback. * diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 2452e6449532..b43a4eec3cec 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -20,6 +20,8 @@ #define ADDRCONF_TIMER_FUZZ (HZ / 4) #define ADDRCONF_TIMER_FUZZ_MAX (HZ) +#define ADDRCONF_NOTIFY_PRIORITY 0 + #include <linux/in.h> #include <linux/in6.h> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 15d6599b8bc6..b083e6cbae8c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1666,7 +1666,7 @@ struct cfg80211_bss_select_adjust { * (others are filtered out). * If ommited, all results are passed. * @n_match_sets: number of match sets - * @results_wk: worker for processing results notification. + * @report_results: indicates that results were reported for this request * @wiphy: the wiphy this was for * @dev: the interface * @scan_start: start time of the scheduled scan diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4d05a9443344..76ed24a201eb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1141,7 +1141,6 @@ enum mac80211_rx_flags { * enum mac80211_rx_encoding_flags - MCS & bandwidth flags * * @RX_ENC_FLAG_SHORTPRE: Short preamble was used for this frame - * @RX_ENC_FLAG_40MHZ: HT40 (40 MHz) was used * @RX_ENC_FLAG_SHORT_GI: Short guard interval was used * @RX_ENC_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, * if the driver fills this value it should add @@ -1153,7 +1152,6 @@ enum mac80211_rx_flags { */ enum mac80211_rx_encoding_flags { RX_ENC_FLAG_SHORTPRE = BIT(0), - RX_ENC_FLAG_40MHZ = BIT(1), RX_ENC_FLAG_SHORT_GI = BIT(2), RX_ENC_FLAG_HT_GF = BIT(3), RX_ENC_FLAG_STBC_MASK = BIT(4) | BIT(5), diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h index fe236b3429f0..b94006f6fbdd 100644 --- a/include/net/secure_seq.h +++ b/include/net/secure_seq.h @@ -6,10 +6,12 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport); -u32 secure_tcp_seq_and_tsoff(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport, u32 *tsoff); -u32 secure_tcpv6_seq_and_tsoff(const __be32 *saddr, const __be32 *daddr, - __be16 sport, __be16 dport, u32 *tsoff); +u32 secure_tcp_seq(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport); +u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr); +u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr, + __be16 sport, __be16 dport); +u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr); u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport); u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, diff --git a/include/net/sock.h b/include/net/sock.h index 66349e49d468..f33e3d134e0b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -995,7 +995,7 @@ struct smc_hashinfo; struct module; /* - * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes + * caches using SLAB_TYPESAFE_BY_RCU should let .next pointer from nulls nodes * un-modified. Special care is taken when initializing object to zero. */ static inline void sk_prot_clear_nulls(struct sock *sk, int size) diff --git a/include/net/tcp.h b/include/net/tcp.h index 270e5cc43c99..38a7427ae902 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -470,7 +470,7 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); /* From syncookies.c */ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, - struct dst_entry *dst); + struct dst_entry *dst, u32 tsoff); int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, u32 cookie); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); @@ -1234,10 +1234,12 @@ void tcp_cwnd_restart(struct sock *sk, s32 delta); static inline void tcp_slow_start_after_idle_check(struct sock *sk) { + const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; struct tcp_sock *tp = tcp_sk(sk); s32 delta; - if (!sysctl_tcp_slow_start_after_idle || tp->packets_out) + if (!sysctl_tcp_slow_start_after_idle || tp->packets_out || + ca_ops->cong_control) return; delta = tcp_time_stamp - tp->lsndtime; if (delta > inet_csk(sk)->icsk_rto) @@ -1822,7 +1824,8 @@ struct tcp_request_sock_ops { #endif struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, const struct request_sock *req); - __u32 (*init_seq_tsoff)(const struct sk_buff *skb, u32 *tsoff); + u32 (*init_seq)(const struct sk_buff *skb); + u32 (*init_ts_off)(const struct sk_buff *skb); int (*send_synack)(const struct sock *sk, struct dst_entry *dst, struct flowi *fl, struct request_sock *req, struct tcp_fastopen_cookie *foc, diff --git a/arch/arm/mach-tegra/flowctrl.h b/include/soc/tegra/flowctrl.h index 73a9c5016c1a..8f86aea4024b 100644 --- a/arch/arm/mach-tegra/flowctrl.h +++ b/include/soc/tegra/flowctrl.h @@ -1,7 +1,5 @@ /* - * arch/arm/mach-tegra/flowctrl.h - * - * functions and macros to control the flowcontroller + * Functions and macros to control the flowcontroller * * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved. * @@ -18,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef __MACH_TEGRA_FLOWCTRL_H -#define __MACH_TEGRA_FLOWCTRL_H +#ifndef __SOC_TEGRA_FLOWCTRL_H__ +#define __SOC_TEGRA_FLOWCTRL_H__ #define FLOW_CTRL_HALT_CPU0_EVENTS 0x0 #define FLOW_CTRL_WAITEVENT (2 << 29) @@ -53,14 +51,32 @@ #define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP (0xF << 8) #ifndef __ASSEMBLY__ +#ifdef CONFIG_SOC_TEGRA_FLOWCTRL u32 flowctrl_read_cpu_csr(unsigned int cpuid); void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value); void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value); void flowctrl_cpu_suspend_enter(unsigned int cpuid); void flowctrl_cpu_suspend_exit(unsigned int cpuid); +#else +static inline u32 flowctrl_read_cpu_csr(unsigned int cpuid) +{ + return 0; +} + +static inline void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value) +{ +} + +static inline void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value) {} -void tegra_flowctrl_init(void); -#endif +static inline void flowctrl_cpu_suspend_enter(unsigned int cpuid) +{ +} -#endif +static inline void flowctrl_cpu_suspend_exit(unsigned int cpuid) +{ +} +#endif /* CONFIG_SOC_TEGRA_FLOWCTRL */ +#endif /* __ASSEMBLY */ +#endif /* __SOC_TEGRA_FLOWCTRL_H__ */ diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index 2f271d1b9cea..1c3982bc558f 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -26,12 +26,6 @@ struct clk; struct reset_control; -#ifdef CONFIG_PM_SLEEP -enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void); -void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode); -void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode); -#endif /* CONFIG_PM_SLEEP */ - #ifdef CONFIG_SMP bool tegra_pmc_cpu_is_powered(unsigned int cpuid); int tegra_pmc_cpu_power_on(unsigned int cpuid); @@ -144,7 +138,7 @@ enum tegra_io_pad_voltage { TEGRA_IO_PAD_3300000UV, }; -#ifdef CONFIG_ARCH_TEGRA +#ifdef CONFIG_SOC_TEGRA_PMC int tegra_powergate_is_powered(unsigned int id); int tegra_powergate_power_on(unsigned int id); int tegra_powergate_power_off(unsigned int id); @@ -163,6 +157,11 @@ int tegra_io_pad_get_voltage(enum tegra_io_pad id); /* deprecated, use tegra_io_pad_power_{enable,disable}() instead */ int tegra_io_rail_power_on(unsigned int id); int tegra_io_rail_power_off(unsigned int id); + +enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void); +void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode); +void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode); + #else static inline int tegra_powergate_is_powered(unsigned int id) { @@ -221,6 +220,20 @@ static inline int tegra_io_rail_power_off(unsigned int id) { return -ENOSYS; } -#endif /* CONFIG_ARCH_TEGRA */ + +static inline enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) +{ + return TEGRA_SUSPEND_NONE; +} + +static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode) +{ +} + +static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) +{ +} + +#endif /* CONFIG_SOC_TEGRA_PMC */ #endif /* __SOC_TEGRA_PMC_H__ */ diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index a3c3cab643a9..e37973526153 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -12,6 +12,7 @@ struct btrfs_root; struct btrfs_fs_info; struct btrfs_inode; struct extent_map; +struct btrfs_file_extent_item; struct btrfs_ordered_extent; struct btrfs_delayed_ref_node; struct btrfs_delayed_tree_ref; @@ -24,6 +25,7 @@ struct extent_buffer; struct btrfs_work; struct __btrfs_workqueue; struct btrfs_qgroup_extent_record; +struct btrfs_qgroup; #define show_ref_type(type) \ __print_symbolic(type, \ @@ -54,6 +56,12 @@ struct btrfs_qgroup_extent_record; (obj >= BTRFS_ROOT_TREE_OBJECTID && \ obj <= BTRFS_QUOTA_TREE_OBJECTID)) ? __show_root_type(obj) : "-" +#define show_fi_type(type) \ + __print_symbolic(type, \ + { BTRFS_FILE_EXTENT_INLINE, "INLINE" }, \ + { BTRFS_FILE_EXTENT_REG, "REG" }, \ + { BTRFS_FILE_EXTENT_PREALLOC, "PREALLOC"}) + #define BTRFS_GROUP_FLAGS \ { BTRFS_BLOCK_GROUP_DATA, "DATA"}, \ { BTRFS_BLOCK_GROUP_SYSTEM, "SYSTEM"}, \ @@ -213,7 +221,7 @@ TRACE_EVENT_CONDITION(btrfs_get_extent, __entry->block_start = map->block_start; __entry->block_len = map->block_len; __entry->flags = map->flags; - __entry->refs = atomic_read(&map->refs); + __entry->refs = refcount_read(&map->refs); __entry->compress_type = map->compress_type; ), @@ -232,6 +240,138 @@ TRACE_EVENT_CONDITION(btrfs_get_extent, __entry->refs, __entry->compress_type) ); +/* file extent item */ +DECLARE_EVENT_CLASS(btrfs__file_extent_item_regular, + + TP_PROTO(struct btrfs_inode *bi, struct extent_buffer *l, + struct btrfs_file_extent_item *fi, u64 start), + + TP_ARGS(bi, l, fi, start), + + TP_STRUCT__entry_btrfs( + __field( u64, root_obj ) + __field( u64, ino ) + __field( loff_t, isize ) + __field( u64, disk_isize ) + __field( u64, num_bytes ) + __field( u64, ram_bytes ) + __field( u64, disk_bytenr ) + __field( u64, disk_num_bytes ) + __field( u64, extent_offset ) + __field( u8, extent_type ) + __field( u8, compression ) + __field( u64, extent_start ) + __field( u64, extent_end ) + ), + + TP_fast_assign_btrfs(bi->root->fs_info, + __entry->root_obj = bi->root->objectid; + __entry->ino = btrfs_ino(bi); + __entry->isize = bi->vfs_inode.i_size; + __entry->disk_isize = bi->disk_i_size; + __entry->num_bytes = btrfs_file_extent_num_bytes(l, fi); + __entry->ram_bytes = btrfs_file_extent_ram_bytes(l, fi); + __entry->disk_bytenr = btrfs_file_extent_disk_bytenr(l, fi); + __entry->disk_num_bytes = btrfs_file_extent_disk_num_bytes(l, fi); + __entry->extent_offset = btrfs_file_extent_offset(l, fi); + __entry->extent_type = btrfs_file_extent_type(l, fi); + __entry->compression = btrfs_file_extent_compression(l, fi); + __entry->extent_start = start; + __entry->extent_end = (start + __entry->num_bytes); + ), + + TP_printk_btrfs( + "root=%llu(%s) inode=%llu size=%llu disk_isize=%llu " + "file extent range=[%llu %llu] " + "(num_bytes=%llu ram_bytes=%llu disk_bytenr=%llu " + "disk_num_bytes=%llu extent_offset=%llu type=%s " + "compression=%u", + show_root_type(__entry->root_obj), __entry->ino, + __entry->isize, + __entry->disk_isize, __entry->extent_start, + __entry->extent_end, __entry->num_bytes, __entry->ram_bytes, + __entry->disk_bytenr, __entry->disk_num_bytes, + __entry->extent_offset, show_fi_type(__entry->extent_type), + __entry->compression) +); + +DECLARE_EVENT_CLASS( + btrfs__file_extent_item_inline, + + TP_PROTO(struct btrfs_inode *bi, struct extent_buffer *l, + struct btrfs_file_extent_item *fi, int slot, u64 start), + + TP_ARGS(bi, l, fi, slot, start), + + TP_STRUCT__entry_btrfs( + __field( u64, root_obj ) + __field( u64, ino ) + __field( loff_t, isize ) + __field( u64, disk_isize ) + __field( u8, extent_type ) + __field( u8, compression ) + __field( u64, extent_start ) + __field( u64, extent_end ) + ), + + TP_fast_assign_btrfs( + bi->root->fs_info, + __entry->root_obj = bi->root->objectid; + __entry->ino = btrfs_ino(bi); + __entry->isize = bi->vfs_inode.i_size; + __entry->disk_isize = bi->disk_i_size; + __entry->extent_type = btrfs_file_extent_type(l, fi); + __entry->compression = btrfs_file_extent_compression(l, fi); + __entry->extent_start = start; + __entry->extent_end = (start + btrfs_file_extent_inline_len(l, slot, fi)); + ), + + TP_printk_btrfs( + "root=%llu(%s) inode=%llu size=%llu disk_isize=%llu " + "file extent range=[%llu %llu] " + "extent_type=%s compression=%u", + show_root_type(__entry->root_obj), __entry->ino, __entry->isize, + __entry->disk_isize, __entry->extent_start, + __entry->extent_end, show_fi_type(__entry->extent_type), + __entry->compression) +); + +DEFINE_EVENT( + btrfs__file_extent_item_regular, btrfs_get_extent_show_fi_regular, + + TP_PROTO(struct btrfs_inode *bi, struct extent_buffer *l, + struct btrfs_file_extent_item *fi, u64 start), + + TP_ARGS(bi, l, fi, start) +); + +DEFINE_EVENT( + btrfs__file_extent_item_regular, btrfs_truncate_show_fi_regular, + + TP_PROTO(struct btrfs_inode *bi, struct extent_buffer *l, + struct btrfs_file_extent_item *fi, u64 start), + + TP_ARGS(bi, l, fi, start) +); + +DEFINE_EVENT( + btrfs__file_extent_item_inline, btrfs_get_extent_show_fi_inline, + + TP_PROTO(struct btrfs_inode *bi, struct extent_buffer *l, + struct btrfs_file_extent_item *fi, int slot, u64 start), + + TP_ARGS(bi, l, fi, slot, start) +); + +DEFINE_EVENT( + btrfs__file_extent_item_inline, btrfs_truncate_show_fi_inline, + + TP_PROTO(struct btrfs_inode *bi, struct extent_buffer *l, + struct btrfs_file_extent_item *fi, int slot, u64 start), + + TP_ARGS(bi, l, fi, slot, start) +); + #define show_ordered_flags(flags) \ __print_flags(flags, "|", \ { (1 << BTRFS_ORDERED_IO_DONE), "IO_DONE" }, \ @@ -275,7 +415,7 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent, __entry->bytes_left = ordered->bytes_left; __entry->flags = ordered->flags; __entry->compress_type = ordered->compress_type; - __entry->refs = atomic_read(&ordered->refs); + __entry->refs = refcount_read(&ordered->refs); __entry->root_objectid = BTRFS_I(inode)->root->root_key.objectid; __entry->truncated_len = ordered->truncated_len; @@ -1475,6 +1615,49 @@ TRACE_EVENT(qgroup_update_counters, __entry->cur_new_count) ); +TRACE_EVENT(qgroup_update_reserve, + + TP_PROTO(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup, + s64 diff), + + TP_ARGS(fs_info, qgroup, diff), + + TP_STRUCT__entry_btrfs( + __field( u64, qgid ) + __field( u64, cur_reserved ) + __field( s64, diff ) + ), + + TP_fast_assign_btrfs(fs_info, + __entry->qgid = qgroup->qgroupid; + __entry->cur_reserved = qgroup->reserved; + __entry->diff = diff; + ), + + TP_printk_btrfs("qgid=%llu cur_reserved=%llu diff=%lld", + __entry->qgid, __entry->cur_reserved, __entry->diff) +); + +TRACE_EVENT(qgroup_meta_reserve, + + TP_PROTO(struct btrfs_root *root, s64 diff), + + TP_ARGS(root, diff), + + TP_STRUCT__entry_btrfs( + __field( u64, refroot ) + __field( s64, diff ) + ), + + TP_fast_assign_btrfs(root->fs_info, + __entry->refroot = root->objectid; + __entry->diff = diff; + ), + + TP_printk_btrfs("refroot=%llu(%s) diff=%lld", + show_root_type(__entry->refroot), __entry->diff) +); + #endif /* _TRACE_BTRFS_H */ /* This part must be outside protection */ diff --git a/include/trace/events/iommu.h b/include/trace/events/iommu.h index 2c7befb10f13..99254ed89212 100644 --- a/include/trace/events/iommu.h +++ b/include/trace/events/iommu.h @@ -11,7 +11,6 @@ #define _TRACE_IOMMU_H #include <linux/tracepoint.h> -#include <linux/pci.h> struct device; diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index dcfc3a5a9cb1..a456e5309238 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -291,10 +291,10 @@ struct btrfs_ioctl_feature_flags { struct btrfs_balance_args { __u64 profiles; union { - __le64 usage; + __u64 usage; struct { - __le32 usage_min; - __le32 usage_max; + __u32 usage_min; + __u32 usage_max; }; }; __u64 devid; @@ -324,8 +324,8 @@ struct btrfs_balance_args { * Process chunks that cross stripes_min..stripes_max devices, * BTRFS_BALANCE_ARGS_STRIPES_RANGE */ - __le32 stripes_min; - __le32 stripes_max; + __u32 stripes_min; + __u32 stripes_max; __u64 unused[6]; } __attribute__ ((__packed__)); diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index 176b6cb1008d..b5280db9ef6a 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -419,7 +419,7 @@ typedef struct elf64_shdr { #define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */ #define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */ #define NT_METAG_TLS 0x502 /* Metag TLS pointer */ - +#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ /* Note header in a PT_NOTE section */ typedef struct elf32_note { diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h new file mode 100644 index 000000000000..370d8845ab21 --- /dev/null +++ b/include/uapi/linux/tee.h @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2015-2016, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TEE_H +#define __TEE_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +/* + * This file describes the API provided by a TEE driver to user space. + * + * Each TEE driver defines a TEE specific protocol which is used for the + * data passed back and forth using TEE_IOC_CMD. + */ + +/* Helpers to make the ioctl defines */ +#define TEE_IOC_MAGIC 0xa4 +#define TEE_IOC_BASE 0 + +/* Flags relating to shared memory */ +#define TEE_IOCTL_SHM_MAPPED 0x1 /* memory mapped in normal world */ +#define TEE_IOCTL_SHM_DMA_BUF 0x2 /* dma-buf handle on shared memory */ + +#define TEE_MAX_ARG_SIZE 1024 + +#define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */ + +/* + * TEE Implementation ID + */ +#define TEE_IMPL_ID_OPTEE 1 + +/* + * OP-TEE specific capabilities + */ +#define TEE_OPTEE_CAP_TZ (1 << 0) + +/** + * struct tee_ioctl_version_data - TEE version + * @impl_id: [out] TEE implementation id + * @impl_caps: [out] Implementation specific capabilities + * @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above + * + * Identifies the TEE implementation, @impl_id is one of TEE_IMPL_ID_* above. + * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_* + * is valid when @impl_id == TEE_IMPL_ID_OPTEE. + */ +struct tee_ioctl_version_data { + __u32 impl_id; + __u32 impl_caps; + __u32 gen_caps; +}; + +/** + * TEE_IOC_VERSION - query version of TEE + * + * Takes a tee_ioctl_version_data struct and returns with the TEE version + * data filled in. + */ +#define TEE_IOC_VERSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 0, \ + struct tee_ioctl_version_data) + +/** + * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument + * @size: [in/out] Size of shared memory to allocate + * @flags: [in/out] Flags to/from allocation. + * @id: [out] Identifier of the shared memory + * + * The flags field should currently be zero as input. Updated by the call + * with actual flags as defined by TEE_IOCTL_SHM_* above. + * This structure is used as argument for TEE_IOC_SHM_ALLOC below. + */ +struct tee_ioctl_shm_alloc_data { + __u64 size; + __u32 flags; + __s32 id; +}; + +/** + * TEE_IOC_SHM_ALLOC - allocate shared memory + * + * Allocates shared memory between the user space process and secure OS. + * + * Returns a file descriptor on success or < 0 on failure + * + * The returned file descriptor is used to map the shared memory into user + * space. The shared memory is freed when the descriptor is closed and the + * memory is unmapped. + */ +#define TEE_IOC_SHM_ALLOC _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 1, \ + struct tee_ioctl_shm_alloc_data) + +/** + * struct tee_ioctl_buf_data - Variable sized buffer + * @buf_ptr: [in] A __user pointer to a buffer + * @buf_len: [in] Length of the buffer above + * + * Used as argument for TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE, + * TEE_IOC_SUPPL_RECV, and TEE_IOC_SUPPL_SEND below. + */ +struct tee_ioctl_buf_data { + __u64 buf_ptr; + __u64 buf_len; +}; + +/* + * Attributes for struct tee_ioctl_param, selects field in the union + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_NONE 0 /* parameter not used */ + +/* + * These defines value parameters (struct tee_ioctl_param_value) + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT 1 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT 2 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT 3 /* input and output */ + +/* + * These defines shared memory reference parameters (struct + * tee_ioctl_param_memref) + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT 5 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */ + +/* + * Mask for the type part of the attribute, leaves room for more types + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff + +/* + * Matches TEEC_LOGIN_* in GP TEE Client API + * Are only defined for GP compliant TEEs + */ +#define TEE_IOCTL_LOGIN_PUBLIC 0 +#define TEE_IOCTL_LOGIN_USER 1 +#define TEE_IOCTL_LOGIN_GROUP 2 +#define TEE_IOCTL_LOGIN_APPLICATION 4 +#define TEE_IOCTL_LOGIN_USER_APPLICATION 5 +#define TEE_IOCTL_LOGIN_GROUP_APPLICATION 6 + +/** + * struct tee_ioctl_param - parameter + * @attr: attributes + * @a: if a memref, offset into the shared memory object, else a value parameter + * @b: if a memref, size of the buffer, else a value parameter + * @c: if a memref, shared memory identifier, else a value parameter + * + * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in + * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE + * indicates that none of the members are used. + * + * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an + * identifier representing the shared memory object. A memref can reference + * a part of a shared memory by specifying an offset (@a) and size (@b) of + * the object. To supply the entire shared memory object set the offset + * (@a) to 0 and size (@b) to the previously returned size of the object. + */ +struct tee_ioctl_param { + __u64 attr; + __u64 a; + __u64 b; + __u64 c; +}; + +#define TEE_IOCTL_UUID_LEN 16 + +/** + * struct tee_ioctl_open_session_arg - Open session argument + * @uuid: [in] UUID of the Trusted Application + * @clnt_uuid: [in] UUID of client + * @clnt_login: [in] Login class of client, TEE_IOCTL_LOGIN_* above + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @session: [out] Session id + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ +struct tee_ioctl_open_session_arg { + __u8 uuid[TEE_IOCTL_UUID_LEN]; + __u8 clnt_uuid[TEE_IOCTL_UUID_LEN]; + __u32 clnt_login; + __u32 cancel_id; + __u32 session; + __u32 ret; + __u32 ret_origin; + __u32 num_params; + /* num_params tells the actual number of element in params */ + struct tee_ioctl_param params[]; +}; + +/** + * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_ioctl_open_session_arg followed by any array of struct + * tee_ioctl_param + */ +#define TEE_IOC_OPEN_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \ + struct tee_ioctl_buf_data) + +/** + * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted + * Application + * @func: [in] Trusted Application function, specific to the TA + * @session: [in] Session id + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ +struct tee_ioctl_invoke_arg { + __u32 func; + __u32 session; + __u32 cancel_id; + __u32 ret; + __u32 ret_origin; + __u32 num_params; + /* num_params tells the actual number of element in params */ + struct tee_ioctl_param params[]; +}; + +/** + * TEE_IOC_INVOKE - Invokes a function in a Trusted Application + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_invoke_func_arg followed by any array of struct tee_param + */ +#define TEE_IOC_INVOKE _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 3, \ + struct tee_ioctl_buf_data) + +/** + * struct tee_ioctl_cancel_arg - Cancels an open session or invoke ioctl + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @session: [in] Session id, if the session is opened, else set to 0 + */ +struct tee_ioctl_cancel_arg { + __u32 cancel_id; + __u32 session; +}; + +/** + * TEE_IOC_CANCEL - Cancels an open session or invoke + */ +#define TEE_IOC_CANCEL _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 4, \ + struct tee_ioctl_cancel_arg) + +/** + * struct tee_ioctl_close_session_arg - Closes an open session + * @session: [in] Session id + */ +struct tee_ioctl_close_session_arg { + __u32 session; +}; + +/** + * TEE_IOC_CLOSE_SESSION - Closes a session + */ +#define TEE_IOC_CLOSE_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 5, \ + struct tee_ioctl_close_session_arg) + +/** + * struct tee_iocl_supp_recv_arg - Receive a request for a supplicant function + * @func: [in] supplicant function + * @num_params [in/out] number of parameters following this struct + * + * @num_params is the number of params that tee-supplicant has room to + * receive when input, @num_params is the number of actual params + * tee-supplicant receives when output. + */ +struct tee_iocl_supp_recv_arg { + __u32 func; + __u32 num_params; + /* num_params tells the actual number of element in params */ + struct tee_ioctl_param params[]; +}; + +/** + * TEE_IOC_SUPPL_RECV - Receive a request for a supplicant function + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_iocl_supp_recv_arg followed by any array of struct tee_param + */ +#define TEE_IOC_SUPPL_RECV _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 6, \ + struct tee_ioctl_buf_data) + +/** + * struct tee_iocl_supp_send_arg - Send a response to a received request + * @ret: [out] return value + * @num_params [in] number of parameters following this struct + */ +struct tee_iocl_supp_send_arg { + __u32 ret; + __u32 num_params; + /* num_params tells the actual number of element in params */ + struct tee_ioctl_param params[]; +}; + +/** + * TEE_IOC_SUPPL_SEND - Receive a request for a supplicant function + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_iocl_supp_send_arg followed by any array of struct tee_param + */ +#define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \ + struct tee_ioctl_buf_data) + +/* + * Five syscalls are used when communicating with the TEE driver. + * open(): opens the device associated with the driver + * ioctl(): as described above operating on the file descriptor from open() + * close(): two cases + * - closes the device file descriptor + * - closes a file descriptor connected to allocated shared memory + * mmap(): maps shared memory into user space using information from struct + * tee_ioctl_shm_alloc_data + * munmap(): unmaps previously shared memory + */ + +#endif /*__TEE_H*/ diff --git a/init/Kconfig b/init/Kconfig index a92f27da4a27..1d3475fc9496 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -521,11 +521,41 @@ config RCU_EXPERT config SRCU bool + default y help This option selects the sleepable version of RCU. This version permits arbitrary sleeping or blocking within RCU read-side critical sections. +config CLASSIC_SRCU + bool "Use v4.11 classic SRCU implementation" + default n + depends on RCU_EXPERT && SRCU + help + This option selects the traditional well-tested classic SRCU + implementation from v4.11, as might be desired for enterprise + Linux distributions. Without this option, the shiny new + Tiny SRCU and Tree SRCU implementations are used instead. + At some point, it is hoped that Tiny SRCU and Tree SRCU + will accumulate enough test time and confidence to allow + Classic SRCU to be dropped entirely. + + Say Y if you need a rock-solid SRCU. + + Say N if you would like help test Tree SRCU. + +config TINY_SRCU + bool + default y if SRCU && TINY_RCU && !CLASSIC_SRCU + help + This option selects the single-CPU non-preemptible version of SRCU. + +config TREE_SRCU + bool + default y if SRCU && !TINY_RCU && !CLASSIC_SRCU + help + This option selects the full-fledged version of SRCU. + config TASKS_RCU bool default n @@ -543,6 +573,9 @@ config RCU_STALL_COMMON the tiny variants to disable RCU CPU stall warnings, while making these warnings mandatory for the tree variants. +config RCU_NEED_SEGCBLIST + def_bool ( TREE_RCU || PREEMPT_RCU || TINY_SRCU || TREE_SRCU ) + config CONTEXT_TRACKING bool @@ -612,11 +645,17 @@ config RCU_FANOUT_LEAF initialization. These systems tend to run CPU-bound, and thus are not helped by synchronized interrupts, and thus tend to skew them, which reduces lock contention enough that large - leaf-level fanouts work well. + leaf-level fanouts work well. That said, setting leaf-level + fanout to a large number will likely cause problematic + lock contention on the leaf-level rcu_node structures unless + you boot with the skew_tick kernel parameter. Select a specific number if testing RCU itself. - Select the maximum permissible value for large systems. + Select the maximum permissible value for large systems, but + please understand that you may also need to set the skew_tick + kernel boot parameter to avoid contention on the rcu_node + structure's locks. Take the default if unsure. diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index fddcae801724..9bbd33497d3d 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -429,7 +429,7 @@ static int bpf_parse_options(char *data, struct bpf_mount_opts *opts) static int bpf_fill_super(struct super_block *sb, void *data, int silent) { - static struct tree_descr bpf_rfiles[] = { { "" } }; + static const struct tree_descr bpf_rfiles[] = { { "" } }; struct bpf_mount_opts opts; struct inode *inode; int ret; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c2ff608c1984..c5b56c92f8e2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -298,7 +298,8 @@ static const char *const bpf_jmp_string[16] = { [BPF_EXIT >> 4] = "exit", }; -static void print_bpf_insn(struct bpf_insn *insn) +static void print_bpf_insn(const struct bpf_verifier_env *env, + const struct bpf_insn *insn) { u8 class = BPF_CLASS(insn->code); @@ -362,9 +363,19 @@ static void print_bpf_insn(struct bpf_insn *insn) insn->code, bpf_ldst_string[BPF_SIZE(insn->code) >> 3], insn->src_reg, insn->imm); - } else if (BPF_MODE(insn->code) == BPF_IMM) { - verbose("(%02x) r%d = 0x%x\n", - insn->code, insn->dst_reg, insn->imm); + } else if (BPF_MODE(insn->code) == BPF_IMM && + BPF_SIZE(insn->code) == BPF_DW) { + /* At this point, we already made sure that the second + * part of the ldimm64 insn is accessible. + */ + u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm; + bool map_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD; + + if (map_ptr && !env->allow_ptr_leaks) + imm = 0; + + verbose("(%02x) r%d = 0x%llx\n", insn->code, + insn->dst_reg, (unsigned long long)imm); } else { verbose("BUG_ld_%02x\n", insn->code); return; @@ -2853,7 +2864,7 @@ static int do_check(struct bpf_verifier_env *env) if (log_level) { verbose("%d: ", insn_idx); - print_bpf_insn(insn); + print_bpf_insn(env, insn); } err = ext_analyzer_insn_hook(env, insn_idx, prev_insn_idx); diff --git a/kernel/fork.c b/kernel/fork.c index 08ba696aa561..bfd91b180778 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1337,7 +1337,7 @@ void __cleanup_sighand(struct sighand_struct *sighand) if (atomic_dec_and_test(&sighand->count)) { signalfd_cleanup(sighand); /* - * sighand_cachep is SLAB_DESTROY_BY_RCU so we can free it + * sighand_cachep is SLAB_TYPESAFE_BY_RCU so we can free it * without an RCU grace period, see __lock_task_sighand(). */ kmem_cache_free(sighand_cachep, sighand); @@ -2176,7 +2176,7 @@ void __init proc_caches_init(void) { sighand_cachep = kmem_cache_create("sighand_cache", sizeof(struct sighand_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU| + SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_TYPESAFE_BY_RCU| SLAB_NOTRACK|SLAB_ACCOUNT, sighand_ctor); signal_cachep = kmem_cache_create("signal_cache", sizeof(struct signal_struct), 0, diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 0a1b3c748478..c0e31bfee25c 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -1158,10 +1158,10 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth, return 0; printk("\n"); - printk("======================================================\n"); - printk("[ INFO: possible circular locking dependency detected ]\n"); + pr_warn("======================================================\n"); + pr_warn("WARNING: possible circular locking dependency detected\n"); print_kernel_ident(); - printk("-------------------------------------------------------\n"); + pr_warn("------------------------------------------------------\n"); printk("%s/%d is trying to acquire lock:\n", curr->comm, task_pid_nr(curr)); print_lock(check_src); @@ -1496,11 +1496,11 @@ print_bad_irq_dependency(struct task_struct *curr, return 0; printk("\n"); - printk("======================================================\n"); - printk("[ INFO: %s-safe -> %s-unsafe lock order detected ]\n", + pr_warn("=====================================================\n"); + pr_warn("WARNING: %s-safe -> %s-unsafe lock order detected\n", irqclass, irqclass); print_kernel_ident(); - printk("------------------------------------------------------\n"); + pr_warn("-----------------------------------------------------\n"); printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] is trying to acquire:\n", curr->comm, task_pid_nr(curr), curr->hardirq_context, hardirq_count() >> HARDIRQ_SHIFT, @@ -1725,10 +1725,10 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev, return 0; printk("\n"); - printk("=============================================\n"); - printk("[ INFO: possible recursive locking detected ]\n"); + pr_warn("============================================\n"); + pr_warn("WARNING: possible recursive locking detected\n"); print_kernel_ident(); - printk("---------------------------------------------\n"); + pr_warn("--------------------------------------------\n"); printk("%s/%d is trying to acquire lock:\n", curr->comm, task_pid_nr(curr)); print_lock(next); @@ -2075,10 +2075,10 @@ static void print_collision(struct task_struct *curr, struct lock_chain *chain) { printk("\n"); - printk("======================\n"); - printk("[chain_key collision ]\n"); + pr_warn("============================\n"); + pr_warn("WARNING: chain_key collision\n"); print_kernel_ident(); - printk("----------------------\n"); + pr_warn("----------------------------\n"); printk("%s/%d: ", current->comm, task_pid_nr(current)); printk("Hash chain already cached but the contents don't match!\n"); @@ -2374,10 +2374,10 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this, return 0; printk("\n"); - printk("=================================\n"); - printk("[ INFO: inconsistent lock state ]\n"); + pr_warn("================================\n"); + pr_warn("WARNING: inconsistent lock state\n"); print_kernel_ident(); - printk("---------------------------------\n"); + pr_warn("--------------------------------\n"); printk("inconsistent {%s} -> {%s} usage.\n", usage_str[prev_bit], usage_str[new_bit]); @@ -2439,10 +2439,10 @@ print_irq_inversion_bug(struct task_struct *curr, return 0; printk("\n"); - printk("=========================================================\n"); - printk("[ INFO: possible irq lock inversion dependency detected ]\n"); + pr_warn("========================================================\n"); + pr_warn("WARNING: possible irq lock inversion dependency detected\n"); print_kernel_ident(); - printk("---------------------------------------------------------\n"); + pr_warn("--------------------------------------------------------\n"); printk("%s/%d just changed the state of lock:\n", curr->comm, task_pid_nr(curr)); print_lock(this); @@ -3190,10 +3190,10 @@ print_lock_nested_lock_not_held(struct task_struct *curr, return 0; printk("\n"); - printk("==================================\n"); - printk("[ BUG: Nested lock was not taken ]\n"); + pr_warn("==================================\n"); + pr_warn("WARNING: Nested lock was not taken\n"); print_kernel_ident(); - printk("----------------------------------\n"); + pr_warn("----------------------------------\n"); printk("%s/%d is trying to lock:\n", curr->comm, task_pid_nr(curr)); print_lock(hlock); @@ -3403,10 +3403,10 @@ print_unlock_imbalance_bug(struct task_struct *curr, struct lockdep_map *lock, return 0; printk("\n"); - printk("=====================================\n"); - printk("[ BUG: bad unlock balance detected! ]\n"); + pr_warn("=====================================\n"); + pr_warn("WARNING: bad unlock balance detected!\n"); print_kernel_ident(); - printk("-------------------------------------\n"); + pr_warn("-------------------------------------\n"); printk("%s/%d is trying to release lock (", curr->comm, task_pid_nr(curr)); print_lockdep_cache(lock); @@ -3975,10 +3975,10 @@ print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock, return 0; printk("\n"); - printk("=================================\n"); - printk("[ BUG: bad contention detected! ]\n"); + pr_warn("=================================\n"); + pr_warn("WARNING: bad contention detected!\n"); print_kernel_ident(); - printk("---------------------------------\n"); + pr_warn("---------------------------------\n"); printk("%s/%d is trying to contend lock (", curr->comm, task_pid_nr(curr)); print_lockdep_cache(lock); @@ -4319,10 +4319,10 @@ print_freed_lock_bug(struct task_struct *curr, const void *mem_from, return; printk("\n"); - printk("=========================\n"); - printk("[ BUG: held lock freed! ]\n"); + pr_warn("=========================\n"); + pr_warn("WARNING: held lock freed!\n"); print_kernel_ident(); - printk("-------------------------\n"); + pr_warn("-------------------------\n"); printk("%s/%d is freeing memory %p-%p, with a lock still held there!\n", curr->comm, task_pid_nr(curr), mem_from, mem_to-1); print_lock(hlock); @@ -4377,11 +4377,11 @@ static void print_held_locks_bug(void) return; printk("\n"); - printk("=====================================\n"); - printk("[ BUG: %s/%d still has locks held! ]\n", + pr_warn("====================================\n"); + pr_warn("WARNING: %s/%d still has locks held!\n", current->comm, task_pid_nr(current)); print_kernel_ident(); - printk("-------------------------------------\n"); + pr_warn("------------------------------------\n"); lockdep_print_held_locks(current); printk("\nstack backtrace:\n"); dump_stack(); @@ -4446,7 +4446,7 @@ retry: } while_each_thread(g, p); printk("\n"); - printk("=============================================\n\n"); + pr_warn("=============================================\n\n"); if (unlock) read_unlock(&tasklist_lock); @@ -4476,10 +4476,10 @@ asmlinkage __visible void lockdep_sys_exit(void) if (!debug_locks_off()) return; printk("\n"); - printk("================================================\n"); - printk("[ BUG: lock held when returning to user space! ]\n"); + pr_warn("================================================\n"); + pr_warn("WARNING: lock held when returning to user space!\n"); print_kernel_ident(); - printk("------------------------------------------------\n"); + pr_warn("------------------------------------------------\n"); printk("%s/%d is leaving the kernel with locks still held!\n", curr->comm, curr->pid); lockdep_print_held_locks(curr); @@ -4496,13 +4496,13 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s) #endif /* #ifdef CONFIG_PROVE_RCU_REPEATEDLY */ /* Note: the following can be executed concurrently, so be careful. */ printk("\n"); - pr_err("===============================\n"); - pr_err("[ ERR: suspicious RCU usage. ]\n"); + pr_warn("=============================\n"); + pr_warn("WARNING: suspicious RCU usage\n"); print_kernel_ident(); - pr_err("-------------------------------\n"); - pr_err("%s:%d %s!\n", file, line, s); - pr_err("\nother info that might help us debug this:\n\n"); - pr_err("\n%srcu_scheduler_active = %d, debug_locks = %d\n", + pr_warn("-----------------------------\n"); + printk("%s:%d %s!\n", file, line, s); + printk("\nother info that might help us debug this:\n\n"); + printk("\n%srcu_scheduler_active = %d, debug_locks = %d\n", !rcu_lockdep_current_cpu_online() ? "RCU used illegally from offline CPU!\n" : !rcu_is_watching() diff --git a/kernel/locking/rtmutex-debug.c b/kernel/locking/rtmutex-debug.c index 32fe775a2eaf..58e366ad36f4 100644 --- a/kernel/locking/rtmutex-debug.c +++ b/kernel/locking/rtmutex-debug.c @@ -102,10 +102,11 @@ void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter) return; } - printk("\n============================================\n"); - printk( "[ BUG: circular locking deadlock detected! ]\n"); - printk("%s\n", print_tainted()); - printk( "--------------------------------------------\n"); + pr_warn("\n"); + pr_warn("============================================\n"); + pr_warn("WARNING: circular locking deadlock detected!\n"); + pr_warn("%s\n", print_tainted()); + pr_warn("--------------------------------------------\n"); printk("%s/%d is deadlocking current task %s/%d\n\n", task->comm, task_pid_nr(task), current->comm, task_pid_nr(current)); diff --git a/kernel/power/process.c b/kernel/power/process.c index c7209f060eeb..78672d324a6e 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -132,7 +132,7 @@ int freeze_processes(void) if (!pm_freezing) atomic_inc(&system_freezing_cnt); - pm_wakeup_clear(); + pm_wakeup_clear(true); pr_info("Freezing user space processes ... "); pm_freezing = true; error = try_to_freeze_tasks(true); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 15e6baef5c73..c0248c74d6d4 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -72,6 +72,8 @@ static void freeze_begin(void) static void freeze_enter(void) { + trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, true); + spin_lock_irq(&suspend_freeze_lock); if (pm_wakeup_pending()) goto out; @@ -98,6 +100,27 @@ static void freeze_enter(void) out: suspend_freeze_state = FREEZE_STATE_NONE; spin_unlock_irq(&suspend_freeze_lock); + + trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, false); +} + +static void s2idle_loop(void) +{ + do { + freeze_enter(); + + if (freeze_ops && freeze_ops->wake) + freeze_ops->wake(); + + dpm_resume_noirq(PMSG_RESUME); + if (freeze_ops && freeze_ops->sync) + freeze_ops->sync(); + + if (pm_wakeup_pending()) + break; + + pm_wakeup_clear(false); + } while (!dpm_suspend_noirq(PMSG_SUSPEND)); } void freeze_wake(void) @@ -371,10 +394,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) * all the devices are suspended. */ if (state == PM_SUSPEND_FREEZE) { - trace_suspend_resume(TPS("machine_suspend"), state, true); - freeze_enter(); - trace_suspend_resume(TPS("machine_suspend"), state, false); - goto Platform_wake; + s2idle_loop(); + goto Platform_early_resume; } error = disable_nonboot_cpus(); diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile index 18dfc485225c..23803c7d5180 100644 --- a/kernel/rcu/Makefile +++ b/kernel/rcu/Makefile @@ -3,10 +3,13 @@ KCOV_INSTRUMENT := n obj-y += update.o sync.o -obj-$(CONFIG_SRCU) += srcu.o +obj-$(CONFIG_CLASSIC_SRCU) += srcu.o +obj-$(CONFIG_TREE_SRCU) += srcutree.o +obj-$(CONFIG_TINY_SRCU) += srcutiny.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_RCU_PERF_TEST) += rcuperf.o obj-$(CONFIG_TREE_RCU) += tree.o obj-$(CONFIG_PREEMPT_RCU) += tree.o obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o obj-$(CONFIG_TINY_RCU) += tiny.o +obj-$(CONFIG_RCU_NEED_SEGCBLIST) += rcu_segcblist.o diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index 0d6ff3e471be..73e16ec4054b 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -56,6 +56,83 @@ #define DYNTICK_TASK_EXIT_IDLE (DYNTICK_TASK_NEST_VALUE + \ DYNTICK_TASK_FLAG) + +/* + * Grace-period counter management. + */ + +#define RCU_SEQ_CTR_SHIFT 2 +#define RCU_SEQ_STATE_MASK ((1 << RCU_SEQ_CTR_SHIFT) - 1) + +/* + * Return the counter portion of a sequence number previously returned + * by rcu_seq_snap() or rcu_seq_current(). + */ +static inline unsigned long rcu_seq_ctr(unsigned long s) +{ + return s >> RCU_SEQ_CTR_SHIFT; +} + +/* + * Return the state portion of a sequence number previously returned + * by rcu_seq_snap() or rcu_seq_current(). + */ +static inline int rcu_seq_state(unsigned long s) +{ + return s & RCU_SEQ_STATE_MASK; +} + +/* + * Set the state portion of the pointed-to sequence number. + * The caller is responsible for preventing conflicting updates. + */ +static inline void rcu_seq_set_state(unsigned long *sp, int newstate) +{ + WARN_ON_ONCE(newstate & ~RCU_SEQ_STATE_MASK); + WRITE_ONCE(*sp, (*sp & ~RCU_SEQ_STATE_MASK) + newstate); +} + +/* Adjust sequence number for start of update-side operation. */ +static inline void rcu_seq_start(unsigned long *sp) +{ + WRITE_ONCE(*sp, *sp + 1); + smp_mb(); /* Ensure update-side operation after counter increment. */ + WARN_ON_ONCE(rcu_seq_state(*sp) != 1); +} + +/* Adjust sequence number for end of update-side operation. */ +static inline void rcu_seq_end(unsigned long *sp) +{ + smp_mb(); /* Ensure update-side operation before counter increment. */ + WARN_ON_ONCE(!rcu_seq_state(*sp)); + WRITE_ONCE(*sp, (*sp | RCU_SEQ_STATE_MASK) + 1); +} + +/* Take a snapshot of the update side's sequence number. */ +static inline unsigned long rcu_seq_snap(unsigned long *sp) +{ + unsigned long s; + + s = (READ_ONCE(*sp) + 2 * RCU_SEQ_STATE_MASK + 1) & ~RCU_SEQ_STATE_MASK; + smp_mb(); /* Above access must not bleed into critical section. */ + return s; +} + +/* Return the current value the update side's sequence number, no ordering. */ +static inline unsigned long rcu_seq_current(unsigned long *sp) +{ + return READ_ONCE(*sp); +} + +/* + * Given a snapshot from rcu_seq_snap(), determine whether or not a + * full update-side operation has occurred. + */ +static inline bool rcu_seq_done(unsigned long *sp, unsigned long s) +{ + return ULONG_CMP_GE(READ_ONCE(*sp), s); +} + /* * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally * by call_rcu() and rcu callback execution, and are therefore not part of the @@ -109,12 +186,12 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) rcu_lock_acquire(&rcu_callback_map); if (__is_kfree_rcu_offset(offset)) { - RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); + RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset);) kfree((void *)head - offset); rcu_lock_release(&rcu_callback_map); return true; } else { - RCU_TRACE(trace_rcu_invoke_callback(rn, head)); + RCU_TRACE(trace_rcu_invoke_callback(rn, head);) head->func(head); rcu_lock_release(&rcu_callback_map); return false; @@ -144,4 +221,76 @@ void rcu_test_sync_prims(void); */ extern void resched_cpu(int cpu); +#if defined(SRCU) || !defined(TINY_RCU) + +#include <linux/rcu_node_tree.h> + +extern int rcu_num_lvls; +extern int num_rcu_lvl[]; +extern int rcu_num_nodes; +static bool rcu_fanout_exact; +static int rcu_fanout_leaf; + +/* + * Compute the per-level fanout, either using the exact fanout specified + * or balancing the tree, depending on the rcu_fanout_exact boot parameter. + */ +static inline void rcu_init_levelspread(int *levelspread, const int *levelcnt) +{ + int i; + + if (rcu_fanout_exact) { + levelspread[rcu_num_lvls - 1] = rcu_fanout_leaf; + for (i = rcu_num_lvls - 2; i >= 0; i--) + levelspread[i] = RCU_FANOUT; + } else { + int ccur; + int cprv; + + cprv = nr_cpu_ids; + for (i = rcu_num_lvls - 1; i >= 0; i--) { + ccur = levelcnt[i]; + levelspread[i] = (cprv + ccur - 1) / ccur; + cprv = ccur; + } + } +} + +/* + * Do a full breadth-first scan of the rcu_node structures for the + * specified rcu_state structure. + */ +#define rcu_for_each_node_breadth_first(rsp, rnp) \ + for ((rnp) = &(rsp)->node[0]; \ + (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++) + +/* + * Do a breadth-first scan of the non-leaf rcu_node structures for the + * specified rcu_state structure. Note that if there is a singleton + * rcu_node tree with but one rcu_node structure, this loop is a no-op. + */ +#define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \ + for ((rnp) = &(rsp)->node[0]; \ + (rnp) < (rsp)->level[rcu_num_lvls - 1]; (rnp)++) + +/* + * Scan the leaves of the rcu_node hierarchy for the specified rcu_state + * structure. Note that if there is a singleton rcu_node tree with but + * one rcu_node structure, this loop -will- visit the rcu_node structure. + * It is still a leaf node, even if it is also the root node. + */ +#define rcu_for_each_leaf_node(rsp, rnp) \ + for ((rnp) = (rsp)->level[rcu_num_lvls - 1]; \ + (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++) + +/* + * Iterate over all possible CPUs in a leaf RCU node. + */ +#define for_each_leaf_node_possible_cpu(rnp, cpu) \ + for ((cpu) = cpumask_next(rnp->grplo - 1, cpu_possible_mask); \ + cpu <= rnp->grphi; \ + cpu = cpumask_next((cpu), cpu_possible_mask)) + +#endif /* #if defined(SRCU) || !defined(TINY_RCU) */ + #endif /* __LINUX_RCU_H */ diff --git a/kernel/rcu/rcu_segcblist.c b/kernel/rcu/rcu_segcblist.c new file mode 100644 index 000000000000..2b62a38b080f --- /dev/null +++ b/kernel/rcu/rcu_segcblist.c @@ -0,0 +1,505 @@ +/* + * RCU segmented callback lists, function definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright IBM Corporation, 2017 + * + * Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> + +#include "rcu_segcblist.h" + +/* Initialize simple callback list. */ +void rcu_cblist_init(struct rcu_cblist *rclp) +{ + rclp->head = NULL; + rclp->tail = &rclp->head; + rclp->len = 0; + rclp->len_lazy = 0; +} + +/* + * Debug function to actually count the number of callbacks. + * If the number exceeds the limit specified, return -1. + */ +long rcu_cblist_count_cbs(struct rcu_cblist *rclp, long lim) +{ + int cnt = 0; + struct rcu_head **rhpp = &rclp->head; + + for (;;) { + if (!*rhpp) + return cnt; + if (++cnt > lim) + return -1; + rhpp = &(*rhpp)->next; + } +} + +/* + * Dequeue the oldest rcu_head structure from the specified callback + * list. This function assumes that the callback is non-lazy, but + * the caller can later invoke rcu_cblist_dequeued_lazy() if it + * finds otherwise (and if it cares about laziness). This allows + * different users to have different ways of determining laziness. + */ +struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp) +{ + struct rcu_head *rhp; + + rhp = rclp->head; + if (!rhp) + return NULL; + rclp->len--; + rclp->head = rhp->next; + if (!rclp->head) + rclp->tail = &rclp->head; + return rhp; +} + +/* + * Initialize an rcu_segcblist structure. + */ +void rcu_segcblist_init(struct rcu_segcblist *rsclp) +{ + int i; + + BUILD_BUG_ON(RCU_NEXT_TAIL + 1 != ARRAY_SIZE(rsclp->gp_seq)); + BUILD_BUG_ON(ARRAY_SIZE(rsclp->tails) != ARRAY_SIZE(rsclp->gp_seq)); + rsclp->head = NULL; + for (i = 0; i < RCU_CBLIST_NSEGS; i++) + rsclp->tails[i] = &rsclp->head; + rsclp->len = 0; + rsclp->len_lazy = 0; +} + +/* + * Disable the specified rcu_segcblist structure, so that callbacks can + * no longer be posted to it. This structure must be empty. + */ +void rcu_segcblist_disable(struct rcu_segcblist *rsclp) +{ + WARN_ON_ONCE(!rcu_segcblist_empty(rsclp)); + WARN_ON_ONCE(rcu_segcblist_n_cbs(rsclp)); + WARN_ON_ONCE(rcu_segcblist_n_lazy_cbs(rsclp)); + rsclp->tails[RCU_NEXT_TAIL] = NULL; +} + +/* + * Is the specified segment of the specified rcu_segcblist structure + * empty of callbacks? + */ +bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg) +{ + if (seg == RCU_DONE_TAIL) + return &rsclp->head == rsclp->tails[RCU_DONE_TAIL]; + return rsclp->tails[seg - 1] == rsclp->tails[seg]; +} + +/* + * Does the specified rcu_segcblist structure contain callbacks that + * are ready to be invoked? + */ +bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp) +{ + return rcu_segcblist_is_enabled(rsclp) && + &rsclp->head != rsclp->tails[RCU_DONE_TAIL]; +} + +/* + * Does the specified rcu_segcblist structure contain callbacks that + * are still pending, that is, not yet ready to be invoked? + */ +bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp) +{ + return rcu_segcblist_is_enabled(rsclp) && + !rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL); +} + +/* + * Dequeue and return the first ready-to-invoke callback. If there + * are no ready-to-invoke callbacks, return NULL. Disables interrupts + * to avoid interference. Does not protect from interference from other + * CPUs or tasks. + */ +struct rcu_head *rcu_segcblist_dequeue(struct rcu_segcblist *rsclp) +{ + unsigned long flags; + int i; + struct rcu_head *rhp; + + local_irq_save(flags); + if (!rcu_segcblist_ready_cbs(rsclp)) { + local_irq_restore(flags); + return NULL; + } + rhp = rsclp->head; + BUG_ON(!rhp); + rsclp->head = rhp->next; + for (i = RCU_DONE_TAIL; i < RCU_CBLIST_NSEGS; i++) { + if (rsclp->tails[i] != &rhp->next) + break; + rsclp->tails[i] = &rsclp->head; + } + smp_mb(); /* Dequeue before decrement for rcu_barrier(). */ + WRITE_ONCE(rsclp->len, rsclp->len - 1); + local_irq_restore(flags); + return rhp; +} + +/* + * Account for the fact that a previously dequeued callback turned out + * to be marked as lazy. + */ +void rcu_segcblist_dequeued_lazy(struct rcu_segcblist *rsclp) +{ + unsigned long flags; + + local_irq_save(flags); + rsclp->len_lazy--; + local_irq_restore(flags); +} + +/* + * Return a pointer to the first callback in the specified rcu_segcblist + * structure. This is useful for diagnostics. + */ +struct rcu_head *rcu_segcblist_first_cb(struct rcu_segcblist *rsclp) +{ + if (rcu_segcblist_is_enabled(rsclp)) + return rsclp->head; + return NULL; +} + +/* + * Return a pointer to the first pending callback in the specified + * rcu_segcblist structure. This is useful just after posting a given + * callback -- if that callback is the first pending callback, then + * you cannot rely on someone else having already started up the required + * grace period. + */ +struct rcu_head *rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp) +{ + if (rcu_segcblist_is_enabled(rsclp)) + return *rsclp->tails[RCU_DONE_TAIL]; + return NULL; +} + +/* + * Does the specified rcu_segcblist structure contain callbacks that + * have not yet been processed beyond having been posted, that is, + * does it contain callbacks in its last segment? + */ +bool rcu_segcblist_new_cbs(struct rcu_segcblist *rsclp) +{ + return rcu_segcblist_is_enabled(rsclp) && + !rcu_segcblist_restempty(rsclp, RCU_NEXT_READY_TAIL); +} + +/* + * Enqueue the specified callback onto the specified rcu_segcblist + * structure, updating accounting as needed. Note that the ->len + * field may be accessed locklessly, hence the WRITE_ONCE(). + * The ->len field is used by rcu_barrier() and friends to determine + * if it must post a callback on this structure, and it is OK + * for rcu_barrier() to sometimes post callbacks needlessly, but + * absolutely not OK for it to ever miss posting a callback. + */ +void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp, + struct rcu_head *rhp, bool lazy) +{ + WRITE_ONCE(rsclp->len, rsclp->len + 1); /* ->len sampled locklessly. */ + if (lazy) + rsclp->len_lazy++; + smp_mb(); /* Ensure counts are updated before callback is enqueued. */ + rhp->next = NULL; + *rsclp->tails[RCU_NEXT_TAIL] = rhp; + rsclp->tails[RCU_NEXT_TAIL] = &rhp->next; +} + +/* + * Entrain the specified callback onto the specified rcu_segcblist at + * the end of the last non-empty segment. If the entire rcu_segcblist + * is empty, make no change, but return false. + * + * This is intended for use by rcu_barrier()-like primitives, -not- + * for normal grace-period use. IMPORTANT: The callback you enqueue + * will wait for all prior callbacks, NOT necessarily for a grace + * period. You have been warned. + */ +bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp, + struct rcu_head *rhp, bool lazy) +{ + int i; + + if (rcu_segcblist_n_cbs(rsclp) == 0) + return false; + WRITE_ONCE(rsclp->len, rsclp->len + 1); + if (lazy) + rsclp->len_lazy++; + smp_mb(); /* Ensure counts are updated before callback is entrained. */ + rhp->next = NULL; + for (i = RCU_NEXT_TAIL; i > RCU_DONE_TAIL; i--) + if (rsclp->tails[i] != rsclp->tails[i - 1]) + break; + *rsclp->tails[i] = rhp; + for (; i <= RCU_NEXT_TAIL; i++) + rsclp->tails[i] = &rhp->next; + return true; +} + +/* + * Extract only the counts from the specified rcu_segcblist structure, + * and place them in the specified rcu_cblist structure. This function + * supports both callback orphaning and invocation, hence the separation + * of counts and callbacks. (Callbacks ready for invocation must be + * orphaned and adopted separately from pending callbacks, but counts + * apply to all callbacks. Locking must be used to make sure that + * both orphaned-callbacks lists are consistent.) + */ +void rcu_segcblist_extract_count(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp) +{ + rclp->len_lazy += rsclp->len_lazy; + rclp->len += rsclp->len; + rsclp->len_lazy = 0; + WRITE_ONCE(rsclp->len, 0); /* ->len sampled locklessly. */ +} + +/* + * Extract only those callbacks ready to be invoked from the specified + * rcu_segcblist structure and place them in the specified rcu_cblist + * structure. + */ +void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp) +{ + int i; + + if (!rcu_segcblist_ready_cbs(rsclp)) + return; /* Nothing to do. */ + *rclp->tail = rsclp->head; + rsclp->head = *rsclp->tails[RCU_DONE_TAIL]; + *rsclp->tails[RCU_DONE_TAIL] = NULL; + rclp->tail = rsclp->tails[RCU_DONE_TAIL]; + for (i = RCU_CBLIST_NSEGS - 1; i >= RCU_DONE_TAIL; i--) + if (rsclp->tails[i] == rsclp->tails[RCU_DONE_TAIL]) + rsclp->tails[i] = &rsclp->head; +} + +/* + * Extract only those callbacks still pending (not yet ready to be + * invoked) from the specified rcu_segcblist structure and place them in + * the specified rcu_cblist structure. Note that this loses information + * about any callbacks that might have been partway done waiting for + * their grace period. Too bad! They will have to start over. + */ +void rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp) +{ + int i; + + if (!rcu_segcblist_pend_cbs(rsclp)) + return; /* Nothing to do. */ + *rclp->tail = *rsclp->tails[RCU_DONE_TAIL]; + rclp->tail = rsclp->tails[RCU_NEXT_TAIL]; + *rsclp->tails[RCU_DONE_TAIL] = NULL; + for (i = RCU_DONE_TAIL + 1; i < RCU_CBLIST_NSEGS; i++) + rsclp->tails[i] = rsclp->tails[RCU_DONE_TAIL]; +} + +/* + * Insert counts from the specified rcu_cblist structure in the + * specified rcu_segcblist structure. + */ +void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp) +{ + rsclp->len_lazy += rclp->len_lazy; + /* ->len sampled locklessly. */ + WRITE_ONCE(rsclp->len, rsclp->len + rclp->len); + rclp->len_lazy = 0; + rclp->len = 0; +} + +/* + * Move callbacks from the specified rcu_cblist to the beginning of the + * done-callbacks segment of the specified rcu_segcblist. + */ +void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp) +{ + int i; + + if (!rclp->head) + return; /* No callbacks to move. */ + *rclp->tail = rsclp->head; + rsclp->head = rclp->head; + for (i = RCU_DONE_TAIL; i < RCU_CBLIST_NSEGS; i++) + if (&rsclp->head == rsclp->tails[i]) + rsclp->tails[i] = rclp->tail; + else + break; + rclp->head = NULL; + rclp->tail = &rclp->head; +} + +/* + * Move callbacks from the specified rcu_cblist to the end of the + * new-callbacks segment of the specified rcu_segcblist. + */ +void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp) +{ + if (!rclp->head) + return; /* Nothing to do. */ + *rsclp->tails[RCU_NEXT_TAIL] = rclp->head; + rsclp->tails[RCU_NEXT_TAIL] = rclp->tail; + rclp->head = NULL; + rclp->tail = &rclp->head; +} + +/* + * Advance the callbacks in the specified rcu_segcblist structure based + * on the current value passed in for the grace-period counter. + */ +void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq) +{ + int i, j; + + WARN_ON_ONCE(!rcu_segcblist_is_enabled(rsclp)); + if (rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL)) + return; + + /* + * Find all callbacks whose ->gp_seq numbers indicate that they + * are ready to invoke, and put them into the RCU_DONE_TAIL segment. + */ + for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) { + if (ULONG_CMP_LT(seq, rsclp->gp_seq[i])) + break; + rsclp->tails[RCU_DONE_TAIL] = rsclp->tails[i]; + } + + /* If no callbacks moved, nothing more need be done. */ + if (i == RCU_WAIT_TAIL) + return; + + /* Clean up tail pointers that might have been misordered above. */ + for (j = RCU_WAIT_TAIL; j < i; j++) + rsclp->tails[j] = rsclp->tails[RCU_DONE_TAIL]; + + /* + * Callbacks moved, so clean up the misordered ->tails[] pointers + * that now point into the middle of the list of ready-to-invoke + * callbacks. The overall effect is to copy down the later pointers + * into the gap that was created by the now-ready segments. + */ + for (j = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++, j++) { + if (rsclp->tails[j] == rsclp->tails[RCU_NEXT_TAIL]) + break; /* No more callbacks. */ + rsclp->tails[j] = rsclp->tails[i]; + rsclp->gp_seq[j] = rsclp->gp_seq[i]; + } +} + +/* + * "Accelerate" callbacks based on more-accurate grace-period information. + * The reason for this is that RCU does not synchronize the beginnings and + * ends of grace periods, and that callbacks are posted locally. This in + * turn means that the callbacks must be labelled conservatively early + * on, as getting exact information would degrade both performance and + * scalability. When more accurate grace-period information becomes + * available, previously posted callbacks can be "accelerated", marking + * them to complete at the end of the earlier grace period. + * + * This function operates on an rcu_segcblist structure, and also the + * grace-period sequence number seq at which new callbacks would become + * ready to invoke. Returns true if there are callbacks that won't be + * ready to invoke until seq, false otherwise. + */ +bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq) +{ + int i; + + WARN_ON_ONCE(!rcu_segcblist_is_enabled(rsclp)); + if (rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL)) + return false; + + /* + * Find the segment preceding the oldest segment of callbacks + * whose ->gp_seq[] completion is at or after that passed in via + * "seq", skipping any empty segments. This oldest segment, along + * with any later segments, can be merged in with any newly arrived + * callbacks in the RCU_NEXT_TAIL segment, and assigned "seq" + * as their ->gp_seq[] grace-period completion sequence number. + */ + for (i = RCU_NEXT_READY_TAIL; i > RCU_DONE_TAIL; i--) + if (rsclp->tails[i] != rsclp->tails[i - 1] && + ULONG_CMP_LT(rsclp->gp_seq[i], seq)) + break; + + /* + * If all the segments contain callbacks that correspond to + * earlier grace-period sequence numbers than "seq", leave. + * Assuming that the rcu_segcblist structure has enough + * segments in its arrays, this can only happen if some of + * the non-done segments contain callbacks that really are + * ready to invoke. This situation will get straightened + * out by the next call to rcu_segcblist_advance(). + * + * Also advance to the oldest segment of callbacks whose + * ->gp_seq[] completion is at or after that passed in via "seq", + * skipping any empty segments. + */ + if (++i >= RCU_NEXT_TAIL) + return false; + + /* + * Merge all later callbacks, including newly arrived callbacks, + * into the segment located by the for-loop above. Assign "seq" + * as the ->gp_seq[] value in order to correctly handle the case + * where there were no pending callbacks in the rcu_segcblist + * structure other than in the RCU_NEXT_TAIL segment. + */ + for (; i < RCU_NEXT_TAIL; i++) { + rsclp->tails[i] = rsclp->tails[RCU_NEXT_TAIL]; + rsclp->gp_seq[i] = seq; + } + return true; +} + +/* + * Scan the specified rcu_segcblist structure for callbacks that need + * a grace period later than the one specified by "seq". We don't look + * at the RCU_DONE_TAIL or RCU_NEXT_TAIL segments because they don't + * have a grace-period sequence number. + */ +bool rcu_segcblist_future_gp_needed(struct rcu_segcblist *rsclp, + unsigned long seq) +{ + int i; + + for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) + if (rsclp->tails[i - 1] != rsclp->tails[i] && + ULONG_CMP_LT(seq, rsclp->gp_seq[i])) + return true; + return false; +} diff --git a/kernel/rcu/rcu_segcblist.h b/kernel/rcu/rcu_segcblist.h new file mode 100644 index 000000000000..6e36e36478cd --- /dev/null +++ b/kernel/rcu/rcu_segcblist.h @@ -0,0 +1,164 @@ +/* + * RCU segmented callback lists, internal-to-rcu header file + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright IBM Corporation, 2017 + * + * Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> + */ + +#include <linux/rcu_segcblist.h> + +/* + * Account for the fact that a previously dequeued callback turned out + * to be marked as lazy. + */ +static inline void rcu_cblist_dequeued_lazy(struct rcu_cblist *rclp) +{ + rclp->len_lazy--; +} + +/* + * Interim function to return rcu_cblist head pointer. Longer term, the + * rcu_cblist will be used more pervasively, removing the need for this + * function. + */ +static inline struct rcu_head *rcu_cblist_head(struct rcu_cblist *rclp) +{ + return rclp->head; +} + +/* + * Interim function to return rcu_cblist head pointer. Longer term, the + * rcu_cblist will be used more pervasively, removing the need for this + * function. + */ +static inline struct rcu_head **rcu_cblist_tail(struct rcu_cblist *rclp) +{ + WARN_ON_ONCE(!rclp->head); + return rclp->tail; +} + +void rcu_cblist_init(struct rcu_cblist *rclp); +long rcu_cblist_count_cbs(struct rcu_cblist *rclp, long lim); +struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp); + +/* + * Is the specified rcu_segcblist structure empty? + * + * But careful! The fact that the ->head field is NULL does not + * necessarily imply that there are no callbacks associated with + * this structure. When callbacks are being invoked, they are + * removed as a group. If callback invocation must be preempted, + * the remaining callbacks will be added back to the list. Either + * way, the counts are updated later. + * + * So it is often the case that rcu_segcblist_n_cbs() should be used + * instead. + */ +static inline bool rcu_segcblist_empty(struct rcu_segcblist *rsclp) +{ + return !rsclp->head; +} + +/* Return number of callbacks in segmented callback list. */ +static inline long rcu_segcblist_n_cbs(struct rcu_segcblist *rsclp) +{ + return READ_ONCE(rsclp->len); +} + +/* Return number of lazy callbacks in segmented callback list. */ +static inline long rcu_segcblist_n_lazy_cbs(struct rcu_segcblist *rsclp) +{ + return rsclp->len_lazy; +} + +/* Return number of lazy callbacks in segmented callback list. */ +static inline long rcu_segcblist_n_nonlazy_cbs(struct rcu_segcblist *rsclp) +{ + return rsclp->len - rsclp->len_lazy; +} + +/* + * Is the specified rcu_segcblist enabled, for example, not corresponding + * to an offline or callback-offloaded CPU? + */ +static inline bool rcu_segcblist_is_enabled(struct rcu_segcblist *rsclp) +{ + return !!rsclp->tails[RCU_NEXT_TAIL]; +} + +/* + * Are all segments following the specified segment of the specified + * rcu_segcblist structure empty of callbacks? (The specified + * segment might well contain callbacks.) + */ +static inline bool rcu_segcblist_restempty(struct rcu_segcblist *rsclp, int seg) +{ + return !*rsclp->tails[seg]; +} + +/* + * Interim function to return rcu_segcblist head pointer. Longer term, the + * rcu_segcblist will be used more pervasively, removing the need for this + * function. + */ +static inline struct rcu_head *rcu_segcblist_head(struct rcu_segcblist *rsclp) +{ + return rsclp->head; +} + +/* + * Interim function to return rcu_segcblist head pointer. Longer term, the + * rcu_segcblist will be used more pervasively, removing the need for this + * function. + */ +static inline struct rcu_head **rcu_segcblist_tail(struct rcu_segcblist *rsclp) +{ + WARN_ON_ONCE(rcu_segcblist_empty(rsclp)); + return rsclp->tails[RCU_NEXT_TAIL]; +} + +void rcu_segcblist_init(struct rcu_segcblist *rsclp); +void rcu_segcblist_disable(struct rcu_segcblist *rsclp); +bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg); +bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp); +bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp); +struct rcu_head *rcu_segcblist_dequeue(struct rcu_segcblist *rsclp); +void rcu_segcblist_dequeued_lazy(struct rcu_segcblist *rsclp); +struct rcu_head *rcu_segcblist_first_cb(struct rcu_segcblist *rsclp); +struct rcu_head *rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp); +bool rcu_segcblist_new_cbs(struct rcu_segcblist *rsclp); +void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp, + struct rcu_head *rhp, bool lazy); +bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp, + struct rcu_head *rhp, bool lazy); +void rcu_segcblist_extract_count(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp); +void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp); +void rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp); +void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp); +void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp); +void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp, + struct rcu_cblist *rclp); +void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq); +bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq); +bool rcu_segcblist_future_gp_needed(struct rcu_segcblist *rsclp, + unsigned long seq); diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index cccc417a8135..ae6e574d4cf5 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -559,19 +559,34 @@ static void srcu_torture_barrier(void) static void srcu_torture_stats(void) { - int cpu; - int idx = srcu_ctlp->completed & 0x1; + int __maybe_unused cpu; + int idx; - pr_alert("%s%s per-CPU(idx=%d):", +#if defined(CONFIG_TREE_SRCU) || defined(CONFIG_CLASSIC_SRCU) +#ifdef CONFIG_TREE_SRCU + idx = srcu_ctlp->srcu_idx & 0x1; +#else /* #ifdef CONFIG_TREE_SRCU */ + idx = srcu_ctlp->completed & 0x1; +#endif /* #else #ifdef CONFIG_TREE_SRCU */ + pr_alert("%s%s Tree SRCU per-CPU(idx=%d):", torture_type, TORTURE_FLAG, idx); for_each_possible_cpu(cpu) { unsigned long l0, l1; unsigned long u0, u1; long c0, c1; - struct srcu_array *counts = per_cpu_ptr(srcu_ctlp->per_cpu_ref, cpu); +#ifdef CONFIG_TREE_SRCU + struct srcu_data *counts; + counts = per_cpu_ptr(srcu_ctlp->sda, cpu); + u0 = counts->srcu_unlock_count[!idx]; + u1 = counts->srcu_unlock_count[idx]; +#else /* #ifdef CONFIG_TREE_SRCU */ + struct srcu_array *counts; + + counts = per_cpu_ptr(srcu_ctlp->per_cpu_ref, cpu); u0 = counts->unlock_count[!idx]; u1 = counts->unlock_count[idx]; +#endif /* #else #ifdef CONFIG_TREE_SRCU */ /* * Make sure that a lock is always counted if the corresponding @@ -579,14 +594,26 @@ static void srcu_torture_stats(void) */ smp_rmb(); +#ifdef CONFIG_TREE_SRCU + l0 = counts->srcu_lock_count[!idx]; + l1 = counts->srcu_lock_count[idx]; +#else /* #ifdef CONFIG_TREE_SRCU */ l0 = counts->lock_count[!idx]; l1 = counts->lock_count[idx]; +#endif /* #else #ifdef CONFIG_TREE_SRCU */ c0 = l0 - u0; c1 = l1 - u1; pr_cont(" %d(%ld,%ld)", cpu, c0, c1); } pr_cont("\n"); +#elif defined(CONFIG_TINY_SRCU) + idx = READ_ONCE(srcu_ctlp->srcu_idx) & 0x1; + pr_alert("%s%s Tiny SRCU per-CPU(idx=%d): (%d,%d)\n", + torture_type, TORTURE_FLAG, idx, + READ_ONCE(srcu_ctlp->srcu_lock_nesting[!idx]), + READ_ONCE(srcu_ctlp->srcu_lock_nesting[idx])); +#endif } static void srcu_torture_synchronize_expedited(void) @@ -1333,12 +1360,14 @@ rcu_torture_stats_print(void) cur_ops->stats(); if (rtcv_snap == rcu_torture_current_version && rcu_torture_current != NULL) { - int __maybe_unused flags; - unsigned long __maybe_unused gpnum; - unsigned long __maybe_unused completed; + int __maybe_unused flags = 0; + unsigned long __maybe_unused gpnum = 0; + unsigned long __maybe_unused completed = 0; rcutorture_get_gp_data(cur_ops->ttype, &flags, &gpnum, &completed); + srcutorture_get_gp_data(cur_ops->ttype, srcu_ctlp, + &flags, &gpnum, &completed); wtp = READ_ONCE(writer_task); pr_alert("??? Writer stall state %s(%d) g%lu c%lu f%#x ->state %#lx\n", rcu_torture_writer_state_getname(), diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index ef3bcfb15b39..584d8a983883 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -22,7 +22,7 @@ * Lai Jiangshan <laijs@cn.fujitsu.com> * * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt + * Documentation/RCU/ *.txt * */ @@ -243,8 +243,14 @@ static bool srcu_readers_active(struct srcu_struct *sp) * cleanup_srcu_struct - deconstruct a sleep-RCU structure * @sp: structure to clean up. * - * Must invoke this after you are finished using a given srcu_struct that - * was initialized via init_srcu_struct(), else you leak memory. + * Must invoke this only after you are finished using a given srcu_struct + * that was initialized via init_srcu_struct(). This code does some + * probabalistic checking, spotting late uses of srcu_read_lock(), + * synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu(). + * If any such late uses are detected, the per-CPU memory associated with + * the srcu_struct is simply leaked and WARN_ON() is invoked. If the + * caller frees the srcu_struct itself, a use-after-free crash will likely + * ensue, but at least there will be a warning printed. */ void cleanup_srcu_struct(struct srcu_struct *sp) { diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c new file mode 100644 index 000000000000..36e1f82faed1 --- /dev/null +++ b/kernel/rcu/srcutiny.c @@ -0,0 +1,216 @@ +/* + * Sleepable Read-Copy Update mechanism for mutual exclusion, + * tiny version for non-preemptible single-CPU use. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (C) IBM Corporation, 2017 + * + * Author: Paul McKenney <paulmck@us.ibm.com> + */ + +#include <linux/export.h> +#include <linux/mutex.h> +#include <linux/preempt.h> +#include <linux/rcupdate_wait.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/srcu.h> + +#include <linux/rcu_node_tree.h> +#include "rcu_segcblist.h" +#include "rcu.h" + +static int init_srcu_struct_fields(struct srcu_struct *sp) +{ + sp->srcu_lock_nesting[0] = 0; + sp->srcu_lock_nesting[1] = 0; + init_swait_queue_head(&sp->srcu_wq); + sp->srcu_gp_seq = 0; + rcu_segcblist_init(&sp->srcu_cblist); + sp->srcu_gp_running = false; + sp->srcu_gp_waiting = false; + sp->srcu_idx = 0; + INIT_WORK(&sp->srcu_work, srcu_drive_gp); + return 0; +} + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + +int __init_srcu_struct(struct srcu_struct *sp, const char *name, + struct lock_class_key *key) +{ + /* Don't re-initialize a lock while it is held. */ + debug_check_no_locks_freed((void *)sp, sizeof(*sp)); + lockdep_init_map(&sp->dep_map, name, key, 0); + return init_srcu_struct_fields(sp); +} +EXPORT_SYMBOL_GPL(__init_srcu_struct); + +#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ + +/* + * init_srcu_struct - initialize a sleep-RCU structure + * @sp: structure to initialize. + * + * Must invoke this on a given srcu_struct before passing that srcu_struct + * to any other function. Each srcu_struct represents a separate domain + * of SRCU protection. + */ +int init_srcu_struct(struct srcu_struct *sp) +{ + return init_srcu_struct_fields(sp); +} +EXPORT_SYMBOL_GPL(init_srcu_struct); + +#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ + +/* + * cleanup_srcu_struct - deconstruct a sleep-RCU structure + * @sp: structure to clean up. + * + * Must invoke this after you are finished using a given srcu_struct that + * was initialized via init_srcu_struct(), else you leak memory. + */ +void cleanup_srcu_struct(struct srcu_struct *sp) +{ + WARN_ON(sp->srcu_lock_nesting[0] || sp->srcu_lock_nesting[1]); + flush_work(&sp->srcu_work); + WARN_ON(rcu_seq_state(sp->srcu_gp_seq)); + WARN_ON(sp->srcu_gp_running); + WARN_ON(sp->srcu_gp_waiting); + WARN_ON(!rcu_segcblist_empty(&sp->srcu_cblist)); +} +EXPORT_SYMBOL_GPL(cleanup_srcu_struct); + +/* + * Counts the new reader in the appropriate per-CPU element of the + * srcu_struct. Must be called from process context. + * Returns an index that must be passed to the matching srcu_read_unlock(). + */ +int __srcu_read_lock(struct srcu_struct *sp) +{ + int idx; + + idx = READ_ONCE(sp->srcu_idx); + WRITE_ONCE(sp->srcu_lock_nesting[idx], sp->srcu_lock_nesting[idx] + 1); + return idx; +} +EXPORT_SYMBOL_GPL(__srcu_read_lock); + +/* + * Removes the count for the old reader from the appropriate element of + * the srcu_struct. Must be called from process context. + */ +void __srcu_read_unlock(struct srcu_struct *sp, int idx) +{ + int newval = sp->srcu_lock_nesting[idx] - 1; + + WRITE_ONCE(sp->srcu_lock_nesting[idx], newval); + if (!newval && READ_ONCE(sp->srcu_gp_waiting)) + swake_up(&sp->srcu_wq); +} +EXPORT_SYMBOL_GPL(__srcu_read_unlock); + +/* + * Workqueue handler to drive one grace period and invoke any callbacks + * that become ready as a result. Single-CPU and !PREEMPT operation + * means that we get away with murder on synchronization. ;-) + */ +void srcu_drive_gp(struct work_struct *wp) +{ + int idx; + struct rcu_cblist ready_cbs; + struct srcu_struct *sp; + struct rcu_head *rhp; + + sp = container_of(wp, struct srcu_struct, srcu_work); + if (sp->srcu_gp_running || rcu_segcblist_empty(&sp->srcu_cblist)) + return; /* Already running or nothing to do. */ + + /* Tag recently arrived callbacks and wait for readers. */ + WRITE_ONCE(sp->srcu_gp_running, true); + rcu_segcblist_accelerate(&sp->srcu_cblist, + rcu_seq_snap(&sp->srcu_gp_seq)); + rcu_seq_start(&sp->srcu_gp_seq); + idx = sp->srcu_idx; + WRITE_ONCE(sp->srcu_idx, !sp->srcu_idx); + WRITE_ONCE(sp->srcu_gp_waiting, true); /* srcu_read_unlock() wakes! */ + swait_event(sp->srcu_wq, !READ_ONCE(sp->srcu_lock_nesting[idx])); + WRITE_ONCE(sp->srcu_gp_waiting, false); /* srcu_read_unlock() cheap. */ + rcu_seq_end(&sp->srcu_gp_seq); + + /* Update callback list based on GP, and invoke ready callbacks. */ + rcu_segcblist_advance(&sp->srcu_cblist, + rcu_seq_current(&sp->srcu_gp_seq)); + if (rcu_segcblist_ready_cbs(&sp->srcu_cblist)) { + rcu_cblist_init(&ready_cbs); + local_irq_disable(); + rcu_segcblist_extract_done_cbs(&sp->srcu_cblist, &ready_cbs); + local_irq_enable(); + rhp = rcu_cblist_dequeue(&ready_cbs); + for (; rhp != NULL; rhp = rcu_cblist_dequeue(&ready_cbs)) { + local_bh_disable(); + rhp->func(rhp); + local_bh_enable(); + } + local_irq_disable(); + rcu_segcblist_insert_count(&sp->srcu_cblist, &ready_cbs); + local_irq_enable(); + } + WRITE_ONCE(sp->srcu_gp_running, false); + + /* + * If more callbacks, reschedule ourselves. This can race with + * a call_srcu() at interrupt level, but the ->srcu_gp_running + * checks will straighten that out. + */ + if (!rcu_segcblist_empty(&sp->srcu_cblist)) + schedule_work(&sp->srcu_work); +} +EXPORT_SYMBOL_GPL(srcu_drive_gp); + +/* + * Enqueue an SRCU callback on the specified srcu_struct structure, + * initiating grace-period processing if it is not already running. + */ +void call_srcu(struct srcu_struct *sp, struct rcu_head *head, + rcu_callback_t func) +{ + unsigned long flags; + + head->func = func; + local_irq_save(flags); + rcu_segcblist_enqueue(&sp->srcu_cblist, head, false); + local_irq_restore(flags); + if (!READ_ONCE(sp->srcu_gp_running)) + schedule_work(&sp->srcu_work); +} +EXPORT_SYMBOL_GPL(call_srcu); + +/* + * synchronize_srcu - wait for prior SRCU read-side critical-section completion + */ +void synchronize_srcu(struct srcu_struct *sp) +{ + struct rcu_synchronize rs; + + init_rcu_head_on_stack(&rs.head); + init_completion(&rs.completion); + call_srcu(sp, &rs.head, wakeme_after_rcu); + wait_for_completion(&rs.completion); + destroy_rcu_head_on_stack(&rs.head); +} +EXPORT_SYMBOL_GPL(synchronize_srcu); diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c new file mode 100644 index 000000000000..3ae8474557df --- /dev/null +++ b/kernel/rcu/srcutree.c @@ -0,0 +1,1155 @@ +/* + * Sleepable Read-Copy Update mechanism for mutual exclusion. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (C) IBM Corporation, 2006 + * Copyright (C) Fujitsu, 2012 + * + * Author: Paul McKenney <paulmck@us.ibm.com> + * Lai Jiangshan <laijs@cn.fujitsu.com> + * + * For detailed explanation of Read-Copy Update mechanism see - + * Documentation/RCU/ *.txt + * + */ + +#include <linux/export.h> +#include <linux/mutex.h> +#include <linux/percpu.h> +#include <linux/preempt.h> +#include <linux/rcupdate_wait.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/srcu.h> + +#include "rcu.h" +#include "rcu_segcblist.h" + +ulong exp_holdoff = 25 * 1000; /* Holdoff (ns) for auto-expediting. */ +module_param(exp_holdoff, ulong, 0444); + +static void srcu_invoke_callbacks(struct work_struct *work); +static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay); + +/* + * Initialize SRCU combining tree. Note that statically allocated + * srcu_struct structures might already have srcu_read_lock() and + * srcu_read_unlock() running against them. So if the is_static parameter + * is set, don't initialize ->srcu_lock_count[] and ->srcu_unlock_count[]. + */ +static void init_srcu_struct_nodes(struct srcu_struct *sp, bool is_static) +{ + int cpu; + int i; + int level = 0; + int levelspread[RCU_NUM_LVLS]; + struct srcu_data *sdp; + struct srcu_node *snp; + struct srcu_node *snp_first; + + /* Work out the overall tree geometry. */ + sp->level[0] = &sp->node[0]; + for (i = 1; i < rcu_num_lvls; i++) + sp->level[i] = sp->level[i - 1] + num_rcu_lvl[i - 1]; + rcu_init_levelspread(levelspread, num_rcu_lvl); + + /* Each pass through this loop initializes one srcu_node structure. */ + rcu_for_each_node_breadth_first(sp, snp) { + spin_lock_init(&snp->lock); + WARN_ON_ONCE(ARRAY_SIZE(snp->srcu_have_cbs) != + ARRAY_SIZE(snp->srcu_data_have_cbs)); + for (i = 0; i < ARRAY_SIZE(snp->srcu_have_cbs); i++) { + snp->srcu_have_cbs[i] = 0; + snp->srcu_data_have_cbs[i] = 0; + } + snp->srcu_gp_seq_needed_exp = 0; + snp->grplo = -1; + snp->grphi = -1; + if (snp == &sp->node[0]) { + /* Root node, special case. */ + snp->srcu_parent = NULL; + continue; + } + + /* Non-root node. */ + if (snp == sp->level[level + 1]) + level++; + snp->srcu_parent = sp->level[level - 1] + + (snp - sp->level[level]) / + levelspread[level - 1]; + } + + /* + * Initialize the per-CPU srcu_data array, which feeds into the + * leaves of the srcu_node tree. + */ + WARN_ON_ONCE(ARRAY_SIZE(sdp->srcu_lock_count) != + ARRAY_SIZE(sdp->srcu_unlock_count)); + level = rcu_num_lvls - 1; + snp_first = sp->level[level]; + for_each_possible_cpu(cpu) { + sdp = per_cpu_ptr(sp->sda, cpu); + spin_lock_init(&sdp->lock); + rcu_segcblist_init(&sdp->srcu_cblist); + sdp->srcu_cblist_invoking = false; + sdp->srcu_gp_seq_needed = sp->srcu_gp_seq; + sdp->srcu_gp_seq_needed_exp = sp->srcu_gp_seq; + sdp->mynode = &snp_first[cpu / levelspread[level]]; + for (snp = sdp->mynode; snp != NULL; snp = snp->srcu_parent) { + if (snp->grplo < 0) + snp->grplo = cpu; + snp->grphi = cpu; + } + sdp->cpu = cpu; + INIT_DELAYED_WORK(&sdp->work, srcu_invoke_callbacks); + sdp->sp = sp; + sdp->grpmask = 1 << (cpu - sdp->mynode->grplo); + if (is_static) + continue; + + /* Dynamically allocated, better be no srcu_read_locks()! */ + for (i = 0; i < ARRAY_SIZE(sdp->srcu_lock_count); i++) { + sdp->srcu_lock_count[i] = 0; + sdp->srcu_unlock_count[i] = 0; + } + } +} + +/* + * Initialize non-compile-time initialized fields, including the + * associated srcu_node and srcu_data structures. The is_static + * parameter is passed through to init_srcu_struct_nodes(), and + * also tells us that ->sda has already been wired up to srcu_data. + */ +static int init_srcu_struct_fields(struct srcu_struct *sp, bool is_static) +{ + mutex_init(&sp->srcu_cb_mutex); + mutex_init(&sp->srcu_gp_mutex); + sp->srcu_idx = 0; + sp->srcu_gp_seq = 0; + sp->srcu_barrier_seq = 0; + mutex_init(&sp->srcu_barrier_mutex); + atomic_set(&sp->srcu_barrier_cpu_cnt, 0); + INIT_DELAYED_WORK(&sp->work, process_srcu); + if (!is_static) + sp->sda = alloc_percpu(struct srcu_data); + init_srcu_struct_nodes(sp, is_static); + sp->srcu_gp_seq_needed_exp = 0; + sp->srcu_last_gp_end = ktime_get_mono_fast_ns(); + smp_store_release(&sp->srcu_gp_seq_needed, 0); /* Init done. */ + return sp->sda ? 0 : -ENOMEM; +} + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + +int __init_srcu_struct(struct srcu_struct *sp, const char *name, + struct lock_class_key *key) +{ + /* Don't re-initialize a lock while it is held. */ + debug_check_no_locks_freed((void *)sp, sizeof(*sp)); + lockdep_init_map(&sp->dep_map, name, key, 0); + spin_lock_init(&sp->gp_lock); + return init_srcu_struct_fields(sp, false); +} +EXPORT_SYMBOL_GPL(__init_srcu_struct); + +#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ + +/** + * init_srcu_struct - initialize a sleep-RCU structure + * @sp: structure to initialize. + * + * Must invoke this on a given srcu_struct before passing that srcu_struct + * to any other function. Each srcu_struct represents a separate domain + * of SRCU protection. + */ +int init_srcu_struct(struct srcu_struct *sp) +{ + spin_lock_init(&sp->gp_lock); + return init_srcu_struct_fields(sp, false); +} +EXPORT_SYMBOL_GPL(init_srcu_struct); + +#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ + +/* + * First-use initialization of statically allocated srcu_struct + * structure. Wiring up the combining tree is more than can be + * done with compile-time initialization, so this check is added + * to each update-side SRCU primitive. Use ->gp_lock, which -is- + * compile-time initialized, to resolve races involving multiple + * CPUs trying to garner first-use privileges. + */ +static void check_init_srcu_struct(struct srcu_struct *sp) +{ + unsigned long flags; + + WARN_ON_ONCE(rcu_scheduler_active == RCU_SCHEDULER_INIT); + /* The smp_load_acquire() pairs with the smp_store_release(). */ + if (!rcu_seq_state(smp_load_acquire(&sp->srcu_gp_seq_needed))) /*^^^*/ + return; /* Already initialized. */ + spin_lock_irqsave(&sp->gp_lock, flags); + if (!rcu_seq_state(sp->srcu_gp_seq_needed)) { + spin_unlock_irqrestore(&sp->gp_lock, flags); + return; + } + init_srcu_struct_fields(sp, true); + spin_unlock_irqrestore(&sp->gp_lock, flags); +} + +/* + * Returns approximate total of the readers' ->srcu_lock_count[] values + * for the rank of per-CPU counters specified by idx. + */ +static unsigned long srcu_readers_lock_idx(struct srcu_struct *sp, int idx) +{ + int cpu; + unsigned long sum = 0; + + for_each_possible_cpu(cpu) { + struct srcu_data *cpuc = per_cpu_ptr(sp->sda, cpu); + + sum += READ_ONCE(cpuc->srcu_lock_count[idx]); + } + return sum; +} + +/* + * Returns approximate total of the readers' ->srcu_unlock_count[] values + * for the rank of per-CPU counters specified by idx. + */ +static unsigned long srcu_readers_unlock_idx(struct srcu_struct *sp, int idx) +{ + int cpu; + unsigned long sum = 0; + + for_each_possible_cpu(cpu) { + struct srcu_data *cpuc = per_cpu_ptr(sp->sda, cpu); + + sum += READ_ONCE(cpuc->srcu_unlock_count[idx]); + } + return sum; +} + +/* + * Return true if the number of pre-existing readers is determined to + * be zero. + */ +static bool srcu_readers_active_idx_check(struct srcu_struct *sp, int idx) +{ + unsigned long unlocks; + + unlocks = srcu_readers_unlock_idx(sp, idx); + + /* + * Make sure that a lock is always counted if the corresponding + * unlock is counted. Needs to be a smp_mb() as the read side may + * contain a read from a variable that is written to before the + * synchronize_srcu() in the write side. In this case smp_mb()s + * A and B act like the store buffering pattern. + * + * This smp_mb() also pairs with smp_mb() C to prevent accesses + * after the synchronize_srcu() from being executed before the + * grace period ends. + */ + smp_mb(); /* A */ + + /* + * If the locks are the same as the unlocks, then there must have + * been no readers on this index at some time in between. This does + * not mean that there are no more readers, as one could have read + * the current index but not have incremented the lock counter yet. + * + * Possible bug: There is no guarantee that there haven't been + * ULONG_MAX increments of ->srcu_lock_count[] since the unlocks were + * counted, meaning that this could return true even if there are + * still active readers. Since there are no memory barriers around + * srcu_flip(), the CPU is not required to increment ->srcu_idx + * before running srcu_readers_unlock_idx(), which means that there + * could be an arbitrarily large number of critical sections that + * execute after srcu_readers_unlock_idx() but use the old value + * of ->srcu_idx. + */ + return srcu_readers_lock_idx(sp, idx) == unlocks; +} + +/** + * srcu_readers_active - returns true if there are readers. and false + * otherwise + * @sp: which srcu_struct to count active readers (holding srcu_read_lock). + * + * Note that this is not an atomic primitive, and can therefore suffer + * severe errors when invoked on an active srcu_struct. That said, it + * can be useful as an error check at cleanup time. + */ +static bool srcu_readers_active(struct srcu_struct *sp) +{ + int cpu; + unsigned long sum = 0; + + for_each_possible_cpu(cpu) { + struct srcu_data *cpuc = per_cpu_ptr(sp->sda, cpu); + + sum += READ_ONCE(cpuc->srcu_lock_count[0]); + sum += READ_ONCE(cpuc->srcu_lock_count[1]); + sum -= READ_ONCE(cpuc->srcu_unlock_count[0]); + sum -= READ_ONCE(cpuc->srcu_unlock_count[1]); + } + return sum; +} + +#define SRCU_INTERVAL 1 + +/* + * Return grace-period delay, zero if there are expedited grace + * periods pending, SRCU_INTERVAL otherwise. + */ +static unsigned long srcu_get_delay(struct srcu_struct *sp) +{ + if (ULONG_CMP_LT(READ_ONCE(sp->srcu_gp_seq), + READ_ONCE(sp->srcu_gp_seq_needed_exp))) + return 0; + return SRCU_INTERVAL; +} + +/** + * cleanup_srcu_struct - deconstruct a sleep-RCU structure + * @sp: structure to clean up. + * + * Must invoke this after you are finished using a given srcu_struct that + * was initialized via init_srcu_struct(), else you leak memory. + */ +void cleanup_srcu_struct(struct srcu_struct *sp) +{ + int cpu; + + if (WARN_ON(!srcu_get_delay(sp))) + return; /* Leakage unless caller handles error. */ + if (WARN_ON(srcu_readers_active(sp))) + return; /* Leakage unless caller handles error. */ + flush_delayed_work(&sp->work); + for_each_possible_cpu(cpu) + flush_delayed_work(&per_cpu_ptr(sp->sda, cpu)->work); + if (WARN_ON(rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)) != SRCU_STATE_IDLE) || + WARN_ON(srcu_readers_active(sp))) { + pr_info("cleanup_srcu_struct: Active srcu_struct %p state: %d\n", sp, rcu_seq_state(READ_ONCE(sp->srcu_gp_seq))); + return; /* Caller forgot to stop doing call_srcu()? */ + } + free_percpu(sp->sda); + sp->sda = NULL; +} +EXPORT_SYMBOL_GPL(cleanup_srcu_struct); + +/* + * Counts the new reader in the appropriate per-CPU element of the + * srcu_struct. Must be called from process context. + * Returns an index that must be passed to the matching srcu_read_unlock(). + */ +int __srcu_read_lock(struct srcu_struct *sp) +{ + int idx; + + idx = READ_ONCE(sp->srcu_idx) & 0x1; + __this_cpu_inc(sp->sda->srcu_lock_count[idx]); + smp_mb(); /* B */ /* Avoid leaking the critical section. */ + return idx; +} +EXPORT_SYMBOL_GPL(__srcu_read_lock); + +/* + * Removes the count for the old reader from the appropriate per-CPU + * element of the srcu_struct. Note that this may well be a different + * CPU than that which was incremented by the corresponding srcu_read_lock(). + * Must be called from process context. + */ +void __srcu_read_unlock(struct srcu_struct *sp, int idx) +{ + smp_mb(); /* C */ /* Avoid leaking the critical section. */ + this_cpu_inc(sp->sda->srcu_unlock_count[idx]); +} +EXPORT_SYMBOL_GPL(__srcu_read_unlock); + +/* + * We use an adaptive strategy for synchronize_srcu() and especially for + * synchronize_srcu_expedited(). We spin for a fixed time period + * (defined below) to allow SRCU readers to exit their read-side critical + * sections. If there are still some readers after a few microseconds, + * we repeatedly block for 1-millisecond time periods. + */ +#define SRCU_RETRY_CHECK_DELAY 5 + +/* + * Start an SRCU grace period. + */ +static void srcu_gp_start(struct srcu_struct *sp) +{ + struct srcu_data *sdp = this_cpu_ptr(sp->sda); + int state; + + RCU_LOCKDEP_WARN(!lockdep_is_held(&sp->gp_lock), + "Invoked srcu_gp_start() without ->gp_lock!"); + WARN_ON_ONCE(ULONG_CMP_GE(sp->srcu_gp_seq, sp->srcu_gp_seq_needed)); + rcu_segcblist_advance(&sdp->srcu_cblist, + rcu_seq_current(&sp->srcu_gp_seq)); + (void)rcu_segcblist_accelerate(&sdp->srcu_cblist, + rcu_seq_snap(&sp->srcu_gp_seq)); + smp_mb(); /* Order prior store to ->srcu_gp_seq_needed vs. GP start. */ + rcu_seq_start(&sp->srcu_gp_seq); + state = rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)); + WARN_ON_ONCE(state != SRCU_STATE_SCAN1); +} + +/* + * Track online CPUs to guide callback workqueue placement. + */ +DEFINE_PER_CPU(bool, srcu_online); + +void srcu_online_cpu(unsigned int cpu) +{ + WRITE_ONCE(per_cpu(srcu_online, cpu), true); +} + +void srcu_offline_cpu(unsigned int cpu) +{ + WRITE_ONCE(per_cpu(srcu_online, cpu), false); +} + +/* + * Place the workqueue handler on the specified CPU if online, otherwise + * just run it whereever. This is useful for placing workqueue handlers + * that are to invoke the specified CPU's callbacks. + */ +static bool srcu_queue_delayed_work_on(int cpu, struct workqueue_struct *wq, + struct delayed_work *dwork, + unsigned long delay) +{ + bool ret; + + preempt_disable(); + if (READ_ONCE(per_cpu(srcu_online, cpu))) + ret = queue_delayed_work_on(cpu, wq, dwork, delay); + else + ret = queue_delayed_work(wq, dwork, delay); + preempt_enable(); + return ret; +} + +/* + * Schedule callback invocation for the specified srcu_data structure, + * if possible, on the corresponding CPU. + */ +static void srcu_schedule_cbs_sdp(struct srcu_data *sdp, unsigned long delay) +{ + srcu_queue_delayed_work_on(sdp->cpu, system_power_efficient_wq, + &sdp->work, delay); +} + +/* + * Schedule callback invocation for all srcu_data structures associated + * with the specified srcu_node structure that have callbacks for the + * just-completed grace period, the one corresponding to idx. If possible, + * schedule this invocation on the corresponding CPUs. + */ +static void srcu_schedule_cbs_snp(struct srcu_struct *sp, struct srcu_node *snp, + unsigned long mask, unsigned long delay) +{ + int cpu; + + for (cpu = snp->grplo; cpu <= snp->grphi; cpu++) { + if (!(mask & (1 << (cpu - snp->grplo)))) + continue; + srcu_schedule_cbs_sdp(per_cpu_ptr(sp->sda, cpu), delay); + } +} + +/* + * Note the end of an SRCU grace period. Initiates callback invocation + * and starts a new grace period if needed. + * + * The ->srcu_cb_mutex acquisition does not protect any data, but + * instead prevents more than one grace period from starting while we + * are initiating callback invocation. This allows the ->srcu_have_cbs[] + * array to have a finite number of elements. + */ +static void srcu_gp_end(struct srcu_struct *sp) +{ + unsigned long cbdelay; + bool cbs; + unsigned long gpseq; + int idx; + int idxnext; + unsigned long mask; + struct srcu_node *snp; + + /* Prevent more than one additional grace period. */ + mutex_lock(&sp->srcu_cb_mutex); + + /* End the current grace period. */ + spin_lock_irq(&sp->gp_lock); + idx = rcu_seq_state(sp->srcu_gp_seq); + WARN_ON_ONCE(idx != SRCU_STATE_SCAN2); + cbdelay = srcu_get_delay(sp); + sp->srcu_last_gp_end = ktime_get_mono_fast_ns(); + rcu_seq_end(&sp->srcu_gp_seq); + gpseq = rcu_seq_current(&sp->srcu_gp_seq); + if (ULONG_CMP_LT(sp->srcu_gp_seq_needed_exp, gpseq)) + sp->srcu_gp_seq_needed_exp = gpseq; + spin_unlock_irq(&sp->gp_lock); + mutex_unlock(&sp->srcu_gp_mutex); + /* A new grace period can start at this point. But only one. */ + + /* Initiate callback invocation as needed. */ + idx = rcu_seq_ctr(gpseq) % ARRAY_SIZE(snp->srcu_have_cbs); + idxnext = (idx + 1) % ARRAY_SIZE(snp->srcu_have_cbs); + rcu_for_each_node_breadth_first(sp, snp) { + spin_lock_irq(&snp->lock); + cbs = false; + if (snp >= sp->level[rcu_num_lvls - 1]) + cbs = snp->srcu_have_cbs[idx] == gpseq; + snp->srcu_have_cbs[idx] = gpseq; + rcu_seq_set_state(&snp->srcu_have_cbs[idx], 1); + if (ULONG_CMP_LT(snp->srcu_gp_seq_needed_exp, gpseq)) + snp->srcu_gp_seq_needed_exp = gpseq; + mask = snp->srcu_data_have_cbs[idx]; + snp->srcu_data_have_cbs[idx] = 0; + spin_unlock_irq(&snp->lock); + if (cbs) { + smp_mb(); /* GP end before CB invocation. */ + srcu_schedule_cbs_snp(sp, snp, mask, cbdelay); + } + } + + /* Callback initiation done, allow grace periods after next. */ + mutex_unlock(&sp->srcu_cb_mutex); + + /* Start a new grace period if needed. */ + spin_lock_irq(&sp->gp_lock); + gpseq = rcu_seq_current(&sp->srcu_gp_seq); + if (!rcu_seq_state(gpseq) && + ULONG_CMP_LT(gpseq, sp->srcu_gp_seq_needed)) { + srcu_gp_start(sp); + spin_unlock_irq(&sp->gp_lock); + /* Throttle expedited grace periods: Should be rare! */ + srcu_reschedule(sp, rcu_seq_ctr(gpseq) & 0x3ff + ? 0 : SRCU_INTERVAL); + } else { + spin_unlock_irq(&sp->gp_lock); + } +} + +/* + * Funnel-locking scheme to scalably mediate many concurrent expedited + * grace-period requests. This function is invoked for the first known + * expedited request for a grace period that has already been requested, + * but without expediting. To start a completely new grace period, + * whether expedited or not, use srcu_funnel_gp_start() instead. + */ +static void srcu_funnel_exp_start(struct srcu_struct *sp, struct srcu_node *snp, + unsigned long s) +{ + unsigned long flags; + + for (; snp != NULL; snp = snp->srcu_parent) { + if (rcu_seq_done(&sp->srcu_gp_seq, s) || + ULONG_CMP_GE(READ_ONCE(snp->srcu_gp_seq_needed_exp), s)) + return; + spin_lock_irqsave(&snp->lock, flags); + if (ULONG_CMP_GE(snp->srcu_gp_seq_needed_exp, s)) { + spin_unlock_irqrestore(&snp->lock, flags); + return; + } + WRITE_ONCE(snp->srcu_gp_seq_needed_exp, s); + spin_unlock_irqrestore(&snp->lock, flags); + } + spin_lock_irqsave(&sp->gp_lock, flags); + if (!ULONG_CMP_LT(sp->srcu_gp_seq_needed_exp, s)) + sp->srcu_gp_seq_needed_exp = s; + spin_unlock_irqrestore(&sp->gp_lock, flags); +} + +/* + * Funnel-locking scheme to scalably mediate many concurrent grace-period + * requests. The winner has to do the work of actually starting grace + * period s. Losers must either ensure that their desired grace-period + * number is recorded on at least their leaf srcu_node structure, or they + * must take steps to invoke their own callbacks. + */ +static void srcu_funnel_gp_start(struct srcu_struct *sp, struct srcu_data *sdp, + unsigned long s, bool do_norm) +{ + unsigned long flags; + int idx = rcu_seq_ctr(s) % ARRAY_SIZE(sdp->mynode->srcu_have_cbs); + struct srcu_node *snp = sdp->mynode; + unsigned long snp_seq; + + /* Each pass through the loop does one level of the srcu_node tree. */ + for (; snp != NULL; snp = snp->srcu_parent) { + if (rcu_seq_done(&sp->srcu_gp_seq, s) && snp != sdp->mynode) + return; /* GP already done and CBs recorded. */ + spin_lock_irqsave(&snp->lock, flags); + if (ULONG_CMP_GE(snp->srcu_have_cbs[idx], s)) { + snp_seq = snp->srcu_have_cbs[idx]; + if (snp == sdp->mynode && snp_seq == s) + snp->srcu_data_have_cbs[idx] |= sdp->grpmask; + spin_unlock_irqrestore(&snp->lock, flags); + if (snp == sdp->mynode && snp_seq != s) { + smp_mb(); /* CBs after GP! */ + srcu_schedule_cbs_sdp(sdp, do_norm + ? SRCU_INTERVAL + : 0); + return; + } + if (!do_norm) + srcu_funnel_exp_start(sp, snp, s); + return; + } + snp->srcu_have_cbs[idx] = s; + if (snp == sdp->mynode) + snp->srcu_data_have_cbs[idx] |= sdp->grpmask; + if (!do_norm && ULONG_CMP_LT(snp->srcu_gp_seq_needed_exp, s)) + snp->srcu_gp_seq_needed_exp = s; + spin_unlock_irqrestore(&snp->lock, flags); + } + + /* Top of tree, must ensure the grace period will be started. */ + spin_lock_irqsave(&sp->gp_lock, flags); + if (ULONG_CMP_LT(sp->srcu_gp_seq_needed, s)) { + /* + * Record need for grace period s. Pair with load + * acquire setting up for initialization. + */ + smp_store_release(&sp->srcu_gp_seq_needed, s); /*^^^*/ + } + if (!do_norm && ULONG_CMP_LT(sp->srcu_gp_seq_needed_exp, s)) + sp->srcu_gp_seq_needed_exp = s; + + /* If grace period not already done and none in progress, start it. */ + if (!rcu_seq_done(&sp->srcu_gp_seq, s) && + rcu_seq_state(sp->srcu_gp_seq) == SRCU_STATE_IDLE) { + WARN_ON_ONCE(ULONG_CMP_GE(sp->srcu_gp_seq, sp->srcu_gp_seq_needed)); + srcu_gp_start(sp); + queue_delayed_work(system_power_efficient_wq, &sp->work, + srcu_get_delay(sp)); + } + spin_unlock_irqrestore(&sp->gp_lock, flags); +} + +/* + * Wait until all readers counted by array index idx complete, but + * loop an additional time if there is an expedited grace period pending. + * The caller must ensure that ->srcu_idx is not changed while checking. + */ +static bool try_check_zero(struct srcu_struct *sp, int idx, int trycount) +{ + for (;;) { + if (srcu_readers_active_idx_check(sp, idx)) + return true; + if (--trycount + !srcu_get_delay(sp) <= 0) + return false; + udelay(SRCU_RETRY_CHECK_DELAY); + } +} + +/* + * Increment the ->srcu_idx counter so that future SRCU readers will + * use the other rank of the ->srcu_(un)lock_count[] arrays. This allows + * us to wait for pre-existing readers in a starvation-free manner. + */ +static void srcu_flip(struct srcu_struct *sp) +{ + WRITE_ONCE(sp->srcu_idx, sp->srcu_idx + 1); + + /* + * Ensure that if the updater misses an __srcu_read_unlock() + * increment, that task's next __srcu_read_lock() will see the + * above counter update. Note that both this memory barrier + * and the one in srcu_readers_active_idx_check() provide the + * guarantee for __srcu_read_lock(). + */ + smp_mb(); /* D */ /* Pairs with C. */ +} + +/* + * If SRCU is likely idle, return true, otherwise return false. + * + * Note that it is OK for several current from-idle requests for a new + * grace period from idle to specify expediting because they will all end + * up requesting the same grace period anyhow. So no loss. + * + * Note also that if any CPU (including the current one) is still invoking + * callbacks, this function will nevertheless say "idle". This is not + * ideal, but the overhead of checking all CPUs' callback lists is even + * less ideal, especially on large systems. Furthermore, the wakeup + * can happen before the callback is fully removed, so we have no choice + * but to accept this type of error. + * + * This function is also subject to counter-wrap errors, but let's face + * it, if this function was preempted for enough time for the counters + * to wrap, it really doesn't matter whether or not we expedite the grace + * period. The extra overhead of a needlessly expedited grace period is + * negligible when amoritized over that time period, and the extra latency + * of a needlessly non-expedited grace period is similarly negligible. + */ +static bool srcu_might_be_idle(struct srcu_struct *sp) +{ + unsigned long curseq; + unsigned long flags; + struct srcu_data *sdp; + unsigned long t; + + /* If the local srcu_data structure has callbacks, not idle. */ + local_irq_save(flags); + sdp = this_cpu_ptr(sp->sda); + if (rcu_segcblist_pend_cbs(&sdp->srcu_cblist)) { + local_irq_restore(flags); + return false; /* Callbacks already present, so not idle. */ + } + local_irq_restore(flags); + + /* + * No local callbacks, so probabalistically probe global state. + * Exact information would require acquiring locks, which would + * kill scalability, hence the probabalistic nature of the probe. + */ + + /* First, see if enough time has passed since the last GP. */ + t = ktime_get_mono_fast_ns(); + if (exp_holdoff == 0 || + time_in_range_open(t, sp->srcu_last_gp_end, + sp->srcu_last_gp_end + exp_holdoff)) + return false; /* Too soon after last GP. */ + + /* Next, check for probable idleness. */ + curseq = rcu_seq_current(&sp->srcu_gp_seq); + smp_mb(); /* Order ->srcu_gp_seq with ->srcu_gp_seq_needed. */ + if (ULONG_CMP_LT(curseq, READ_ONCE(sp->srcu_gp_seq_needed))) + return false; /* Grace period in progress, so not idle. */ + smp_mb(); /* Order ->srcu_gp_seq with prior access. */ + if (curseq != rcu_seq_current(&sp->srcu_gp_seq)) + return false; /* GP # changed, so not idle. */ + return true; /* With reasonable probability, idle! */ +} + +/* + * Enqueue an SRCU callback on the srcu_data structure associated with + * the current CPU and the specified srcu_struct structure, initiating + * grace-period processing if it is not already running. + * + * Note that all CPUs must agree that the grace period extended beyond + * all pre-existing SRCU read-side critical section. On systems with + * more than one CPU, this means that when "func()" is invoked, each CPU + * is guaranteed to have executed a full memory barrier since the end of + * its last corresponding SRCU read-side critical section whose beginning + * preceded the call to call_rcu(). It also means that each CPU executing + * an SRCU read-side critical section that continues beyond the start of + * "func()" must have executed a memory barrier after the call_rcu() + * but before the beginning of that SRCU read-side critical section. + * Note that these guarantees include CPUs that are offline, idle, or + * executing in user mode, as well as CPUs that are executing in the kernel. + * + * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the + * resulting SRCU callback function "func()", then both CPU A and CPU + * B are guaranteed to execute a full memory barrier during the time + * interval between the call to call_rcu() and the invocation of "func()". + * This guarantee applies even if CPU A and CPU B are the same CPU (but + * again only if the system has more than one CPU). + * + * Of course, these guarantees apply only for invocations of call_srcu(), + * srcu_read_lock(), and srcu_read_unlock() that are all passed the same + * srcu_struct structure. + */ +void __call_srcu(struct srcu_struct *sp, struct rcu_head *rhp, + rcu_callback_t func, bool do_norm) +{ + unsigned long flags; + bool needexp = false; + bool needgp = false; + unsigned long s; + struct srcu_data *sdp; + + check_init_srcu_struct(sp); + rhp->func = func; + local_irq_save(flags); + sdp = this_cpu_ptr(sp->sda); + spin_lock(&sdp->lock); + rcu_segcblist_enqueue(&sdp->srcu_cblist, rhp, false); + rcu_segcblist_advance(&sdp->srcu_cblist, + rcu_seq_current(&sp->srcu_gp_seq)); + s = rcu_seq_snap(&sp->srcu_gp_seq); + (void)rcu_segcblist_accelerate(&sdp->srcu_cblist, s); + if (ULONG_CMP_LT(sdp->srcu_gp_seq_needed, s)) { + sdp->srcu_gp_seq_needed = s; + needgp = true; + } + if (!do_norm && ULONG_CMP_LT(sdp->srcu_gp_seq_needed_exp, s)) { + sdp->srcu_gp_seq_needed_exp = s; + needexp = true; + } + spin_unlock_irqrestore(&sdp->lock, flags); + if (needgp) + srcu_funnel_gp_start(sp, sdp, s, do_norm); + else if (needexp) + srcu_funnel_exp_start(sp, sdp->mynode, s); +} + +void call_srcu(struct srcu_struct *sp, struct rcu_head *rhp, + rcu_callback_t func) +{ + __call_srcu(sp, rhp, func, true); +} +EXPORT_SYMBOL_GPL(call_srcu); + +/* + * Helper function for synchronize_srcu() and synchronize_srcu_expedited(). + */ +static void __synchronize_srcu(struct srcu_struct *sp, bool do_norm) +{ + struct rcu_synchronize rcu; + + RCU_LOCKDEP_WARN(lock_is_held(&sp->dep_map) || + lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_srcu() in same-type SRCU (or in RCU) read-side critical section"); + + if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE) + return; + might_sleep(); + check_init_srcu_struct(sp); + init_completion(&rcu.completion); + init_rcu_head_on_stack(&rcu.head); + __call_srcu(sp, &rcu.head, wakeme_after_rcu, do_norm); + wait_for_completion(&rcu.completion); + destroy_rcu_head_on_stack(&rcu.head); +} + +/** + * synchronize_srcu_expedited - Brute-force SRCU grace period + * @sp: srcu_struct with which to synchronize. + * + * Wait for an SRCU grace period to elapse, but be more aggressive about + * spinning rather than blocking when waiting. + * + * Note that synchronize_srcu_expedited() has the same deadlock and + * memory-ordering properties as does synchronize_srcu(). + */ +void synchronize_srcu_expedited(struct srcu_struct *sp) +{ + __synchronize_srcu(sp, rcu_gp_is_normal()); +} +EXPORT_SYMBOL_GPL(synchronize_srcu_expedited); + +/** + * synchronize_srcu - wait for prior SRCU read-side critical-section completion + * @sp: srcu_struct with which to synchronize. + * + * Wait for the count to drain to zero of both indexes. To avoid the + * possible starvation of synchronize_srcu(), it waits for the count of + * the index=((->srcu_idx & 1) ^ 1) to drain to zero at first, + * and then flip the srcu_idx and wait for the count of the other index. + * + * Can block; must be called from process context. + * + * Note that it is illegal to call synchronize_srcu() from the corresponding + * SRCU read-side critical section; doing so will result in deadlock. + * However, it is perfectly legal to call synchronize_srcu() on one + * srcu_struct from some other srcu_struct's read-side critical section, + * as long as the resulting graph of srcu_structs is acyclic. + * + * There are memory-ordering constraints implied by synchronize_srcu(). + * On systems with more than one CPU, when synchronize_srcu() returns, + * each CPU is guaranteed to have executed a full memory barrier since + * the end of its last corresponding SRCU-sched read-side critical section + * whose beginning preceded the call to synchronize_srcu(). In addition, + * each CPU having an SRCU read-side critical section that extends beyond + * the return from synchronize_srcu() is guaranteed to have executed a + * full memory barrier after the beginning of synchronize_srcu() and before + * the beginning of that SRCU read-side critical section. Note that these + * guarantees include CPUs that are offline, idle, or executing in user mode, + * as well as CPUs that are executing in the kernel. + * + * Furthermore, if CPU A invoked synchronize_srcu(), which returned + * to its caller on CPU B, then both CPU A and CPU B are guaranteed + * to have executed a full memory barrier during the execution of + * synchronize_srcu(). This guarantee applies even if CPU A and CPU B + * are the same CPU, but again only if the system has more than one CPU. + * + * Of course, these memory-ordering guarantees apply only when + * synchronize_srcu(), srcu_read_lock(), and srcu_read_unlock() are + * passed the same srcu_struct structure. + * + * If SRCU is likely idle, expedite the first request. This semantic + * was provided by Classic SRCU, and is relied upon by its users, so TREE + * SRCU must also provide it. Note that detecting idleness is heuristic + * and subject to both false positives and negatives. + */ +void synchronize_srcu(struct srcu_struct *sp) +{ + if (srcu_might_be_idle(sp) || rcu_gp_is_expedited()) + synchronize_srcu_expedited(sp); + else + __synchronize_srcu(sp, true); +} +EXPORT_SYMBOL_GPL(synchronize_srcu); + +/* + * Callback function for srcu_barrier() use. + */ +static void srcu_barrier_cb(struct rcu_head *rhp) +{ + struct srcu_data *sdp; + struct srcu_struct *sp; + + sdp = container_of(rhp, struct srcu_data, srcu_barrier_head); + sp = sdp->sp; + if (atomic_dec_and_test(&sp->srcu_barrier_cpu_cnt)) + complete(&sp->srcu_barrier_completion); +} + +/** + * srcu_barrier - Wait until all in-flight call_srcu() callbacks complete. + * @sp: srcu_struct on which to wait for in-flight callbacks. + */ +void srcu_barrier(struct srcu_struct *sp) +{ + int cpu; + struct srcu_data *sdp; + unsigned long s = rcu_seq_snap(&sp->srcu_barrier_seq); + + check_init_srcu_struct(sp); + mutex_lock(&sp->srcu_barrier_mutex); + if (rcu_seq_done(&sp->srcu_barrier_seq, s)) { + smp_mb(); /* Force ordering following return. */ + mutex_unlock(&sp->srcu_barrier_mutex); + return; /* Someone else did our work for us. */ + } + rcu_seq_start(&sp->srcu_barrier_seq); + init_completion(&sp->srcu_barrier_completion); + + /* Initial count prevents reaching zero until all CBs are posted. */ + atomic_set(&sp->srcu_barrier_cpu_cnt, 1); + + /* + * Each pass through this loop enqueues a callback, but only + * on CPUs already having callbacks enqueued. Note that if + * a CPU already has callbacks enqueue, it must have already + * registered the need for a future grace period, so all we + * need do is enqueue a callback that will use the same + * grace period as the last callback already in the queue. + */ + for_each_possible_cpu(cpu) { + sdp = per_cpu_ptr(sp->sda, cpu); + spin_lock_irq(&sdp->lock); + atomic_inc(&sp->srcu_barrier_cpu_cnt); + sdp->srcu_barrier_head.func = srcu_barrier_cb; + if (!rcu_segcblist_entrain(&sdp->srcu_cblist, + &sdp->srcu_barrier_head, 0)) + atomic_dec(&sp->srcu_barrier_cpu_cnt); + spin_unlock_irq(&sdp->lock); + } + + /* Remove the initial count, at which point reaching zero can happen. */ + if (atomic_dec_and_test(&sp->srcu_barrier_cpu_cnt)) + complete(&sp->srcu_barrier_completion); + wait_for_completion(&sp->srcu_barrier_completion); + + rcu_seq_end(&sp->srcu_barrier_seq); + mutex_unlock(&sp->srcu_barrier_mutex); +} +EXPORT_SYMBOL_GPL(srcu_barrier); + +/** + * srcu_batches_completed - return batches completed. + * @sp: srcu_struct on which to report batch completion. + * + * Report the number of batches, correlated with, but not necessarily + * precisely the same as, the number of grace periods that have elapsed. + */ +unsigned long srcu_batches_completed(struct srcu_struct *sp) +{ + return sp->srcu_idx; +} +EXPORT_SYMBOL_GPL(srcu_batches_completed); + +/* + * Core SRCU state machine. Push state bits of ->srcu_gp_seq + * to SRCU_STATE_SCAN2, and invoke srcu_gp_end() when scan has + * completed in that state. + */ +static void srcu_advance_state(struct srcu_struct *sp) +{ + int idx; + + mutex_lock(&sp->srcu_gp_mutex); + + /* + * Because readers might be delayed for an extended period after + * fetching ->srcu_idx for their index, at any point in time there + * might well be readers using both idx=0 and idx=1. We therefore + * need to wait for readers to clear from both index values before + * invoking a callback. + * + * The load-acquire ensures that we see the accesses performed + * by the prior grace period. + */ + idx = rcu_seq_state(smp_load_acquire(&sp->srcu_gp_seq)); /* ^^^ */ + if (idx == SRCU_STATE_IDLE) { + spin_lock_irq(&sp->gp_lock); + if (ULONG_CMP_GE(sp->srcu_gp_seq, sp->srcu_gp_seq_needed)) { + WARN_ON_ONCE(rcu_seq_state(sp->srcu_gp_seq)); + spin_unlock_irq(&sp->gp_lock); + mutex_unlock(&sp->srcu_gp_mutex); + return; + } + idx = rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)); + if (idx == SRCU_STATE_IDLE) + srcu_gp_start(sp); + spin_unlock_irq(&sp->gp_lock); + if (idx != SRCU_STATE_IDLE) { + mutex_unlock(&sp->srcu_gp_mutex); + return; /* Someone else started the grace period. */ + } + } + + if (rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)) == SRCU_STATE_SCAN1) { + idx = 1 ^ (sp->srcu_idx & 1); + if (!try_check_zero(sp, idx, 1)) { + mutex_unlock(&sp->srcu_gp_mutex); + return; /* readers present, retry later. */ + } + srcu_flip(sp); + rcu_seq_set_state(&sp->srcu_gp_seq, SRCU_STATE_SCAN2); + } + + if (rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)) == SRCU_STATE_SCAN2) { + + /* + * SRCU read-side critical sections are normally short, + * so check at least twice in quick succession after a flip. + */ + idx = 1 ^ (sp->srcu_idx & 1); + if (!try_check_zero(sp, idx, 2)) { + mutex_unlock(&sp->srcu_gp_mutex); + return; /* readers present, retry later. */ + } + srcu_gp_end(sp); /* Releases ->srcu_gp_mutex. */ + } +} + +/* + * Invoke a limited number of SRCU callbacks that have passed through + * their grace period. If there are more to do, SRCU will reschedule + * the workqueue. Note that needed memory barriers have been executed + * in this task's context by srcu_readers_active_idx_check(). + */ +static void srcu_invoke_callbacks(struct work_struct *work) +{ + bool more; + struct rcu_cblist ready_cbs; + struct rcu_head *rhp; + struct srcu_data *sdp; + struct srcu_struct *sp; + + sdp = container_of(work, struct srcu_data, work.work); + sp = sdp->sp; + rcu_cblist_init(&ready_cbs); + spin_lock_irq(&sdp->lock); + smp_mb(); /* Old grace periods before callback invocation! */ + rcu_segcblist_advance(&sdp->srcu_cblist, + rcu_seq_current(&sp->srcu_gp_seq)); + if (sdp->srcu_cblist_invoking || + !rcu_segcblist_ready_cbs(&sdp->srcu_cblist)) { + spin_unlock_irq(&sdp->lock); + return; /* Someone else on the job or nothing to do. */ + } + + /* We are on the job! Extract and invoke ready callbacks. */ + sdp->srcu_cblist_invoking = true; + rcu_segcblist_extract_done_cbs(&sdp->srcu_cblist, &ready_cbs); + spin_unlock_irq(&sdp->lock); + rhp = rcu_cblist_dequeue(&ready_cbs); + for (; rhp != NULL; rhp = rcu_cblist_dequeue(&ready_cbs)) { + local_bh_disable(); + rhp->func(rhp); + local_bh_enable(); + } + + /* + * Update counts, accelerate new callbacks, and if needed, + * schedule another round of callback invocation. + */ + spin_lock_irq(&sdp->lock); + rcu_segcblist_insert_count(&sdp->srcu_cblist, &ready_cbs); + (void)rcu_segcblist_accelerate(&sdp->srcu_cblist, + rcu_seq_snap(&sp->srcu_gp_seq)); + sdp->srcu_cblist_invoking = false; + more = rcu_segcblist_ready_cbs(&sdp->srcu_cblist); + spin_unlock_irq(&sdp->lock); + if (more) + srcu_schedule_cbs_sdp(sdp, 0); +} + +/* + * Finished one round of SRCU grace period. Start another if there are + * more SRCU callbacks queued, otherwise put SRCU into not-running state. + */ +static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay) +{ + bool pushgp = true; + + spin_lock_irq(&sp->gp_lock); + if (ULONG_CMP_GE(sp->srcu_gp_seq, sp->srcu_gp_seq_needed)) { + if (!WARN_ON_ONCE(rcu_seq_state(sp->srcu_gp_seq))) { + /* All requests fulfilled, time to go idle. */ + pushgp = false; + } + } else if (!rcu_seq_state(sp->srcu_gp_seq)) { + /* Outstanding request and no GP. Start one. */ + srcu_gp_start(sp); + } + spin_unlock_irq(&sp->gp_lock); + + if (pushgp) + queue_delayed_work(system_power_efficient_wq, &sp->work, delay); +} + +/* + * This is the work-queue function that handles SRCU grace periods. + */ +void process_srcu(struct work_struct *work) +{ + struct srcu_struct *sp; + + sp = container_of(work, struct srcu_struct, work.work); + + srcu_advance_state(sp); + srcu_reschedule(sp, srcu_get_delay(sp)); +} +EXPORT_SYMBOL_GPL(process_srcu); + +void srcutorture_get_gp_data(enum rcutorture_type test_type, + struct srcu_struct *sp, int *flags, + unsigned long *gpnum, unsigned long *completed) +{ + if (test_type != SRCU_FLAVOR) + return; + *flags = 0; + *completed = rcu_seq_ctr(sp->srcu_gp_seq); + *gpnum = rcu_seq_ctr(sp->srcu_gp_seq_needed); +} +EXPORT_SYMBOL_GPL(srcutorture_get_gp_data); diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 6ad330dbbae2..e5385731e391 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -79,7 +79,7 @@ EXPORT_SYMBOL(__rcu_is_watching); */ static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) { - RCU_TRACE(reset_cpu_stall_ticks(rcp)); + RCU_TRACE(reset_cpu_stall_ticks(rcp);) if (rcp->donetail != rcp->curtail) { rcp->donetail = rcp->curtail; return 1; @@ -125,7 +125,7 @@ void rcu_bh_qs(void) */ void rcu_check_callbacks(int user) { - RCU_TRACE(check_cpu_stalls()); + RCU_TRACE(check_cpu_stalls();) if (user) rcu_sched_qs(); else if (!in_softirq()) @@ -143,7 +143,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) const char *rn = NULL; struct rcu_head *next, *list; unsigned long flags; - RCU_TRACE(int cb_count = 0); + RCU_TRACE(int cb_count = 0;) /* Move the ready-to-invoke callbacks to a local list. */ local_irq_save(flags); @@ -152,7 +152,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) local_irq_restore(flags); return; } - RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1)); + RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1);) list = rcp->rcucblist; rcp->rcucblist = *rcp->donetail; *rcp->donetail = NULL; @@ -162,7 +162,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) local_irq_restore(flags); /* Invoke the callbacks on the local list. */ - RCU_TRACE(rn = rcp->name); + RCU_TRACE(rn = rcp->name;) while (list) { next = list->next; prefetch(next); @@ -171,9 +171,9 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) __rcu_reclaim(rn, list); local_bh_enable(); list = next; - RCU_TRACE(cb_count++); + RCU_TRACE(cb_count++;) } - RCU_TRACE(rcu_trace_sub_qlen(rcp, cb_count)); + RCU_TRACE(rcu_trace_sub_qlen(rcp, cb_count);) RCU_TRACE(trace_rcu_batch_end(rcp->name, cb_count, 0, need_resched(), is_idle_task(current), @@ -221,7 +221,7 @@ static void __call_rcu(struct rcu_head *head, local_irq_save(flags); *rcp->curtail = head; rcp->curtail = &head->next; - RCU_TRACE(rcp->qlen++); + RCU_TRACE(rcp->qlen++;) local_irq_restore(flags); if (unlikely(is_idle_task(current))) { @@ -254,8 +254,8 @@ EXPORT_SYMBOL_GPL(call_rcu_bh); void __init rcu_init(void) { open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); - RCU_TRACE(reset_cpu_stall_ticks(&rcu_sched_ctrlblk)); - RCU_TRACE(reset_cpu_stall_ticks(&rcu_bh_ctrlblk)); + RCU_TRACE(reset_cpu_stall_ticks(&rcu_sched_ctrlblk);) + RCU_TRACE(reset_cpu_stall_ticks(&rcu_bh_ctrlblk);) rcu_early_boot_tests(); } diff --git a/kernel/rcu/tiny_plugin.h b/kernel/rcu/tiny_plugin.h index c64b827ecbca..371034e77f87 100644 --- a/kernel/rcu/tiny_plugin.h +++ b/kernel/rcu/tiny_plugin.h @@ -52,7 +52,7 @@ static struct rcu_ctrlblk rcu_bh_ctrlblk = { RCU_TRACE(.name = "rcu_bh") }; -#ifdef CONFIG_DEBUG_LOCK_ALLOC +#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SRCU) #include <linux/kernel_stat.h> int rcu_scheduler_active __read_mostly; @@ -65,15 +65,16 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active); * to RCU_SCHEDULER_RUNNING, skipping the RCU_SCHEDULER_INIT stage. * The reason for this is that Tiny RCU does not need kthreads, so does * not have to care about the fact that the scheduler is half-initialized - * at a certain phase of the boot process. + * at a certain phase of the boot process. Unless SRCU is in the mix. */ void __init rcu_scheduler_starting(void) { WARN_ON(nr_context_switches() > 0); - rcu_scheduler_active = RCU_SCHEDULER_RUNNING; + rcu_scheduler_active = IS_ENABLED(CONFIG_SRCU) + ? RCU_SCHEDULER_INIT : RCU_SCHEDULER_RUNNING; } -#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SRCU) */ #ifdef CONFIG_RCU_TRACE @@ -162,8 +163,8 @@ static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp) static void check_cpu_stalls(void) { - RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk)); - RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk)); + RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk);) + RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk);) } #endif /* #ifdef CONFIG_RCU_TRACE */ diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index a6dcf3bd244f..e354e475e645 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -98,8 +98,8 @@ struct rcu_state sname##_state = { \ .gpnum = 0UL - 300UL, \ .completed = 0UL - 300UL, \ .orphan_lock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.orphan_lock), \ - .orphan_nxttail = &sname##_state.orphan_nxtlist, \ - .orphan_donetail = &sname##_state.orphan_donelist, \ + .orphan_pend = RCU_CBLIST_INITIALIZER(sname##_state.orphan_pend), \ + .orphan_done = RCU_CBLIST_INITIALIZER(sname##_state.orphan_done), \ .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \ .name = RCU_STATE_NAME(sname), \ .abbr = sabbr, \ @@ -124,7 +124,7 @@ static int rcu_fanout_leaf = RCU_FANOUT_LEAF; module_param(rcu_fanout_leaf, int, 0444); int rcu_num_lvls __read_mostly = RCU_NUM_LVLS; /* Number of rcu_nodes at specified level. */ -static int num_rcu_lvl[] = NUM_RCU_LVL_INIT; +int num_rcu_lvl[] = NUM_RCU_LVL_INIT; int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */ /* panic() on RCU Stall sysctl. */ int sysctl_panic_on_rcu_stall __read_mostly; @@ -200,7 +200,7 @@ static const int gp_cleanup_delay; /* * Number of grace periods between delays, normalized by the duration of - * the delay. The longer the the delay, the more the grace periods between + * the delay. The longer the delay, the more the grace periods between * each delay. The reason for this normalization is that it means that, * for non-zero delays, the overall slowdown of grace periods is constant * regardless of the duration of the delay. This arrangement balances @@ -273,11 +273,19 @@ void rcu_bh_qs(void) } } -static DEFINE_PER_CPU(int, rcu_sched_qs_mask); +/* + * Steal a bit from the bottom of ->dynticks for idle entry/exit + * control. Initially this is for TLB flushing. + */ +#define RCU_DYNTICK_CTRL_MASK 0x1 +#define RCU_DYNTICK_CTRL_CTR (RCU_DYNTICK_CTRL_MASK + 1) +#ifndef rcu_eqs_special_exit +#define rcu_eqs_special_exit() do { } while (0) +#endif static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { .dynticks_nesting = DYNTICK_TASK_EXIT_IDLE, - .dynticks = ATOMIC_INIT(1), + .dynticks = ATOMIC_INIT(RCU_DYNTICK_CTRL_CTR), #ifdef CONFIG_NO_HZ_FULL_SYSIDLE .dynticks_idle_nesting = DYNTICK_TASK_NEST_VALUE, .dynticks_idle = ATOMIC_INIT(1), @@ -305,15 +313,20 @@ bool rcu_irq_enter_disabled(void) static void rcu_dynticks_eqs_enter(void) { struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); - int special; + int seq; /* - * CPUs seeing atomic_inc_return() must see prior RCU read-side + * CPUs seeing atomic_add_return() must see prior RCU read-side * critical sections, and we also must force ordering with the * next idle sojourn. */ - special = atomic_inc_return(&rdtp->dynticks); - WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && special & 0x1); + seq = atomic_add_return(RCU_DYNTICK_CTRL_CTR, &rdtp->dynticks); + /* Better be in an extended quiescent state! */ + WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && + (seq & RCU_DYNTICK_CTRL_CTR)); + /* Better not have special action (TLB flush) pending! */ + WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && + (seq & RCU_DYNTICK_CTRL_MASK)); } /* @@ -323,15 +336,22 @@ static void rcu_dynticks_eqs_enter(void) static void rcu_dynticks_eqs_exit(void) { struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); - int special; + int seq; /* - * CPUs seeing atomic_inc_return() must see prior idle sojourns, + * CPUs seeing atomic_add_return() must see prior idle sojourns, * and we also must force ordering with the next RCU read-side * critical section. */ - special = atomic_inc_return(&rdtp->dynticks); - WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !(special & 0x1)); + seq = atomic_add_return(RCU_DYNTICK_CTRL_CTR, &rdtp->dynticks); + WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && + !(seq & RCU_DYNTICK_CTRL_CTR)); + if (seq & RCU_DYNTICK_CTRL_MASK) { + atomic_andnot(RCU_DYNTICK_CTRL_MASK, &rdtp->dynticks); + smp_mb__after_atomic(); /* _exit after clearing mask. */ + /* Prefer duplicate flushes to losing a flush. */ + rcu_eqs_special_exit(); + } } /* @@ -348,9 +368,9 @@ static void rcu_dynticks_eqs_online(void) { struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); - if (atomic_read(&rdtp->dynticks) & 0x1) + if (atomic_read(&rdtp->dynticks) & RCU_DYNTICK_CTRL_CTR) return; - atomic_add(0x1, &rdtp->dynticks); + atomic_add(RCU_DYNTICK_CTRL_CTR, &rdtp->dynticks); } /* @@ -362,7 +382,7 @@ bool rcu_dynticks_curr_cpu_in_eqs(void) { struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); - return !(atomic_read(&rdtp->dynticks) & 0x1); + return !(atomic_read(&rdtp->dynticks) & RCU_DYNTICK_CTRL_CTR); } /* @@ -373,7 +393,7 @@ int rcu_dynticks_snap(struct rcu_dynticks *rdtp) { int snap = atomic_add_return(0, &rdtp->dynticks); - return snap; + return snap & ~RCU_DYNTICK_CTRL_MASK; } /* @@ -382,7 +402,7 @@ int rcu_dynticks_snap(struct rcu_dynticks *rdtp) */ static bool rcu_dynticks_in_eqs(int snap) { - return !(snap & 0x1); + return !(snap & RCU_DYNTICK_CTRL_CTR); } /* @@ -402,14 +422,34 @@ static bool rcu_dynticks_in_eqs_since(struct rcu_dynticks *rdtp, int snap) static void rcu_dynticks_momentary_idle(void) { struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); - int special = atomic_add_return(2, &rdtp->dynticks); + int special = atomic_add_return(2 * RCU_DYNTICK_CTRL_CTR, + &rdtp->dynticks); /* It is illegal to call this from idle state. */ - WARN_ON_ONCE(!(special & 0x1)); + WARN_ON_ONCE(!(special & RCU_DYNTICK_CTRL_CTR)); } -DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, rcu_qs_ctr); -EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr); +/* + * Set the special (bottom) bit of the specified CPU so that it + * will take special action (such as flushing its TLB) on the + * next exit from an extended quiescent state. Returns true if + * the bit was successfully set, or false if the CPU was not in + * an extended quiescent state. + */ +bool rcu_eqs_special_set(int cpu) +{ + int old; + int new; + struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu); + + do { + old = atomic_read(&rdtp->dynticks); + if (old & RCU_DYNTICK_CTRL_CTR) + return false; + new = old | RCU_DYNTICK_CTRL_MASK; + } while (atomic_cmpxchg(&rdtp->dynticks, old, new) != old); + return true; +} /* * Let the RCU core know that this CPU has gone through the scheduler, @@ -418,44 +458,14 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr); * memory barriers to let the RCU core know about it, regardless of what * this CPU might (or might not) do in the near future. * - * We inform the RCU core by emulating a zero-duration dyntick-idle - * period, which we in turn do by incrementing the ->dynticks counter - * by two. + * We inform the RCU core by emulating a zero-duration dyntick-idle period. * * The caller must have disabled interrupts. */ static void rcu_momentary_dyntick_idle(void) { - struct rcu_data *rdp; - int resched_mask; - struct rcu_state *rsp; - - /* - * Yes, we can lose flag-setting operations. This is OK, because - * the flag will be set again after some delay. - */ - resched_mask = raw_cpu_read(rcu_sched_qs_mask); - raw_cpu_write(rcu_sched_qs_mask, 0); - - /* Find the flavor that needs a quiescent state. */ - for_each_rcu_flavor(rsp) { - rdp = raw_cpu_ptr(rsp->rda); - if (!(resched_mask & rsp->flavor_mask)) - continue; - smp_mb(); /* rcu_sched_qs_mask before cond_resched_completed. */ - if (READ_ONCE(rdp->mynode->completed) != - READ_ONCE(rdp->cond_resched_completed)) - continue; - - /* - * Pretend to be momentarily idle for the quiescent state. - * This allows the grace-period kthread to record the - * quiescent state, with no need for this CPU to do anything - * further. - */ - rcu_dynticks_momentary_idle(); - break; - } + raw_cpu_write(rcu_dynticks.rcu_need_heavy_qs, false); + rcu_dynticks_momentary_idle(); } /* @@ -463,14 +473,22 @@ static void rcu_momentary_dyntick_idle(void) * and requires special handling for preemptible RCU. * The caller must have disabled interrupts. */ -void rcu_note_context_switch(void) +void rcu_note_context_switch(bool preempt) { barrier(); /* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization(TPS("Start context switch")); rcu_sched_qs(); rcu_preempt_note_context_switch(); - if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) + /* Load rcu_urgent_qs before other flags. */ + if (!smp_load_acquire(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs))) + goto out; + this_cpu_write(rcu_dynticks.rcu_urgent_qs, false); + if (unlikely(raw_cpu_read(rcu_dynticks.rcu_need_heavy_qs))) rcu_momentary_dyntick_idle(); + this_cpu_inc(rcu_dynticks.rcu_qs_ctr); + if (!preempt) + rcu_note_voluntary_context_switch_lite(current); +out: trace_rcu_utilization(TPS("End context switch")); barrier(); /* Avoid RCU read-side critical sections leaking up. */ } @@ -493,29 +511,26 @@ void rcu_all_qs(void) { unsigned long flags; + if (!raw_cpu_read(rcu_dynticks.rcu_urgent_qs)) + return; + preempt_disable(); + /* Load rcu_urgent_qs before other flags. */ + if (!smp_load_acquire(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs))) { + preempt_enable(); + return; + } + this_cpu_write(rcu_dynticks.rcu_urgent_qs, false); barrier(); /* Avoid RCU read-side critical sections leaking down. */ - if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) { + if (unlikely(raw_cpu_read(rcu_dynticks.rcu_need_heavy_qs))) { local_irq_save(flags); rcu_momentary_dyntick_idle(); local_irq_restore(flags); } - if (unlikely(raw_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))) { - /* - * Yes, we just checked a per-CPU variable with preemption - * enabled, so we might be migrated to some other CPU at - * this point. That is OK because in that case, the - * migration will supply the needed quiescent state. - * We might end up needlessly disabling preemption and - * invoking rcu_sched_qs() on the destination CPU, but - * the probability and cost are both quite low, so this - * should not be a problem in practice. - */ - preempt_disable(); + if (unlikely(raw_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))) rcu_sched_qs(); - preempt_enable(); - } - this_cpu_inc(rcu_qs_ctr); + this_cpu_inc(rcu_dynticks.rcu_qs_ctr); barrier(); /* Avoid RCU read-side critical sections leaking up. */ + preempt_enable(); } EXPORT_SYMBOL_GPL(rcu_all_qs); @@ -704,15 +719,11 @@ void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags, default: break; } - if (rsp != NULL) { - *flags = READ_ONCE(rsp->gp_flags); - *gpnum = READ_ONCE(rsp->gpnum); - *completed = READ_ONCE(rsp->completed); + if (rsp == NULL) return; - } - *flags = 0; - *gpnum = 0; - *completed = 0; + *flags = READ_ONCE(rsp->gp_flags); + *gpnum = READ_ONCE(rsp->gpnum); + *completed = READ_ONCE(rsp->completed); } EXPORT_SYMBOL_GPL(rcutorture_get_gp_data); @@ -728,16 +739,6 @@ void rcutorture_record_progress(unsigned long vernum) EXPORT_SYMBOL_GPL(rcutorture_record_progress); /* - * Does the CPU have callbacks ready to be invoked? - */ -static int -cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp) -{ - return &rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL] && - rdp->nxttail[RCU_NEXT_TAIL] != NULL; -} - -/* * Return the root node of the specified rcu_state structure. */ static struct rcu_node *rcu_get_root(struct rcu_state *rsp) @@ -767,21 +768,17 @@ static int rcu_future_needs_gp(struct rcu_state *rsp) static bool cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp) { - int i; - if (rcu_gp_in_progress(rsp)) return false; /* No, a grace period is already in progress. */ if (rcu_future_needs_gp(rsp)) return true; /* Yes, a no-CBs CPU needs one. */ - if (!rdp->nxttail[RCU_NEXT_TAIL]) + if (!rcu_segcblist_is_enabled(&rdp->cblist)) return false; /* No, this is a no-CBs (or offline) CPU. */ - if (*rdp->nxttail[RCU_NEXT_READY_TAIL]) + if (!rcu_segcblist_restempty(&rdp->cblist, RCU_NEXT_READY_TAIL)) return true; /* Yes, CPU has newly registered callbacks. */ - for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) - if (rdp->nxttail[i - 1] != rdp->nxttail[i] && - ULONG_CMP_LT(READ_ONCE(rsp->completed), - rdp->nxtcompleted[i])) - return true; /* Yes, CBs for future grace period. */ + if (rcu_segcblist_future_gp_needed(&rdp->cblist, + READ_ONCE(rsp->completed))) + return true; /* Yes, CBs for future grace period. */ return false; /* No grace period needed. */ } @@ -1162,6 +1159,24 @@ bool notrace rcu_is_watching(void) } EXPORT_SYMBOL_GPL(rcu_is_watching); +/* + * If a holdout task is actually running, request an urgent quiescent + * state from its CPU. This is unsynchronized, so migrations can cause + * the request to go to the wrong CPU. Which is OK, all that will happen + * is that the CPU's next context switch will be a bit slower and next + * time around this task will generate another request. + */ +void rcu_request_urgent_qs_task(struct task_struct *t) +{ + int cpu; + + barrier(); + cpu = task_cpu(t); + if (!task_curr(t)) + return; /* This task is not running on that CPU. */ + smp_store_release(per_cpu_ptr(&rcu_dynticks.rcu_urgent_qs, cpu), true); +} + #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU) /* @@ -1247,7 +1262,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, bool *isidle, unsigned long *maxj) { unsigned long jtsq; - int *rcrmp; + bool *rnhqp; + bool *ruqp; unsigned long rjtsc; struct rcu_node *rnp; @@ -1283,11 +1299,15 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, * might not be the case for nohz_full CPUs looping in the kernel. */ rnp = rdp->mynode; + ruqp = per_cpu_ptr(&rcu_dynticks.rcu_urgent_qs, rdp->cpu); if (time_after(jiffies, rdp->rsp->gp_start + jtsq) && - READ_ONCE(rdp->rcu_qs_ctr_snap) != per_cpu(rcu_qs_ctr, rdp->cpu) && + READ_ONCE(rdp->rcu_qs_ctr_snap) != per_cpu(rcu_dynticks.rcu_qs_ctr, rdp->cpu) && READ_ONCE(rdp->gpnum) == rnp->gpnum && !rdp->gpwrap) { trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("rqc")); return 1; + } else { + /* Load rcu_qs_ctr before store to rcu_urgent_qs. */ + smp_store_release(ruqp, true); } /* Check for the CPU being offline. */ @@ -1304,7 +1324,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, * in-kernel CPU-bound tasks cannot advance grace periods. * So if the grace period is old enough, make the CPU pay attention. * Note that the unsynchronized assignments to the per-CPU - * rcu_sched_qs_mask variable are safe. Yes, setting of + * rcu_need_heavy_qs variable are safe. Yes, setting of * bits can be lost, but they will be set again on the next * force-quiescent-state pass. So lost bit sets do not result * in incorrect behavior, merely in a grace period lasting @@ -1318,16 +1338,13 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, * is set too high, we override with half of the RCU CPU stall * warning delay. */ - rcrmp = &per_cpu(rcu_sched_qs_mask, rdp->cpu); - if (time_after(jiffies, rdp->rsp->gp_start + jtsq) || - time_after(jiffies, rdp->rsp->jiffies_resched)) { - if (!(READ_ONCE(*rcrmp) & rdp->rsp->flavor_mask)) { - WRITE_ONCE(rdp->cond_resched_completed, - READ_ONCE(rdp->mynode->completed)); - smp_mb(); /* ->cond_resched_completed before *rcrmp. */ - WRITE_ONCE(*rcrmp, - READ_ONCE(*rcrmp) + rdp->rsp->flavor_mask); - } + rnhqp = &per_cpu(rcu_dynticks.rcu_need_heavy_qs, rdp->cpu); + if (!READ_ONCE(*rnhqp) && + (time_after(jiffies, rdp->rsp->gp_start + jtsq) || + time_after(jiffies, rdp->rsp->jiffies_resched))) { + WRITE_ONCE(*rnhqp, true); + /* Store rcu_need_heavy_qs before rcu_urgent_qs. */ + smp_store_release(ruqp, true); rdp->rsp->jiffies_resched += 5; /* Re-enable beating. */ } @@ -1487,7 +1504,8 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) print_cpu_stall_info_end(); for_each_possible_cpu(cpu) - totqlen += per_cpu_ptr(rsp->rda, cpu)->qlen; + totqlen += rcu_segcblist_n_cbs(&per_cpu_ptr(rsp->rda, + cpu)->cblist); pr_cont("(detected by %d, t=%ld jiffies, g=%ld, c=%ld, q=%lu)\n", smp_processor_id(), (long)(jiffies - rsp->gp_start), (long)rsp->gpnum, (long)rsp->completed, totqlen); @@ -1541,7 +1559,8 @@ static void print_cpu_stall(struct rcu_state *rsp) print_cpu_stall_info(rsp, smp_processor_id()); print_cpu_stall_info_end(); for_each_possible_cpu(cpu) - totqlen += per_cpu_ptr(rsp->rda, cpu)->qlen; + totqlen += rcu_segcblist_n_cbs(&per_cpu_ptr(rsp->rda, + cpu)->cblist); pr_cont(" (t=%lu jiffies g=%ld c=%ld q=%lu)\n", jiffies - rsp->gp_start, (long)rsp->gpnum, (long)rsp->completed, totqlen); @@ -1644,30 +1663,6 @@ void rcu_cpu_stall_reset(void) } /* - * Initialize the specified rcu_data structure's default callback list - * to empty. The default callback list is the one that is not used by - * no-callbacks CPUs. - */ -static void init_default_callback_list(struct rcu_data *rdp) -{ - int i; - - rdp->nxtlist = NULL; - for (i = 0; i < RCU_NEXT_SIZE; i++) - rdp->nxttail[i] = &rdp->nxtlist; -} - -/* - * Initialize the specified rcu_data structure's callback list to empty. - */ -static void init_callback_list(struct rcu_data *rdp) -{ - if (init_nocb_callback_list(rdp)) - return; - init_default_callback_list(rdp); -} - -/* * Determine the value that ->completed will have at the end of the * next subsequent grace period. This is used to tag callbacks so that * a CPU can invoke callbacks in a timely fashion even if that CPU has @@ -1721,7 +1716,6 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp, unsigned long *c_out) { unsigned long c; - int i; bool ret = false; struct rcu_node *rnp_root = rcu_get_root(rdp->rsp); @@ -1767,13 +1761,11 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp, /* * Get a new grace-period number. If there really is no grace * period in progress, it will be smaller than the one we obtained - * earlier. Adjust callbacks as needed. Note that even no-CBs - * CPUs have a ->nxtcompleted[] array, so no no-CBs checks needed. + * earlier. Adjust callbacks as needed. */ c = rcu_cbs_completed(rdp->rsp, rnp_root); - for (i = RCU_DONE_TAIL; i < RCU_NEXT_TAIL; i++) - if (ULONG_CMP_LT(c, rdp->nxtcompleted[i])) - rdp->nxtcompleted[i] = c; + if (!rcu_is_nocb_cpu(rdp->cpu)) + (void)rcu_segcblist_accelerate(&rdp->cblist, c); /* * If the needed for the required grace period is already @@ -1805,9 +1797,7 @@ out: /* * Clean up any old requests for the just-ended grace period. Also return - * whether any additional grace periods have been requested. Also invoke - * rcu_nocb_gp_cleanup() in order to wake up any no-callbacks kthreads - * waiting for this grace period to complete. + * whether any additional grace periods have been requested. */ static int rcu_future_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) { @@ -1853,57 +1843,27 @@ static void rcu_gp_kthread_wake(struct rcu_state *rsp) static bool rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) { - unsigned long c; - int i; - bool ret; - - /* If the CPU has no callbacks, nothing to do. */ - if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL]) - return false; - - /* - * Starting from the sublist containing the callbacks most - * recently assigned a ->completed number and working down, find the - * first sublist that is not assignable to an upcoming grace period. - * Such a sublist has something in it (first two tests) and has - * a ->completed number assigned that will complete sooner than - * the ->completed number for newly arrived callbacks (last test). - * - * The key point is that any later sublist can be assigned the - * same ->completed number as the newly arrived callbacks, which - * means that the callbacks in any of these later sublist can be - * grouped into a single sublist, whether or not they have already - * been assigned a ->completed number. - */ - c = rcu_cbs_completed(rsp, rnp); - for (i = RCU_NEXT_TAIL - 1; i > RCU_DONE_TAIL; i--) - if (rdp->nxttail[i] != rdp->nxttail[i - 1] && - !ULONG_CMP_GE(rdp->nxtcompleted[i], c)) - break; + bool ret = false; - /* - * If there are no sublist for unassigned callbacks, leave. - * At the same time, advance "i" one sublist, so that "i" will - * index into the sublist where all the remaining callbacks should - * be grouped into. - */ - if (++i >= RCU_NEXT_TAIL) + /* If no pending (not yet ready to invoke) callbacks, nothing to do. */ + if (!rcu_segcblist_pend_cbs(&rdp->cblist)) return false; /* - * Assign all subsequent callbacks' ->completed number to the next - * full grace period and group them all in the sublist initially - * indexed by "i". + * Callbacks are often registered with incomplete grace-period + * information. Something about the fact that getting exact + * information requires acquiring a global lock... RCU therefore + * makes a conservative estimate of the grace period number at which + * a given callback will become ready to invoke. The following + * code checks this estimate and improves it when possible, thus + * accelerating callback invocation to an earlier grace-period + * number. */ - for (; i <= RCU_NEXT_TAIL; i++) { - rdp->nxttail[i] = rdp->nxttail[RCU_NEXT_TAIL]; - rdp->nxtcompleted[i] = c; - } - /* Record any needed additional grace periods. */ - ret = rcu_start_future_gp(rnp, rdp, NULL); + if (rcu_segcblist_accelerate(&rdp->cblist, rcu_cbs_completed(rsp, rnp))) + ret = rcu_start_future_gp(rnp, rdp, NULL); /* Trace depending on how much we were able to accelerate. */ - if (!*rdp->nxttail[RCU_WAIT_TAIL]) + if (rcu_segcblist_restempty(&rdp->cblist, RCU_WAIT_TAIL)) trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("AccWaitCB")); else trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("AccReadyCB")); @@ -1923,32 +1883,15 @@ static bool rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, static bool rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) { - int i, j; - - /* If the CPU has no callbacks, nothing to do. */ - if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL]) + /* If no pending (not yet ready to invoke) callbacks, nothing to do. */ + if (!rcu_segcblist_pend_cbs(&rdp->cblist)) return false; /* * Find all callbacks whose ->completed numbers indicate that they * are ready to invoke, and put them into the RCU_DONE_TAIL sublist. */ - for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) { - if (ULONG_CMP_LT(rnp->completed, rdp->nxtcompleted[i])) - break; - rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[i]; - } - /* Clean up any sublist tail pointers that were misordered above. */ - for (j = RCU_WAIT_TAIL; j < i; j++) - rdp->nxttail[j] = rdp->nxttail[RCU_DONE_TAIL]; - - /* Copy down callbacks to fill in empty sublists. */ - for (j = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++, j++) { - if (rdp->nxttail[j] == rdp->nxttail[RCU_NEXT_TAIL]) - break; - rdp->nxttail[j] = rdp->nxttail[i]; - rdp->nxtcompleted[j] = rdp->nxtcompleted[i]; - } + rcu_segcblist_advance(&rdp->cblist, rnp->completed); /* Classify any remaining callbacks. */ return rcu_accelerate_cbs(rsp, rnp, rdp); @@ -1993,7 +1936,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpustart")); need_gp = !!(rnp->qsmask & rdp->grpmask); rdp->cpu_no_qs.b.norm = need_gp; - rdp->rcu_qs_ctr_snap = __this_cpu_read(rcu_qs_ctr); + rdp->rcu_qs_ctr_snap = __this_cpu_read(rcu_dynticks.rcu_qs_ctr); rdp->core_needs_qs = need_gp; zero_cpu_stall_ticks(rdp); WRITE_ONCE(rdp->gpwrap, false); @@ -2591,7 +2534,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp) * within the current grace period. */ rdp->cpu_no_qs.b.norm = true; /* need qs for new gp. */ - rdp->rcu_qs_ctr_snap = __this_cpu_read(rcu_qs_ctr); + rdp->rcu_qs_ctr_snap = __this_cpu_read(rcu_dynticks.rcu_qs_ctr); raw_spin_unlock_irqrestore_rcu_node(rnp, flags); return; } @@ -2665,13 +2608,8 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp, * because _rcu_barrier() excludes CPU-hotplug operations, so it * cannot be running now. Thus no memory barrier is required. */ - if (rdp->nxtlist != NULL) { - rsp->qlen_lazy += rdp->qlen_lazy; - rsp->qlen += rdp->qlen; - rdp->n_cbs_orphaned += rdp->qlen; - rdp->qlen_lazy = 0; - WRITE_ONCE(rdp->qlen, 0); - } + rdp->n_cbs_orphaned += rcu_segcblist_n_cbs(&rdp->cblist); + rcu_segcblist_extract_count(&rdp->cblist, &rsp->orphan_done); /* * Next, move those callbacks still needing a grace period to @@ -2679,31 +2617,18 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp, * Some of the callbacks might have gone partway through a grace * period, but that is too bad. They get to start over because we * cannot assume that grace periods are synchronized across CPUs. - * We don't bother updating the ->nxttail[] array yet, instead - * we just reset the whole thing later on. */ - if (*rdp->nxttail[RCU_DONE_TAIL] != NULL) { - *rsp->orphan_nxttail = *rdp->nxttail[RCU_DONE_TAIL]; - rsp->orphan_nxttail = rdp->nxttail[RCU_NEXT_TAIL]; - *rdp->nxttail[RCU_DONE_TAIL] = NULL; - } + rcu_segcblist_extract_pend_cbs(&rdp->cblist, &rsp->orphan_pend); /* * Then move the ready-to-invoke callbacks to the orphanage, * where some other CPU will pick them up. These will not be * required to pass though another grace period: They are done. */ - if (rdp->nxtlist != NULL) { - *rsp->orphan_donetail = rdp->nxtlist; - rsp->orphan_donetail = rdp->nxttail[RCU_DONE_TAIL]; - } + rcu_segcblist_extract_done_cbs(&rdp->cblist, &rsp->orphan_done); - /* - * Finally, initialize the rcu_data structure's list to empty and - * disallow further callbacks on this CPU. - */ - init_callback_list(rdp); - rdp->nxttail[RCU_NEXT_TAIL] = NULL; + /* Finally, disallow further callbacks on this CPU. */ + rcu_segcblist_disable(&rdp->cblist); } /* @@ -2712,7 +2637,6 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp, */ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp, unsigned long flags) { - int i; struct rcu_data *rdp = raw_cpu_ptr(rsp->rda); /* No-CBs CPUs are handled specially. */ @@ -2721,13 +2645,10 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp, unsigned long flags) return; /* Do the accounting first. */ - rdp->qlen_lazy += rsp->qlen_lazy; - rdp->qlen += rsp->qlen; - rdp->n_cbs_adopted += rsp->qlen; - if (rsp->qlen_lazy != rsp->qlen) + rdp->n_cbs_adopted += rsp->orphan_done.len; + if (rsp->orphan_done.len_lazy != rsp->orphan_done.len) rcu_idle_count_callbacks_posted(); - rsp->qlen_lazy = 0; - rsp->qlen = 0; + rcu_segcblist_insert_count(&rdp->cblist, &rsp->orphan_done); /* * We do not need a memory barrier here because the only way we @@ -2735,24 +2656,13 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp, unsigned long flags) * we are the task doing the rcu_barrier(). */ - /* First adopt the ready-to-invoke callbacks. */ - if (rsp->orphan_donelist != NULL) { - *rsp->orphan_donetail = *rdp->nxttail[RCU_DONE_TAIL]; - *rdp->nxttail[RCU_DONE_TAIL] = rsp->orphan_donelist; - for (i = RCU_NEXT_SIZE - 1; i >= RCU_DONE_TAIL; i--) - if (rdp->nxttail[i] == rdp->nxttail[RCU_DONE_TAIL]) - rdp->nxttail[i] = rsp->orphan_donetail; - rsp->orphan_donelist = NULL; - rsp->orphan_donetail = &rsp->orphan_donelist; - } - - /* And then adopt the callbacks that still need a grace period. */ - if (rsp->orphan_nxtlist != NULL) { - *rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_nxtlist; - rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_nxttail; - rsp->orphan_nxtlist = NULL; - rsp->orphan_nxttail = &rsp->orphan_nxtlist; - } + /* First adopt the ready-to-invoke callbacks, then the done ones. */ + rcu_segcblist_insert_done_cbs(&rdp->cblist, &rsp->orphan_done); + WARN_ON_ONCE(rsp->orphan_done.head); + rcu_segcblist_insert_pend_cbs(&rdp->cblist, &rsp->orphan_pend); + WARN_ON_ONCE(rsp->orphan_pend.head); + WARN_ON_ONCE(rcu_segcblist_empty(&rdp->cblist) != + !rcu_segcblist_n_cbs(&rdp->cblist)); } /* @@ -2760,14 +2670,14 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp, unsigned long flags) */ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp) { - RCU_TRACE(unsigned long mask); - RCU_TRACE(struct rcu_data *rdp = this_cpu_ptr(rsp->rda)); - RCU_TRACE(struct rcu_node *rnp = rdp->mynode); + RCU_TRACE(unsigned long mask;) + RCU_TRACE(struct rcu_data *rdp = this_cpu_ptr(rsp->rda);) + RCU_TRACE(struct rcu_node *rnp = rdp->mynode;) if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) return; - RCU_TRACE(mask = rdp->grpmask); + RCU_TRACE(mask = rdp->grpmask;) trace_rcu_grace_period(rsp->name, rnp->gpnum + 1 - !!(rnp->qsmask & mask), TPS("cpuofl")); @@ -2840,9 +2750,11 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) rcu_adopt_orphan_cbs(rsp, flags); raw_spin_unlock_irqrestore(&rsp->orphan_lock, flags); - WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL, - "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n", - cpu, rdp->qlen, rdp->nxtlist); + WARN_ONCE(rcu_segcblist_n_cbs(&rdp->cblist) != 0 || + !rcu_segcblist_empty(&rdp->cblist), + "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, 1stCB=%p\n", + cpu, rcu_segcblist_n_cbs(&rdp->cblist), + rcu_segcblist_first_cb(&rdp->cblist)); } /* @@ -2852,14 +2764,17 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) { unsigned long flags; - struct rcu_head *next, *list, **tail; - long bl, count, count_lazy; - int i; + struct rcu_head *rhp; + struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl); + long bl, count; /* If no callbacks are ready, just return. */ - if (!cpu_has_callbacks_ready_to_invoke(rdp)) { - trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, 0); - trace_rcu_batch_end(rsp->name, 0, !!READ_ONCE(rdp->nxtlist), + if (!rcu_segcblist_ready_cbs(&rdp->cblist)) { + trace_rcu_batch_start(rsp->name, + rcu_segcblist_n_lazy_cbs(&rdp->cblist), + rcu_segcblist_n_cbs(&rdp->cblist), 0); + trace_rcu_batch_end(rsp->name, 0, + !rcu_segcblist_empty(&rdp->cblist), need_resched(), is_idle_task(current), rcu_is_callbacks_kthread()); return; @@ -2867,73 +2782,61 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) /* * Extract the list of ready callbacks, disabling to prevent - * races with call_rcu() from interrupt handlers. + * races with call_rcu() from interrupt handlers. Leave the + * callback counts, as rcu_barrier() needs to be conservative. */ local_irq_save(flags); WARN_ON_ONCE(cpu_is_offline(smp_processor_id())); bl = rdp->blimit; - trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, bl); - list = rdp->nxtlist; - rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL]; - *rdp->nxttail[RCU_DONE_TAIL] = NULL; - tail = rdp->nxttail[RCU_DONE_TAIL]; - for (i = RCU_NEXT_SIZE - 1; i >= 0; i--) - if (rdp->nxttail[i] == rdp->nxttail[RCU_DONE_TAIL]) - rdp->nxttail[i] = &rdp->nxtlist; + trace_rcu_batch_start(rsp->name, rcu_segcblist_n_lazy_cbs(&rdp->cblist), + rcu_segcblist_n_cbs(&rdp->cblist), bl); + rcu_segcblist_extract_done_cbs(&rdp->cblist, &rcl); local_irq_restore(flags); /* Invoke callbacks. */ - count = count_lazy = 0; - while (list) { - next = list->next; - prefetch(next); - debug_rcu_head_unqueue(list); - if (__rcu_reclaim(rsp->name, list)) - count_lazy++; - list = next; - /* Stop only if limit reached and CPU has something to do. */ - if (++count >= bl && + rhp = rcu_cblist_dequeue(&rcl); + for (; rhp; rhp = rcu_cblist_dequeue(&rcl)) { + debug_rcu_head_unqueue(rhp); + if (__rcu_reclaim(rsp->name, rhp)) + rcu_cblist_dequeued_lazy(&rcl); + /* + * Stop only if limit reached and CPU has something to do. + * Note: The rcl structure counts down from zero. + */ + if (-rcl.len >= bl && (need_resched() || (!is_idle_task(current) && !rcu_is_callbacks_kthread()))) break; } local_irq_save(flags); - trace_rcu_batch_end(rsp->name, count, !!list, need_resched(), - is_idle_task(current), - rcu_is_callbacks_kthread()); - - /* Update count, and requeue any remaining callbacks. */ - if (list != NULL) { - *tail = rdp->nxtlist; - rdp->nxtlist = list; - for (i = 0; i < RCU_NEXT_SIZE; i++) - if (&rdp->nxtlist == rdp->nxttail[i]) - rdp->nxttail[i] = tail; - else - break; - } + count = -rcl.len; + trace_rcu_batch_end(rsp->name, count, !!rcl.head, need_resched(), + is_idle_task(current), rcu_is_callbacks_kthread()); + + /* Update counts and requeue any remaining callbacks. */ + rcu_segcblist_insert_done_cbs(&rdp->cblist, &rcl); smp_mb(); /* List handling before counting for rcu_barrier(). */ - rdp->qlen_lazy -= count_lazy; - WRITE_ONCE(rdp->qlen, rdp->qlen - count); rdp->n_cbs_invoked += count; + rcu_segcblist_insert_count(&rdp->cblist, &rcl); /* Reinstate batch limit if we have worked down the excess. */ - if (rdp->blimit == LONG_MAX && rdp->qlen <= qlowmark) + count = rcu_segcblist_n_cbs(&rdp->cblist); + if (rdp->blimit == LONG_MAX && count <= qlowmark) rdp->blimit = blimit; /* Reset ->qlen_last_fqs_check trigger if enough CBs have drained. */ - if (rdp->qlen == 0 && rdp->qlen_last_fqs_check != 0) { + if (count == 0 && rdp->qlen_last_fqs_check != 0) { rdp->qlen_last_fqs_check = 0; rdp->n_force_qs_snap = rsp->n_force_qs; - } else if (rdp->qlen < rdp->qlen_last_fqs_check - qhimark) - rdp->qlen_last_fqs_check = rdp->qlen; - WARN_ON_ONCE((rdp->nxtlist == NULL) != (rdp->qlen == 0)); + } else if (count < rdp->qlen_last_fqs_check - qhimark) + rdp->qlen_last_fqs_check = count; + WARN_ON_ONCE(rcu_segcblist_empty(&rdp->cblist) != (count == 0)); local_irq_restore(flags); /* Re-invoke RCU core processing if there are callbacks remaining. */ - if (cpu_has_callbacks_ready_to_invoke(rdp)) + if (rcu_segcblist_ready_cbs(&rdp->cblist)) invoke_rcu_core(); } @@ -3099,7 +3002,7 @@ __rcu_process_callbacks(struct rcu_state *rsp) bool needwake; struct rcu_data *rdp = raw_cpu_ptr(rsp->rda); - WARN_ON_ONCE(rdp->beenonline == 0); + WARN_ON_ONCE(!rdp->beenonline); /* Update RCU state based on any recent quiescent states. */ rcu_check_quiescent_state(rsp, rdp); @@ -3117,7 +3020,7 @@ __rcu_process_callbacks(struct rcu_state *rsp) } /* If there are callbacks ready, invoke them. */ - if (cpu_has_callbacks_ready_to_invoke(rdp)) + if (rcu_segcblist_ready_cbs(&rdp->cblist)) invoke_rcu_callbacks(rsp, rdp); /* Do any needed deferred wakeups of rcuo kthreads. */ @@ -3189,7 +3092,8 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp, * invoking force_quiescent_state() if the newly enqueued callback * is the only one waiting for a grace period to complete. */ - if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) { + if (unlikely(rcu_segcblist_n_cbs(&rdp->cblist) > + rdp->qlen_last_fqs_check + qhimark)) { /* Are we ignoring a completed grace period? */ note_gp_changes(rsp, rdp); @@ -3207,10 +3111,10 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp, /* Give the grace period a kick. */ rdp->blimit = LONG_MAX; if (rsp->n_force_qs == rdp->n_force_qs_snap && - *rdp->nxttail[RCU_DONE_TAIL] != head) + rcu_segcblist_first_pend_cb(&rdp->cblist) != head) force_quiescent_state(rsp); rdp->n_force_qs_snap = rsp->n_force_qs; - rdp->qlen_last_fqs_check = rdp->qlen; + rdp->qlen_last_fqs_check = rcu_segcblist_n_cbs(&rdp->cblist); } } } @@ -3250,7 +3154,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func, rdp = this_cpu_ptr(rsp->rda); /* Add the callback to our list. */ - if (unlikely(rdp->nxttail[RCU_NEXT_TAIL] == NULL) || cpu != -1) { + if (unlikely(!rcu_segcblist_is_enabled(&rdp->cblist)) || cpu != -1) { int offline; if (cpu != -1) @@ -3269,23 +3173,21 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func, */ BUG_ON(cpu != -1); WARN_ON_ONCE(!rcu_is_watching()); - if (!likely(rdp->nxtlist)) - init_default_callback_list(rdp); + if (rcu_segcblist_empty(&rdp->cblist)) + rcu_segcblist_init(&rdp->cblist); } - WRITE_ONCE(rdp->qlen, rdp->qlen + 1); - if (lazy) - rdp->qlen_lazy++; - else + rcu_segcblist_enqueue(&rdp->cblist, head, lazy); + if (!lazy) rcu_idle_count_callbacks_posted(); - smp_mb(); /* Count before adding callback for rcu_barrier(). */ - *rdp->nxttail[RCU_NEXT_TAIL] = head; - rdp->nxttail[RCU_NEXT_TAIL] = &head->next; if (__is_kfree_rcu_offset((unsigned long)func)) trace_rcu_kfree_callback(rsp->name, head, (unsigned long)func, - rdp->qlen_lazy, rdp->qlen); + rcu_segcblist_n_lazy_cbs(&rdp->cblist), + rcu_segcblist_n_cbs(&rdp->cblist)); else - trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen); + trace_rcu_callback(rsp->name, head, + rcu_segcblist_n_lazy_cbs(&rdp->cblist), + rcu_segcblist_n_cbs(&rdp->cblist)); /* Go handle any RCU core processing required. */ __call_rcu_core(rsp, rdp, head, flags); @@ -3531,41 +3433,6 @@ void cond_synchronize_sched(unsigned long oldstate) } EXPORT_SYMBOL_GPL(cond_synchronize_sched); -/* Adjust sequence number for start of update-side operation. */ -static void rcu_seq_start(unsigned long *sp) -{ - WRITE_ONCE(*sp, *sp + 1); - smp_mb(); /* Ensure update-side operation after counter increment. */ - WARN_ON_ONCE(!(*sp & 0x1)); -} - -/* Adjust sequence number for end of update-side operation. */ -static void rcu_seq_end(unsigned long *sp) -{ - smp_mb(); /* Ensure update-side operation before counter increment. */ - WRITE_ONCE(*sp, *sp + 1); - WARN_ON_ONCE(*sp & 0x1); -} - -/* Take a snapshot of the update side's sequence number. */ -static unsigned long rcu_seq_snap(unsigned long *sp) -{ - unsigned long s; - - s = (READ_ONCE(*sp) + 3) & ~0x1; - smp_mb(); /* Above access must not bleed into critical section. */ - return s; -} - -/* - * Given a snapshot from rcu_seq_snap(), determine whether or not a - * full update-side operation has occurred. - */ -static bool rcu_seq_done(unsigned long *sp, unsigned long s) -{ - return ULONG_CMP_GE(READ_ONCE(*sp), s); -} - /* * Check to see if there is any immediate RCU-related work to be done * by the current CPU, for the specified type of RCU, returning 1 if so. @@ -3589,7 +3456,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) /* Is the RCU core waiting for a quiescent state from this CPU? */ if (rcu_scheduler_fully_active && rdp->core_needs_qs && rdp->cpu_no_qs.b.norm && - rdp->rcu_qs_ctr_snap == __this_cpu_read(rcu_qs_ctr)) { + rdp->rcu_qs_ctr_snap == __this_cpu_read(rcu_dynticks.rcu_qs_ctr)) { rdp->n_rp_core_needs_qs++; } else if (rdp->core_needs_qs && !rdp->cpu_no_qs.b.norm) { rdp->n_rp_report_qs++; @@ -3597,7 +3464,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) } /* Does this CPU have callbacks ready to invoke? */ - if (cpu_has_callbacks_ready_to_invoke(rdp)) { + if (rcu_segcblist_ready_cbs(&rdp->cblist)) { rdp->n_rp_cb_ready++; return 1; } @@ -3661,10 +3528,10 @@ static bool __maybe_unused rcu_cpu_has_callbacks(bool *all_lazy) for_each_rcu_flavor(rsp) { rdp = this_cpu_ptr(rsp->rda); - if (!rdp->nxtlist) + if (rcu_segcblist_empty(&rdp->cblist)) continue; hc = true; - if (rdp->qlen != rdp->qlen_lazy || !all_lazy) { + if (rcu_segcblist_n_nonlazy_cbs(&rdp->cblist) || !all_lazy) { al = false; break; } @@ -3773,7 +3640,7 @@ static void _rcu_barrier(struct rcu_state *rsp) __call_rcu(&rdp->barrier_head, rcu_barrier_callback, rsp, cpu, 0); } - } else if (READ_ONCE(rdp->qlen)) { + } else if (rcu_segcblist_n_cbs(&rdp->cblist)) { _rcu_barrier_trace(rsp, "OnlineQ", cpu, rsp->barrier_sequence); smp_call_function_single(cpu, rcu_barrier_func, rsp, 1); @@ -3882,8 +3749,9 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) rdp->qlen_last_fqs_check = 0; rdp->n_force_qs_snap = rsp->n_force_qs; rdp->blimit = blimit; - if (!rdp->nxtlist) - init_callback_list(rdp); /* Re-enable callbacks on this CPU. */ + if (rcu_segcblist_empty(&rdp->cblist) && /* No early-boot CBs? */ + !init_nocb_callback_list(rdp)) + rcu_segcblist_init(&rdp->cblist); /* Re-enable callbacks. */ rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; rcu_sysidle_init_percpu_data(rdp->dynticks); rcu_dynticks_eqs_online(); @@ -3902,12 +3770,16 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) rdp->gpnum = rnp->completed; /* Make CPU later note any new GP. */ rdp->completed = rnp->completed; rdp->cpu_no_qs.b.norm = true; - rdp->rcu_qs_ctr_snap = per_cpu(rcu_qs_ctr, cpu); + rdp->rcu_qs_ctr_snap = per_cpu(rcu_dynticks.rcu_qs_ctr, cpu); rdp->core_needs_qs = false; trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuonl")); raw_spin_unlock_irqrestore_rcu_node(rnp, flags); } +/* + * Invoked early in the CPU-online process, when pretty much all + * services are available. The incoming CPU is not present. + */ int rcutree_prepare_cpu(unsigned int cpu) { struct rcu_state *rsp; @@ -3921,6 +3793,9 @@ int rcutree_prepare_cpu(unsigned int cpu) return 0; } +/* + * Update RCU priority boot kthread affinity for CPU-hotplug changes. + */ static void rcutree_affinity_setting(unsigned int cpu, int outgoing) { struct rcu_data *rdp = per_cpu_ptr(rcu_state_p->rda, cpu); @@ -3928,20 +3803,34 @@ static void rcutree_affinity_setting(unsigned int cpu, int outgoing) rcu_boost_kthread_setaffinity(rdp->mynode, outgoing); } +/* + * Near the end of the CPU-online process. Pretty much all services + * enabled, and the CPU is now very much alive. + */ int rcutree_online_cpu(unsigned int cpu) { sync_sched_exp_online_cleanup(cpu); rcutree_affinity_setting(cpu, -1); + if (IS_ENABLED(CONFIG_TREE_SRCU)) + srcu_online_cpu(cpu); return 0; } +/* + * Near the beginning of the process. The CPU is still very much alive + * with pretty much all services enabled. + */ int rcutree_offline_cpu(unsigned int cpu) { rcutree_affinity_setting(cpu, cpu); + if (IS_ENABLED(CONFIG_TREE_SRCU)) + srcu_offline_cpu(cpu); return 0; } - +/* + * Near the end of the offline process. We do only tracing here. + */ int rcutree_dying_cpu(unsigned int cpu) { struct rcu_state *rsp; @@ -3951,6 +3840,9 @@ int rcutree_dying_cpu(unsigned int cpu) return 0; } +/* + * The outgoing CPU is gone and we are running elsewhere. + */ int rcutree_dead_cpu(unsigned int cpu) { struct rcu_state *rsp; @@ -3968,6 +3860,10 @@ int rcutree_dead_cpu(unsigned int cpu) * incoming CPUs are not allowed to use RCU read-side critical sections * until this function is called. Failing to observe this restriction * will result in lockdep splats. + * + * Note that this function is special in that it is invoked directly + * from the incoming CPU rather than from the cpuhp_step mechanism. + * This is because this function must be invoked at a precise location. */ void rcu_cpu_starting(unsigned int cpu) { @@ -3993,9 +3889,6 @@ void rcu_cpu_starting(unsigned int cpu) * The CPU is exiting the idle loop into the arch_cpu_idle_dead() * function. We now remove it from the rcu_node tree's ->qsmaskinit * bit masks. - * The CPU is exiting the idle loop into the arch_cpu_idle_dead() - * function. We now remove it from the rcu_node tree's ->qsmaskinit - * bit masks. */ static void rcu_cleanup_dying_idle_cpu(int cpu, struct rcu_state *rsp) { @@ -4011,6 +3904,14 @@ static void rcu_cleanup_dying_idle_cpu(int cpu, struct rcu_state *rsp) raw_spin_unlock_irqrestore_rcu_node(rnp, flags); } +/* + * The outgoing function has no further need of RCU, so remove it from + * the list of CPUs that RCU must track. + * + * Note that this function is special in that it is invoked directly + * from the outgoing CPU rather than from the cpuhp_step mechanism. + * This is because this function must be invoked at a precise location. + */ void rcu_report_dead(unsigned int cpu) { struct rcu_state *rsp; @@ -4025,6 +3926,10 @@ void rcu_report_dead(unsigned int cpu) } #endif +/* + * On non-huge systems, use expedited RCU grace periods to make suspend + * and hibernation run faster. + */ static int rcu_pm_notify(struct notifier_block *self, unsigned long action, void *hcpu) { @@ -4095,7 +4000,7 @@ early_initcall(rcu_spawn_gp_kthread); * task is booting the system, and such primitives are no-ops). After this * function is called, any synchronous grace-period primitives are run as * expedited, with the requesting task driving the grace period forward. - * A later core_initcall() rcu_exp_runtime_mode() will switch to full + * A later core_initcall() rcu_set_runtime_mode() will switch to full * runtime RCU functionality. */ void rcu_scheduler_starting(void) @@ -4108,31 +4013,6 @@ void rcu_scheduler_starting(void) } /* - * Compute the per-level fanout, either using the exact fanout specified - * or balancing the tree, depending on the rcu_fanout_exact boot parameter. - */ -static void __init rcu_init_levelspread(int *levelspread, const int *levelcnt) -{ - int i; - - if (rcu_fanout_exact) { - levelspread[rcu_num_lvls - 1] = rcu_fanout_leaf; - for (i = rcu_num_lvls - 2; i >= 0; i--) - levelspread[i] = RCU_FANOUT; - } else { - int ccur; - int cprv; - - cprv = nr_cpu_ids; - for (i = rcu_num_lvls - 1; i >= 0; i--) { - ccur = levelcnt[i]; - levelspread[i] = (cprv + ccur - 1) / ccur; - cprv = ccur; - } - } -} - -/* * Helper function for rcu_init() that initializes one rcu_state structure. */ static void __init rcu_init_one(struct rcu_state *rsp) @@ -4141,9 +4021,7 @@ static void __init rcu_init_one(struct rcu_state *rsp) static const char * const fqs[] = RCU_FQS_NAME_INIT; static struct lock_class_key rcu_node_class[RCU_NUM_LVLS]; static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS]; - static u8 fl_mask = 0x1; - int levelcnt[RCU_NUM_LVLS]; /* # nodes in each level. */ int levelspread[RCU_NUM_LVLS]; /* kids/node in each level. */ int cpustride = 1; int i; @@ -4158,20 +4036,16 @@ static void __init rcu_init_one(struct rcu_state *rsp) /* Initialize the level-tracking arrays. */ - for (i = 0; i < rcu_num_lvls; i++) - levelcnt[i] = num_rcu_lvl[i]; for (i = 1; i < rcu_num_lvls; i++) - rsp->level[i] = rsp->level[i - 1] + levelcnt[i - 1]; - rcu_init_levelspread(levelspread, levelcnt); - rsp->flavor_mask = fl_mask; - fl_mask <<= 1; + rsp->level[i] = rsp->level[i - 1] + num_rcu_lvl[i - 1]; + rcu_init_levelspread(levelspread, num_rcu_lvl); /* Initialize the elements themselves, starting from the leaves. */ for (i = rcu_num_lvls - 1; i >= 0; i--) { cpustride *= levelspread[i]; rnp = rsp->level[i]; - for (j = 0; j < levelcnt[i]; j++, rnp++) { + for (j = 0; j < num_rcu_lvl[i]; j++, rnp++) { raw_spin_lock_init(&ACCESS_PRIVATE(rnp, lock)); lockdep_set_class_and_name(&ACCESS_PRIVATE(rnp, lock), &rcu_node_class[i], buf[i]); @@ -4344,6 +4218,8 @@ void __init rcu_init(void) for_each_online_cpu(cpu) { rcutree_prepare_cpu(cpu); rcu_cpu_starting(cpu); + if (IS_ENABLED(CONFIG_TREE_SRCU)) + srcu_online_cpu(cpu); } } diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index ec62a05bfdb3..ba38262c3554 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -30,80 +30,9 @@ #include <linux/seqlock.h> #include <linux/swait.h> #include <linux/stop_machine.h> +#include <linux/rcu_node_tree.h> -/* - * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and - * CONFIG_RCU_FANOUT_LEAF. - * In theory, it should be possible to add more levels straightforwardly. - * In practice, this did work well going from three levels to four. - * Of course, your mileage may vary. - */ - -#ifdef CONFIG_RCU_FANOUT -#define RCU_FANOUT CONFIG_RCU_FANOUT -#else /* #ifdef CONFIG_RCU_FANOUT */ -# ifdef CONFIG_64BIT -# define RCU_FANOUT 64 -# else -# define RCU_FANOUT 32 -# endif -#endif /* #else #ifdef CONFIG_RCU_FANOUT */ - -#ifdef CONFIG_RCU_FANOUT_LEAF -#define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF -#else /* #ifdef CONFIG_RCU_FANOUT_LEAF */ -# ifdef CONFIG_64BIT -# define RCU_FANOUT_LEAF 64 -# else -# define RCU_FANOUT_LEAF 32 -# endif -#endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */ - -#define RCU_FANOUT_1 (RCU_FANOUT_LEAF) -#define RCU_FANOUT_2 (RCU_FANOUT_1 * RCU_FANOUT) -#define RCU_FANOUT_3 (RCU_FANOUT_2 * RCU_FANOUT) -#define RCU_FANOUT_4 (RCU_FANOUT_3 * RCU_FANOUT) - -#if NR_CPUS <= RCU_FANOUT_1 -# define RCU_NUM_LVLS 1 -# define NUM_RCU_LVL_0 1 -# define NUM_RCU_NODES NUM_RCU_LVL_0 -# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 } -# define RCU_NODE_NAME_INIT { "rcu_node_0" } -# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" } -#elif NR_CPUS <= RCU_FANOUT_2 -# define RCU_NUM_LVLS 2 -# define NUM_RCU_LVL_0 1 -# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) -# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1) -# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 } -# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" } -# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" } -#elif NR_CPUS <= RCU_FANOUT_3 -# define RCU_NUM_LVLS 3 -# define NUM_RCU_LVL_0 1 -# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) -# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) -# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2) -# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 } -# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" } -# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" } -#elif NR_CPUS <= RCU_FANOUT_4 -# define RCU_NUM_LVLS 4 -# define NUM_RCU_LVL_0 1 -# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3) -# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) -# define NUM_RCU_LVL_3 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) -# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) -# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 } -# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" } -# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" } -#else -# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" -#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */ - -extern int rcu_num_lvls; -extern int rcu_num_nodes; +#include "rcu_segcblist.h" /* * Dynticks per-CPU state. @@ -113,6 +42,9 @@ struct rcu_dynticks { /* Process level is worth LLONG_MAX/2. */ int dynticks_nmi_nesting; /* Track NMI nesting level. */ atomic_t dynticks; /* Even value for idle, else odd. */ + bool rcu_need_heavy_qs; /* GP old, need heavy quiescent state. */ + unsigned long rcu_qs_ctr; /* Light universal quiescent state ctr. */ + bool rcu_urgent_qs; /* GP old need light quiescent state. */ #ifdef CONFIG_NO_HZ_FULL_SYSIDLE long long dynticks_idle_nesting; /* irq/process nesting level from idle. */ @@ -262,41 +194,6 @@ struct rcu_node { #define leaf_node_cpu_bit(rnp, cpu) (1UL << ((cpu) - (rnp)->grplo)) /* - * Do a full breadth-first scan of the rcu_node structures for the - * specified rcu_state structure. - */ -#define rcu_for_each_node_breadth_first(rsp, rnp) \ - for ((rnp) = &(rsp)->node[0]; \ - (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++) - -/* - * Do a breadth-first scan of the non-leaf rcu_node structures for the - * specified rcu_state structure. Note that if there is a singleton - * rcu_node tree with but one rcu_node structure, this loop is a no-op. - */ -#define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \ - for ((rnp) = &(rsp)->node[0]; \ - (rnp) < (rsp)->level[rcu_num_lvls - 1]; (rnp)++) - -/* - * Scan the leaves of the rcu_node hierarchy for the specified rcu_state - * structure. Note that if there is a singleton rcu_node tree with but - * one rcu_node structure, this loop -will- visit the rcu_node structure. - * It is still a leaf node, even if it is also the root node. - */ -#define rcu_for_each_leaf_node(rsp, rnp) \ - for ((rnp) = (rsp)->level[rcu_num_lvls - 1]; \ - (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++) - -/* - * Iterate over all possible CPUs in a leaf RCU node. - */ -#define for_each_leaf_node_possible_cpu(rnp, cpu) \ - for ((cpu) = cpumask_next(rnp->grplo - 1, cpu_possible_mask); \ - cpu <= rnp->grphi; \ - cpu = cpumask_next((cpu), cpu_possible_mask)) - -/* * Union to allow "aggregate OR" operation on the need for a quiescent * state by the normal and expedited grace periods. */ @@ -336,34 +233,9 @@ struct rcu_data { /* period it is aware of. */ /* 2) batch handling */ - /* - * If nxtlist is not NULL, it is partitioned as follows. - * Any of the partitions might be empty, in which case the - * pointer to that partition will be equal to the pointer for - * the following partition. When the list is empty, all of - * the nxttail elements point to the ->nxtlist pointer itself, - * which in that case is NULL. - * - * [nxtlist, *nxttail[RCU_DONE_TAIL]): - * Entries that batch # <= ->completed - * The grace period for these entries has completed, and - * the other grace-period-completed entries may be moved - * here temporarily in rcu_process_callbacks(). - * [*nxttail[RCU_DONE_TAIL], *nxttail[RCU_WAIT_TAIL]): - * Entries that batch # <= ->completed - 1: waiting for current GP - * [*nxttail[RCU_WAIT_TAIL], *nxttail[RCU_NEXT_READY_TAIL]): - * Entries known to have arrived before current GP ended - * [*nxttail[RCU_NEXT_READY_TAIL], *nxttail[RCU_NEXT_TAIL]): - * Entries that might have arrived after current GP ended - * Note that the value of *nxttail[RCU_NEXT_TAIL] will - * always be NULL, as this is the end of the list. - */ - struct rcu_head *nxtlist; - struct rcu_head **nxttail[RCU_NEXT_SIZE]; - unsigned long nxtcompleted[RCU_NEXT_SIZE]; - /* grace periods for sublists. */ - long qlen_lazy; /* # of lazy queued callbacks */ - long qlen; /* # of queued callbacks, incl lazy */ + struct rcu_segcblist cblist; /* Segmented callback list, with */ + /* different callbacks waiting for */ + /* different grace periods. */ long qlen_last_fqs_check; /* qlen at last check for QS forcing */ unsigned long n_cbs_invoked; /* count of RCU cbs invoked. */ @@ -482,7 +354,6 @@ struct rcu_state { struct rcu_node *level[RCU_NUM_LVLS + 1]; /* Hierarchy levels (+1 to */ /* shut bogus gcc warning) */ - u8 flavor_mask; /* bit in flavor mask. */ struct rcu_data __percpu *rda; /* pointer of percu rcu_data. */ call_rcu_func_t call; /* call_rcu() flavor. */ int ncpus; /* # CPUs seen so far. */ @@ -502,14 +373,11 @@ struct rcu_state { raw_spinlock_t orphan_lock ____cacheline_internodealigned_in_smp; /* Protect following fields. */ - struct rcu_head *orphan_nxtlist; /* Orphaned callbacks that */ + struct rcu_cblist orphan_pend; /* Orphaned callbacks that */ /* need a grace period. */ - struct rcu_head **orphan_nxttail; /* Tail of above. */ - struct rcu_head *orphan_donelist; /* Orphaned callbacks that */ + struct rcu_cblist orphan_done; /* Orphaned callbacks that */ /* are ready to invoke. */ - struct rcu_head **orphan_donetail; /* Tail of above. */ - long qlen_lazy; /* Number of lazy callbacks. */ - long qlen; /* Total number of callbacks. */ + /* (Contains counts.) */ /* End of fields guarded by orphan_lock. */ struct mutex barrier_mutex; /* Guards barrier fields. */ @@ -596,6 +464,7 @@ extern struct rcu_state rcu_preempt_state; #endif /* #ifdef CONFIG_PREEMPT_RCU */ int rcu_dynticks_snap(struct rcu_dynticks *rdtp); +bool rcu_eqs_special_set(int cpu); #ifdef CONFIG_RCU_BOOST DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status); @@ -673,6 +542,14 @@ static bool rcu_nohz_full_cpu(struct rcu_state *rsp); static void rcu_dynticks_task_enter(void); static void rcu_dynticks_task_exit(void); +#ifdef CONFIG_SRCU +void srcu_online_cpu(unsigned int cpu); +void srcu_offline_cpu(unsigned int cpu); +#else /* #ifdef CONFIG_SRCU */ +void srcu_online_cpu(unsigned int cpu) { } +void srcu_offline_cpu(unsigned int cpu) { } +#endif /* #else #ifdef CONFIG_SRCU */ + #endif /* #ifndef RCU_TREE_NONCORE */ #ifdef CONFIG_RCU_TRACE diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h index a7b639ccd46e..e513b4ab1197 100644 --- a/kernel/rcu/tree_exp.h +++ b/kernel/rcu/tree_exp.h @@ -292,7 +292,7 @@ static bool exp_funnel_lock(struct rcu_state *rsp, unsigned long s) trace_rcu_exp_funnel_lock(rsp->name, rnp->level, rnp->grplo, rnp->grphi, TPS("wait")); - wait_event(rnp->exp_wq[(s >> 1) & 0x3], + wait_event(rnp->exp_wq[rcu_seq_ctr(s) & 0x3], sync_exp_work_done(rsp, &rdp->exp_workdone2, s)); return true; @@ -331,6 +331,8 @@ static void sync_sched_exp_handler(void *data) return; } __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, true); + /* Store .exp before .rcu_urgent_qs. */ + smp_store_release(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs), true); resched_cpu(smp_processor_id()); } @@ -531,7 +533,8 @@ static void rcu_exp_wait_wake(struct rcu_state *rsp, unsigned long s) rnp->exp_seq_rq = s; spin_unlock(&rnp->exp_lock); } - wake_up_all(&rnp->exp_wq[(rsp->expedited_sequence >> 1) & 0x3]); + smp_mb(); /* All above changes before wakeup. */ + wake_up_all(&rnp->exp_wq[rcu_seq_ctr(rsp->expedited_sequence) & 0x3]); } trace_rcu_exp_grace_period(rsp->name, s, TPS("endwake")); mutex_unlock(&rsp->exp_wake_mutex); @@ -609,9 +612,9 @@ static void _synchronize_rcu_expedited(struct rcu_state *rsp, /* Wait for expedited grace period to complete. */ rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id()); rnp = rcu_get_root(rsp); - wait_event(rnp->exp_wq[(s >> 1) & 0x3], - sync_exp_work_done(rsp, - &rdp->exp_workdone0, s)); + wait_event(rnp->exp_wq[rcu_seq_ctr(s) & 0x3], + sync_exp_work_done(rsp, &rdp->exp_workdone0, s)); + smp_mb(); /* Workqueue actions happen before return. */ /* Let the next expedited grace period start. */ mutex_unlock(&rsp->exp_mutex); @@ -735,15 +738,3 @@ void synchronize_rcu_expedited(void) EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); #endif /* #else #ifdef CONFIG_PREEMPT_RCU */ - -/* - * Switch to run-time mode once Tree RCU has fully initialized. - */ -static int __init rcu_exp_runtime_mode(void) -{ - rcu_test_sync_prims(); - rcu_scheduler_active = RCU_SCHEDULER_RUNNING; - rcu_test_sync_prims(); - return 0; -} -core_initcall(rcu_exp_runtime_mode); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 0a62a8f1caac..c9a48657512a 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1350,10 +1350,10 @@ static bool __maybe_unused rcu_try_advance_all_cbs(void) */ if ((rdp->completed != rnp->completed || unlikely(READ_ONCE(rdp->gpwrap))) && - rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_NEXT_TAIL]) + rcu_segcblist_pend_cbs(&rdp->cblist)) note_gp_changes(rsp, rdp); - if (cpu_has_callbacks_ready_to_invoke(rdp)) + if (rcu_segcblist_ready_cbs(&rdp->cblist)) cbs_ready = true; } return cbs_ready; @@ -1461,7 +1461,7 @@ static void rcu_prepare_for_idle(void) rdtp->last_accelerate = jiffies; for_each_rcu_flavor(rsp) { rdp = this_cpu_ptr(rsp->rda); - if (!*rdp->nxttail[RCU_DONE_TAIL]) + if (rcu_segcblist_pend_cbs(&rdp->cblist)) continue; rnp = rdp->mynode; raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */ @@ -1529,7 +1529,7 @@ static void rcu_oom_notify_cpu(void *unused) for_each_rcu_flavor(rsp) { rdp = raw_cpu_ptr(rsp->rda); - if (rdp->qlen_lazy != 0) { + if (rcu_segcblist_n_lazy_cbs(&rdp->cblist)) { atomic_inc(&oom_callback_count); rsp->call(&rdp->oom_head, rcu_oom_callback); } @@ -1709,7 +1709,7 @@ __setup("rcu_nocbs=", rcu_nocb_setup); static int __init parse_rcu_nocb_poll(char *arg) { - rcu_nocb_poll = 1; + rcu_nocb_poll = true; return 0; } early_param("rcu_nocb_poll", parse_rcu_nocb_poll); @@ -1860,7 +1860,9 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeEmpty")); } else { - rdp->nocb_defer_wakeup = RCU_NOGP_WAKE; + WRITE_ONCE(rdp->nocb_defer_wakeup, RCU_NOGP_WAKE); + /* Store ->nocb_defer_wakeup before ->rcu_urgent_qs. */ + smp_store_release(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs), true); trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeEmptyIsDeferred")); } @@ -1872,7 +1874,9 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeOvf")); } else { - rdp->nocb_defer_wakeup = RCU_NOGP_WAKE_FORCE; + WRITE_ONCE(rdp->nocb_defer_wakeup, RCU_NOGP_WAKE_FORCE); + /* Store ->nocb_defer_wakeup before ->rcu_urgent_qs. */ + smp_store_release(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs), true); trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeOvfIsDeferred")); } @@ -1930,30 +1934,26 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, struct rcu_data *rdp, unsigned long flags) { - long ql = rsp->qlen; - long qll = rsp->qlen_lazy; + long ql = rsp->orphan_done.len; + long qll = rsp->orphan_done.len_lazy; /* If this is not a no-CBs CPU, tell the caller to do it the old way. */ if (!rcu_is_nocb_cpu(smp_processor_id())) return false; - rsp->qlen = 0; - rsp->qlen_lazy = 0; /* First, enqueue the donelist, if any. This preserves CB ordering. */ - if (rsp->orphan_donelist != NULL) { - __call_rcu_nocb_enqueue(rdp, rsp->orphan_donelist, - rsp->orphan_donetail, ql, qll, flags); - ql = qll = 0; - rsp->orphan_donelist = NULL; - rsp->orphan_donetail = &rsp->orphan_donelist; + if (rsp->orphan_done.head) { + __call_rcu_nocb_enqueue(rdp, rcu_cblist_head(&rsp->orphan_done), + rcu_cblist_tail(&rsp->orphan_done), + ql, qll, flags); } - if (rsp->orphan_nxtlist != NULL) { - __call_rcu_nocb_enqueue(rdp, rsp->orphan_nxtlist, - rsp->orphan_nxttail, ql, qll, flags); - ql = qll = 0; - rsp->orphan_nxtlist = NULL; - rsp->orphan_nxttail = &rsp->orphan_nxtlist; + if (rsp->orphan_pend.head) { + __call_rcu_nocb_enqueue(rdp, rcu_cblist_head(&rsp->orphan_pend), + rcu_cblist_tail(&rsp->orphan_pend), + ql, qll, flags); } + rcu_cblist_init(&rsp->orphan_done); + rcu_cblist_init(&rsp->orphan_pend); return true; } @@ -2395,16 +2395,16 @@ static bool init_nocb_callback_list(struct rcu_data *rdp) return false; /* If there are early-boot callbacks, move them to nocb lists. */ - if (rdp->nxtlist) { - rdp->nocb_head = rdp->nxtlist; - rdp->nocb_tail = rdp->nxttail[RCU_NEXT_TAIL]; - atomic_long_set(&rdp->nocb_q_count, rdp->qlen); - atomic_long_set(&rdp->nocb_q_count_lazy, rdp->qlen_lazy); - rdp->nxtlist = NULL; - rdp->qlen = 0; - rdp->qlen_lazy = 0; + if (!rcu_segcblist_empty(&rdp->cblist)) { + rdp->nocb_head = rcu_segcblist_head(&rdp->cblist); + rdp->nocb_tail = rcu_segcblist_tail(&rdp->cblist); + atomic_long_set(&rdp->nocb_q_count, + rcu_segcblist_n_cbs(&rdp->cblist)); + atomic_long_set(&rdp->nocb_q_count_lazy, + rcu_segcblist_n_lazy_cbs(&rdp->cblist)); + rcu_segcblist_init(&rdp->cblist); } - rdp->nxttail[RCU_NEXT_TAIL] = NULL; + rcu_segcblist_disable(&rdp->cblist); return true; } diff --git a/kernel/rcu/tree_trace.c b/kernel/rcu/tree_trace.c index 8751a748499a..6cea17a1ea30 100644 --- a/kernel/rcu/tree_trace.c +++ b/kernel/rcu/tree_trace.c @@ -41,11 +41,11 @@ #include <linux/mutex.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/prefetch.h> #define RCU_TREE_NONCORE #include "tree.h" - -DECLARE_PER_CPU_SHARED_ALIGNED(unsigned long, rcu_qs_ctr); +#include "rcu.h" static int r_open(struct inode *inode, struct file *file, const struct seq_operations *op) @@ -121,7 +121,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) cpu_is_offline(rdp->cpu) ? '!' : ' ', ulong2long(rdp->completed), ulong2long(rdp->gpnum), rdp->cpu_no_qs.b.norm, - rdp->rcu_qs_ctr_snap == per_cpu(rcu_qs_ctr, rdp->cpu), + rdp->rcu_qs_ctr_snap == per_cpu(rdp->dynticks->rcu_qs_ctr, rdp->cpu), rdp->core_needs_qs); seq_printf(m, " dt=%d/%llx/%d df=%lu", rcu_dynticks_snap(rdp->dynticks), @@ -130,17 +130,15 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->dynticks_fqs); seq_printf(m, " of=%lu", rdp->offline_fqs); rcu_nocb_q_lengths(rdp, &ql, &qll); - qll += rdp->qlen_lazy; - ql += rdp->qlen; + qll += rcu_segcblist_n_lazy_cbs(&rdp->cblist); + ql += rcu_segcblist_n_cbs(&rdp->cblist); seq_printf(m, " ql=%ld/%ld qs=%c%c%c%c", qll, ql, - ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != - rdp->nxttail[RCU_NEXT_TAIL]], - ".R"[rdp->nxttail[RCU_WAIT_TAIL] != - rdp->nxttail[RCU_NEXT_READY_TAIL]], - ".W"[rdp->nxttail[RCU_DONE_TAIL] != - rdp->nxttail[RCU_WAIT_TAIL]], - ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]]); + ".N"[!rcu_segcblist_segempty(&rdp->cblist, RCU_NEXT_TAIL)], + ".R"[!rcu_segcblist_segempty(&rdp->cblist, + RCU_NEXT_READY_TAIL)], + ".W"[!rcu_segcblist_segempty(&rdp->cblist, RCU_WAIT_TAIL)], + ".D"[!rcu_segcblist_segempty(&rdp->cblist, RCU_DONE_TAIL)]); #ifdef CONFIG_RCU_BOOST seq_printf(m, " kt=%d/%c ktl=%x", per_cpu(rcu_cpu_has_work, rdp->cpu), @@ -278,7 +276,9 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) seq_printf(m, "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n", rsp->n_force_qs, rsp->n_force_qs_ngp, rsp->n_force_qs - rsp->n_force_qs_ngp, - READ_ONCE(rsp->n_force_qs_lh), rsp->qlen_lazy, rsp->qlen); + READ_ONCE(rsp->n_force_qs_lh), + rsp->orphan_done.len_lazy, + rsp->orphan_done.len); for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < rcu_num_nodes; rnp++) { if (rnp->level != level) { seq_puts(m, "\n"); diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 55c8530316c7..273e869ca21d 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL(rcu_read_lock_sched_held); * non-expedited counterparts? Intended for use within RCU. Note * that if the user specifies both rcu_expedited and rcu_normal, then * rcu_normal wins. (Except during the time period during boot from - * when the first task is spawned until the rcu_exp_runtime_mode() + * when the first task is spawned until the rcu_set_runtime_mode() * core_initcall() is invoked, at which point everything is expedited.) */ bool rcu_gp_is_normal(void) @@ -190,6 +190,39 @@ void rcu_end_inkernel_boot(void) #endif /* #ifndef CONFIG_TINY_RCU */ +/* + * Test each non-SRCU synchronous grace-period wait API. This is + * useful just after a change in mode for these primitives, and + * during early boot. + */ +void rcu_test_sync_prims(void) +{ + if (!IS_ENABLED(CONFIG_PROVE_RCU)) + return; + synchronize_rcu(); + synchronize_rcu_bh(); + synchronize_sched(); + synchronize_rcu_expedited(); + synchronize_rcu_bh_expedited(); + synchronize_sched_expedited(); +} + +#if !defined(CONFIG_TINY_RCU) || defined(CONFIG_SRCU) + +/* + * Switch to run-time mode once RCU has fully initialized. + */ +static int __init rcu_set_runtime_mode(void) +{ + rcu_test_sync_prims(); + rcu_scheduler_active = RCU_SCHEDULER_RUNNING; + rcu_test_sync_prims(); + return 0; +} +core_initcall(rcu_set_runtime_mode); + +#endif /* #if !defined(CONFIG_TINY_RCU) || defined(CONFIG_SRCU) */ + #ifdef CONFIG_PREEMPT_RCU /* @@ -632,6 +665,7 @@ static void check_holdout_task(struct task_struct *t, put_task_struct(t); return; } + rcu_request_urgent_qs_task(t); if (!needreport) return; if (*firstreport) { @@ -817,23 +851,6 @@ static void rcu_spawn_tasks_kthread(void) #endif /* #ifdef CONFIG_TASKS_RCU */ -/* - * Test each non-SRCU synchronous grace-period wait API. This is - * useful just after a change in mode for these primitives, and - * during early boot. - */ -void rcu_test_sync_prims(void) -{ - if (!IS_ENABLED(CONFIG_PROVE_RCU)) - return; - synchronize_rcu(); - synchronize_rcu_bh(); - synchronize_sched(); - synchronize_rcu_expedited(); - synchronize_rcu_bh_expedited(); - synchronize_sched_expedited(); -} - #ifdef CONFIG_PROVE_RCU /* diff --git a/kernel/sched/core.c b/kernel/sched/core.c index c51147a1204c..759f4bd52cd6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3382,7 +3382,7 @@ static void __sched notrace __schedule(bool preempt) hrtick_clear(rq); local_irq_disable(); - rcu_note_context_switch(); + rcu_note_context_switch(preempt); /* * Make sure that signal_pending_state()->signal_pending() below diff --git a/kernel/signal.c b/kernel/signal.c index a8c54f384553..ca92bcfeb322 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1237,7 +1237,7 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, } /* * This sighand can be already freed and even reused, but - * we rely on SLAB_DESTROY_BY_RCU and sighand_ctor() which + * we rely on SLAB_TYPESAFE_BY_RCU and sighand_ctor() which * initializes ->siglock: this slab can't go away, it has * the same object type, ->siglock can't be reinitialized. * diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 4ad4420b33d6..c4536c449021 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3311,13 +3311,14 @@ static void test_cpu_buff_start(struct trace_iterator *iter) if (!(iter->iter_flags & TRACE_FILE_ANNOTATE)) return; - if (iter->started && cpumask_test_cpu(iter->cpu, iter->started)) + if (cpumask_available(iter->started) && + cpumask_test_cpu(iter->cpu, iter->started)) return; if (per_cpu_ptr(iter->trace_buffer->data, iter->cpu)->skipped_entries) return; - if (iter->started) + if (cpumask_available(iter->started)) cpumask_set_cpu(iter->cpu, iter->started); /* Don't print started cpu buffer for the first entry of the trace */ diff --git a/lib/dma-debug.c b/lib/dma-debug.c index fe4d50c992df..ea4cc3dde4f1 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -1498,7 +1498,7 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size, entry->type = dma_debug_coherent; entry->dev = dev; entry->pfn = page_to_pfn(virt_to_page(virt)); - entry->offset = (size_t) virt & ~PAGE_MASK; + entry->offset = offset_in_page(virt); entry->size = size; entry->dev_addr = dma_addr; entry->direction = DMA_BIDIRECTIONAL; @@ -1514,7 +1514,7 @@ void debug_dma_free_coherent(struct device *dev, size_t size, .type = dma_debug_coherent, .dev = dev, .pfn = page_to_pfn(virt_to_page(virt)), - .offset = (size_t) virt & ~PAGE_MASK, + .offset = offset_in_page(virt), .dev_addr = addr, .size = size, .direction = DMA_BIDIRECTIONAL, diff --git a/lib/iov_iter.c b/lib/iov_iter.c index ae82d9cea553..f835964c9485 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -790,6 +790,8 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll) { if (!unroll) return; + if (WARN_ON(unroll > MAX_RW_COUNT)) + return; i->count += unroll; if (unlikely(i->type & ITER_PIPE)) { struct pipe_inode_info *pipe = i->pipe; diff --git a/mm/filemap.c b/mm/filemap.c index b7b973b47d8d..6f1be573a5e6 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2050,7 +2050,7 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) iocb->ki_pos += retval; count -= retval; } - iov_iter_revert(iter, iov_iter_count(iter) - count); + iov_iter_revert(iter, count - iov_iter_count(iter)); /* * Btrfs can have a short DIO read if we encounter diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index b10da59cf765..c81549d5c833 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c @@ -413,7 +413,7 @@ void kasan_cache_create(struct kmem_cache *cache, size_t *size, *size += sizeof(struct kasan_alloc_meta); /* Add free meta. */ - if (cache->flags & SLAB_DESTROY_BY_RCU || cache->ctor || + if (cache->flags & SLAB_TYPESAFE_BY_RCU || cache->ctor || cache->object_size < sizeof(struct kasan_free_meta)) { cache->kasan_info.free_meta_offset = *size; *size += sizeof(struct kasan_free_meta); @@ -561,7 +561,7 @@ static void kasan_poison_slab_free(struct kmem_cache *cache, void *object) unsigned long rounded_up_size = round_up(size, KASAN_SHADOW_SCALE_SIZE); /* RCU slabs could be legally used after free within the RCU period */ - if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU)) + if (unlikely(cache->flags & SLAB_TYPESAFE_BY_RCU)) return; kasan_poison_shadow(object, rounded_up_size, KASAN_KMALLOC_FREE); @@ -572,7 +572,7 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object) s8 shadow_byte; /* RCU slabs could be legally used after free within the RCU period */ - if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU)) + if (unlikely(cache->flags & SLAB_TYPESAFE_BY_RCU)) return false; shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object)); diff --git a/mm/kmemcheck.c b/mm/kmemcheck.c index 5bf191756a4a..2d5959c5f7c5 100644 --- a/mm/kmemcheck.c +++ b/mm/kmemcheck.c @@ -95,7 +95,7 @@ void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object, void kmemcheck_slab_free(struct kmem_cache *s, void *object, size_t size) { /* TODO: RCU freeing is unsupported for now; hide false positives. */ - if (!s->ctor && !(s->flags & SLAB_DESTROY_BY_RCU)) + if (!s->ctor && !(s->flags & SLAB_TYPESAFE_BY_RCU)) kmemcheck_mark_freed(object, size); } diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index a7652acd2ab9..54ca54562928 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -21,7 +21,7 @@ #include <linux/slab.h> /* global SRCU for all MMs */ -static struct srcu_struct srcu; +DEFINE_STATIC_SRCU(srcu); /* * This function allows mmu_notifier::release callback to delay a call to @@ -252,12 +252,6 @@ static int do_mmu_notifier_register(struct mmu_notifier *mn, BUG_ON(atomic_read(&mm->mm_users) <= 0); - /* - * Verify that mmu_notifier_init() already run and the global srcu is - * initialized. - */ - BUG_ON(!srcu.per_cpu_ref); - ret = -ENOMEM; mmu_notifier_mm = kmalloc(sizeof(struct mmu_notifier_mm), GFP_KERNEL); if (unlikely(!mmu_notifier_mm)) @@ -406,9 +400,3 @@ void mmu_notifier_unregister_no_release(struct mmu_notifier *mn, mmdrop(mm); } EXPORT_SYMBOL_GPL(mmu_notifier_unregister_no_release); - -static int __init mmu_notifier_init(void) -{ - return init_srcu_struct(&srcu); -} -subsys_initcall(mmu_notifier_init); diff --git a/mm/rmap.c b/mm/rmap.c index 3ff241f714eb..d405f0e0ee96 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -430,7 +430,7 @@ static void anon_vma_ctor(void *data) void __init anon_vma_init(void) { anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma), - 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC|SLAB_ACCOUNT, + 0, SLAB_TYPESAFE_BY_RCU|SLAB_PANIC|SLAB_ACCOUNT, anon_vma_ctor); anon_vma_chain_cachep = KMEM_CACHE(anon_vma_chain, SLAB_PANIC|SLAB_ACCOUNT); @@ -481,7 +481,7 @@ struct anon_vma *page_get_anon_vma(struct page *page) * If this page is still mapped, then its anon_vma cannot have been * freed. But if it has been unmapped, we have no security against the * anon_vma structure being freed and reused (for another anon_vma: - * SLAB_DESTROY_BY_RCU guarantees that - so the atomic_inc_not_zero() + * SLAB_TYPESAFE_BY_RCU guarantees that - so the atomic_inc_not_zero() * above cannot corrupt). */ if (!page_mapped(page)) { diff --git a/mm/slab.c b/mm/slab.c index 1880d482a0cb..2a31ee3c5814 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1728,7 +1728,7 @@ static void slab_destroy(struct kmem_cache *cachep, struct page *page) freelist = page->freelist; slab_destroy_debugcheck(cachep, page); - if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) + if (unlikely(cachep->flags & SLAB_TYPESAFE_BY_RCU)) call_rcu(&page->rcu_head, kmem_rcu_free); else kmem_freepages(cachep, page); @@ -1924,7 +1924,7 @@ static bool set_objfreelist_slab_cache(struct kmem_cache *cachep, cachep->num = 0; - if (cachep->ctor || flags & SLAB_DESTROY_BY_RCU) + if (cachep->ctor || flags & SLAB_TYPESAFE_BY_RCU) return false; left = calculate_slab_order(cachep, size, @@ -2030,7 +2030,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) if (size < 4096 || fls(size - 1) == fls(size-1 + REDZONE_ALIGN + 2 * sizeof(unsigned long long))) flags |= SLAB_RED_ZONE | SLAB_STORE_USER; - if (!(flags & SLAB_DESTROY_BY_RCU)) + if (!(flags & SLAB_TYPESAFE_BY_RCU)) flags |= SLAB_POISON; #endif #endif diff --git a/mm/slab.h b/mm/slab.h index 65e7c3fcac72..9cfcf099709c 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -126,7 +126,7 @@ static inline unsigned long kmem_cache_flags(unsigned long object_size, /* Legal flag mask for kmem_cache_create(), for various configurations */ #define SLAB_CORE_FLAGS (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA | SLAB_PANIC | \ - SLAB_DESTROY_BY_RCU | SLAB_DEBUG_OBJECTS ) + SLAB_TYPESAFE_BY_RCU | SLAB_DEBUG_OBJECTS ) #if defined(CONFIG_DEBUG_SLAB) #define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER) @@ -415,7 +415,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s) * back there or track user information then we can * only use the space before that information. */ - if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) + if (s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER)) return s->inuse; /* * Else we can use all the padding etc for the allocation diff --git a/mm/slab_common.c b/mm/slab_common.c index 09d0e849b07f..01a0fe2eb332 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -39,7 +39,7 @@ static DECLARE_WORK(slab_caches_to_rcu_destroy_work, * Set of flags that will prevent slab merging */ #define SLAB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ - SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \ + SLAB_TRACE | SLAB_TYPESAFE_BY_RCU | SLAB_NOLEAKTRACE | \ SLAB_FAILSLAB | SLAB_KASAN) #define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | \ @@ -500,7 +500,7 @@ static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work) struct kmem_cache *s, *s2; /* - * On destruction, SLAB_DESTROY_BY_RCU kmem_caches are put on the + * On destruction, SLAB_TYPESAFE_BY_RCU kmem_caches are put on the * @slab_caches_to_rcu_destroy list. The slab pages are freed * through RCU and and the associated kmem_cache are dereferenced * while freeing the pages, so the kmem_caches should be freed only @@ -537,7 +537,7 @@ static int shutdown_cache(struct kmem_cache *s) memcg_unlink_cache(s); list_del(&s->list); - if (s->flags & SLAB_DESTROY_BY_RCU) { + if (s->flags & SLAB_TYPESAFE_BY_RCU) { list_add_tail(&s->list, &slab_caches_to_rcu_destroy); schedule_work(&slab_caches_to_rcu_destroy_work); } else { diff --git a/mm/slob.c b/mm/slob.c index eac04d4357ec..1bae78d71096 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -126,7 +126,7 @@ static inline void clear_slob_page_free(struct page *sp) /* * struct slob_rcu is inserted at the tail of allocated slob blocks, which - * were created with a SLAB_DESTROY_BY_RCU slab. slob_rcu is used to free + * were created with a SLAB_TYPESAFE_BY_RCU slab. slob_rcu is used to free * the block using call_rcu. */ struct slob_rcu { @@ -524,7 +524,7 @@ EXPORT_SYMBOL(ksize); int __kmem_cache_create(struct kmem_cache *c, unsigned long flags) { - if (flags & SLAB_DESTROY_BY_RCU) { + if (flags & SLAB_TYPESAFE_BY_RCU) { /* leave room for rcu footer at the end of object */ c->size += sizeof(struct slob_rcu); } @@ -598,7 +598,7 @@ static void kmem_rcu_free(struct rcu_head *head) void kmem_cache_free(struct kmem_cache *c, void *b) { kmemleak_free_recursive(b, c->flags); - if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) { + if (unlikely(c->flags & SLAB_TYPESAFE_BY_RCU)) { struct slob_rcu *slob_rcu; slob_rcu = b + (c->size - sizeof(struct slob_rcu)); slob_rcu->size = c->size; diff --git a/mm/slub.c b/mm/slub.c index 7f4bc7027ed5..57e5156f02be 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1687,7 +1687,7 @@ static void rcu_free_slab(struct rcu_head *h) static void free_slab(struct kmem_cache *s, struct page *page) { - if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) { + if (unlikely(s->flags & SLAB_TYPESAFE_BY_RCU)) { struct rcu_head *head; if (need_reserve_slab_rcu) { @@ -2963,7 +2963,7 @@ static __always_inline void slab_free(struct kmem_cache *s, struct page *page, * slab_free_freelist_hook() could have put the items into quarantine. * If so, no need to free them. */ - if (s->flags & SLAB_KASAN && !(s->flags & SLAB_DESTROY_BY_RCU)) + if (s->flags & SLAB_KASAN && !(s->flags & SLAB_TYPESAFE_BY_RCU)) return; do_slab_free(s, page, head, tail, cnt, addr); } @@ -3433,7 +3433,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) * the slab may touch the object after free or before allocation * then we should never poison the object itself. */ - if ((flags & SLAB_POISON) && !(flags & SLAB_DESTROY_BY_RCU) && + if ((flags & SLAB_POISON) && !(flags & SLAB_TYPESAFE_BY_RCU) && !s->ctor) s->flags |= __OBJECT_POISON; else @@ -3455,7 +3455,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) */ s->inuse = size; - if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) || + if (((flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) || s->ctor)) { /* * Relocate free pointer after the object if it is not @@ -3537,7 +3537,7 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags) s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor); s->reserved = 0; - if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU)) + if (need_reserve_slab_rcu && (s->flags & SLAB_TYPESAFE_BY_RCU)) s->reserved = sizeof(struct rcu_head); if (!calculate_sizes(s, -1)) @@ -5042,7 +5042,7 @@ SLAB_ATTR_RO(cache_dma); static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf) { - return sprintf(buf, "%d\n", !!(s->flags & SLAB_DESTROY_BY_RCU)); + return sprintf(buf, "%d\n", !!(s->flags & SLAB_TYPESAFE_BY_RCU)); } SLAB_ATTR_RO(destroy_by_rcu); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 9ee5787634e5..953b6728bd00 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -626,11 +626,18 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev, { struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; netdev_features_t old_features = features; + netdev_features_t lower_features; - features = netdev_intersect_features(features, real_dev->vlan_features); - features |= NETIF_F_RXCSUM; - features = netdev_intersect_features(features, real_dev->features); + lower_features = netdev_intersect_features((real_dev->vlan_features | + NETIF_F_RXCSUM), + real_dev->features); + /* Add HW_CSUM setting to preserve user ability to control + * checksum offload on the vlan device. + */ + if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) + lower_features |= NETIF_F_HW_CSUM; + features = netdev_intersect_features(features, lower_features); features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE); features |= NETIF_F_LLTX; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index a572db710d4e..c5ce7745b230 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -133,6 +133,8 @@ static inline size_t br_port_info_size(void) + nla_total_size(1) /* IFLA_BRPORT_MCAST_TO_UCAST */ + nla_total_size(1) /* IFLA_BRPORT_LEARNING */ + nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */ + + nla_total_size(1) /* IFLA_BRPORT_MCAST_FLOOD */ + + nla_total_size(1) /* IFLA_BRPORT_BCAST_FLOOD */ + nla_total_size(1) /* IFLA_BRPORT_PROXYARP */ + nla_total_size(1) /* IFLA_BRPORT_PROXYARP_WIFI */ + nla_total_size(1) /* IFLA_BRPORT_VLAN_TUNNEL */ @@ -633,6 +635,8 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 }, [IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NLA_U8 }, [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 }, + [IFLA_BRPORT_MCAST_FLOOD] = { .type = NLA_U8 }, + [IFLA_BRPORT_BCAST_FLOOD] = { .type = NLA_U8 }, }; /* Change the state of the port and notify spanning tree */ diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 4eb773ccce11..4fd02831beed 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -45,6 +45,17 @@ bool libceph_compatible(void *data) } EXPORT_SYMBOL(libceph_compatible); +static int param_get_supported_features(char *buffer, + const struct kernel_param *kp) +{ + return sprintf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT); +} +static const struct kernel_param_ops param_ops_supported_features = { + .get = param_get_supported_features, +}; +module_param_cb(supported_features, ¶m_ops_supported_features, NULL, + S_IRUGO); + /* * find filename portion of a path (/foo/bar/baz -> baz) */ @@ -596,9 +607,7 @@ EXPORT_SYMBOL(ceph_client_gid); /* * create a fresh client instance */ -struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, - u64 supported_features, - u64 required_features) +struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private) { struct ceph_client *client; struct ceph_entity_addr *myaddr = NULL; @@ -615,14 +624,12 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, init_waitqueue_head(&client->auth_wq); client->auth_err = 0; - if (!ceph_test_opt(client, NOMSGAUTH)) - required_features |= CEPH_FEATURE_MSG_AUTH; - client->extra_mon_dispatch = NULL; - client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT | - supported_features; - client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT | - required_features; + client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT; + client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT; + + if (!ceph_test_opt(client, NOMSGAUTH)) + client->required_features |= CEPH_FEATURE_MSG_AUTH; /* msgr */ if (ceph_test_opt(client, MYIP)) diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c index b9233b990399..08ada893f01e 100644 --- a/net/ceph/cls_lock_client.c +++ b/net/ceph/cls_lock_client.c @@ -179,6 +179,57 @@ int ceph_cls_break_lock(struct ceph_osd_client *osdc, } EXPORT_SYMBOL(ceph_cls_break_lock); +int ceph_cls_set_cookie(struct ceph_osd_client *osdc, + struct ceph_object_id *oid, + struct ceph_object_locator *oloc, + char *lock_name, u8 type, char *old_cookie, + char *tag, char *new_cookie) +{ + int cookie_op_buf_size; + int name_len = strlen(lock_name); + int old_cookie_len = strlen(old_cookie); + int tag_len = strlen(tag); + int new_cookie_len = strlen(new_cookie); + void *p, *end; + struct page *cookie_op_page; + int ret; + + cookie_op_buf_size = name_len + sizeof(__le32) + + old_cookie_len + sizeof(__le32) + + tag_len + sizeof(__le32) + + new_cookie_len + sizeof(__le32) + + sizeof(u8) + CEPH_ENCODING_START_BLK_LEN; + if (cookie_op_buf_size > PAGE_SIZE) + return -E2BIG; + + cookie_op_page = alloc_page(GFP_NOIO); + if (!cookie_op_page) + return -ENOMEM; + + p = page_address(cookie_op_page); + end = p + cookie_op_buf_size; + + /* encode cls_lock_set_cookie_op struct */ + ceph_start_encoding(&p, 1, 1, + cookie_op_buf_size - CEPH_ENCODING_START_BLK_LEN); + ceph_encode_string(&p, end, lock_name, name_len); + ceph_encode_8(&p, type); + ceph_encode_string(&p, end, old_cookie, old_cookie_len); + ceph_encode_string(&p, end, tag, tag_len); + ceph_encode_string(&p, end, new_cookie, new_cookie_len); + + dout("%s lock_name %s type %d old_cookie %s tag %s new_cookie %s\n", + __func__, lock_name, type, old_cookie, tag, new_cookie); + ret = ceph_osdc_call(osdc, oid, oloc, "lock", "set_cookie", + CEPH_OSD_FLAG_WRITE, cookie_op_page, + cookie_op_buf_size, NULL, NULL); + + dout("%s: status %d\n", __func__, ret); + __free_page(cookie_op_page); + return ret; +} +EXPORT_SYMBOL(ceph_cls_set_cookie); + void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers) { int i; diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index c62b2b029a6e..71ba13927b3d 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c @@ -62,7 +62,8 @@ static int osdmap_show(struct seq_file *s, void *p) return 0; down_read(&osdc->lock); - seq_printf(s, "epoch %d flags 0x%x\n", map->epoch, map->flags); + seq_printf(s, "epoch %u barrier %u flags 0x%x\n", map->epoch, + osdc->epoch_barrier, map->flags); for (n = rb_first(&map->pg_pools); n; n = rb_next(n)) { struct ceph_pg_pool_info *pi = @@ -177,9 +178,7 @@ static void dump_request(struct seq_file *s, struct ceph_osd_request *req) seq_printf(s, "%llu\t", req->r_tid); dump_target(s, &req->r_t); - seq_printf(s, "\t%d\t%u'%llu", req->r_attempts, - le32_to_cpu(req->r_replay_version.epoch), - le64_to_cpu(req->r_replay_version.version)); + seq_printf(s, "\t%d", req->r_attempts); for (i = 0; i < req->r_num_ops; i++) { struct ceph_osd_req_op *op = &req->r_ops[i]; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 242d7c0d92f8..924f07c36ddb 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -961,6 +961,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, truncate_size, truncate_seq); } + req->r_abort_on_full = true; req->r_flags = flags; req->r_base_oloc.pool = layout->pool_id; req->r_base_oloc.pool_ns = ceph_try_get_string(layout->pool_ns); @@ -1005,7 +1006,7 @@ static bool osd_registered(struct ceph_osd *osd) */ static void osd_init(struct ceph_osd *osd) { - atomic_set(&osd->o_ref, 1); + refcount_set(&osd->o_ref, 1); RB_CLEAR_NODE(&osd->o_node); osd->o_requests = RB_ROOT; osd->o_linger_requests = RB_ROOT; @@ -1050,9 +1051,9 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) static struct ceph_osd *get_osd(struct ceph_osd *osd) { - if (atomic_inc_not_zero(&osd->o_ref)) { - dout("get_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref)-1, - atomic_read(&osd->o_ref)); + if (refcount_inc_not_zero(&osd->o_ref)) { + dout("get_osd %p %d -> %d\n", osd, refcount_read(&osd->o_ref)-1, + refcount_read(&osd->o_ref)); return osd; } else { dout("get_osd %p FAIL\n", osd); @@ -1062,9 +1063,9 @@ static struct ceph_osd *get_osd(struct ceph_osd *osd) static void put_osd(struct ceph_osd *osd) { - dout("put_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref), - atomic_read(&osd->o_ref) - 1); - if (atomic_dec_and_test(&osd->o_ref)) { + dout("put_osd %p %d -> %d\n", osd, refcount_read(&osd->o_ref), + refcount_read(&osd->o_ref) - 1); + if (refcount_dec_and_test(&osd->o_ref)) { osd_cleanup(osd); kfree(osd); } @@ -1297,8 +1298,9 @@ static bool target_should_be_paused(struct ceph_osd_client *osdc, __pool_full(pi); WARN_ON(pi->id != t->base_oloc.pool); - return (t->flags & CEPH_OSD_FLAG_READ && pauserd) || - (t->flags & CEPH_OSD_FLAG_WRITE && pausewr); + return ((t->flags & CEPH_OSD_FLAG_READ) && pauserd) || + ((t->flags & CEPH_OSD_FLAG_WRITE) && pausewr) || + (osdc->osdmap->epoch < osdc->epoch_barrier); } enum calc_target_result { @@ -1503,9 +1505,10 @@ static void encode_request(struct ceph_osd_request *req, struct ceph_msg *msg) ceph_encode_32(&p, req->r_flags); ceph_encode_timespec(p, &req->r_mtime); p += sizeof(struct ceph_timespec); - /* aka reassert_version */ - memcpy(p, &req->r_replay_version, sizeof(req->r_replay_version)); - p += sizeof(req->r_replay_version); + + /* reassert_version */ + memset(p, 0, sizeof(struct ceph_eversion)); + p += sizeof(struct ceph_eversion); /* oloc */ ceph_start_encoding(&p, 5, 4, @@ -1626,6 +1629,7 @@ static void maybe_request_map(struct ceph_osd_client *osdc) ceph_monc_renew_subs(&osdc->client->monc); } +static void complete_request(struct ceph_osd_request *req, int err); static void send_map_check(struct ceph_osd_request *req); static void __submit_request(struct ceph_osd_request *req, bool wrlocked) @@ -1635,6 +1639,7 @@ static void __submit_request(struct ceph_osd_request *req, bool wrlocked) enum calc_target_result ct_res; bool need_send = false; bool promoted = false; + bool need_abort = false; WARN_ON(req->r_tid); dout("%s req %p wrlocked %d\n", __func__, req, wrlocked); @@ -1650,8 +1655,13 @@ again: goto promote; } - if ((req->r_flags & CEPH_OSD_FLAG_WRITE) && - ceph_osdmap_flag(osdc, CEPH_OSDMAP_PAUSEWR)) { + if (osdc->osdmap->epoch < osdc->epoch_barrier) { + dout("req %p epoch %u barrier %u\n", req, osdc->osdmap->epoch, + osdc->epoch_barrier); + req->r_t.paused = true; + maybe_request_map(osdc); + } else if ((req->r_flags & CEPH_OSD_FLAG_WRITE) && + ceph_osdmap_flag(osdc, CEPH_OSDMAP_PAUSEWR)) { dout("req %p pausewr\n", req); req->r_t.paused = true; maybe_request_map(osdc); @@ -1669,6 +1679,8 @@ again: pr_warn_ratelimited("FULL or reached pool quota\n"); req->r_t.paused = true; maybe_request_map(osdc); + if (req->r_abort_on_full) + need_abort = true; } else if (!osd_homeless(osd)) { need_send = true; } else { @@ -1685,6 +1697,8 @@ again: link_request(osd, req); if (need_send) send_request(req); + else if (need_abort) + complete_request(req, -ENOSPC); mutex_unlock(&osd->lock); if (ct_res == CALC_TARGET_POOL_DNE) @@ -1799,6 +1813,97 @@ static void abort_request(struct ceph_osd_request *req, int err) complete_request(req, err); } +static void update_epoch_barrier(struct ceph_osd_client *osdc, u32 eb) +{ + if (likely(eb > osdc->epoch_barrier)) { + dout("updating epoch_barrier from %u to %u\n", + osdc->epoch_barrier, eb); + osdc->epoch_barrier = eb; + /* Request map if we're not to the barrier yet */ + if (eb > osdc->osdmap->epoch) + maybe_request_map(osdc); + } +} + +void ceph_osdc_update_epoch_barrier(struct ceph_osd_client *osdc, u32 eb) +{ + down_read(&osdc->lock); + if (unlikely(eb > osdc->epoch_barrier)) { + up_read(&osdc->lock); + down_write(&osdc->lock); + update_epoch_barrier(osdc, eb); + up_write(&osdc->lock); + } else { + up_read(&osdc->lock); + } +} +EXPORT_SYMBOL(ceph_osdc_update_epoch_barrier); + +/* + * Drop all pending requests that are stalled waiting on a full condition to + * clear, and complete them with ENOSPC as the return code. Set the + * osdc->epoch_barrier to the latest map epoch that we've seen if any were + * cancelled. + */ +static void ceph_osdc_abort_on_full(struct ceph_osd_client *osdc) +{ + struct rb_node *n; + bool victims = false; + + dout("enter abort_on_full\n"); + + if (!ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) && !have_pool_full(osdc)) + goto out; + + /* Scan list and see if there is anything to abort */ + for (n = rb_first(&osdc->osds); n; n = rb_next(n)) { + struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node); + struct rb_node *m; + + m = rb_first(&osd->o_requests); + while (m) { + struct ceph_osd_request *req = rb_entry(m, + struct ceph_osd_request, r_node); + m = rb_next(m); + + if (req->r_abort_on_full) { + victims = true; + break; + } + } + if (victims) + break; + } + + if (!victims) + goto out; + + /* + * Update the barrier to current epoch if it's behind that point, + * since we know we have some calls to be aborted in the tree. + */ + update_epoch_barrier(osdc, osdc->osdmap->epoch); + + for (n = rb_first(&osdc->osds); n; n = rb_next(n)) { + struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node); + struct rb_node *m; + + m = rb_first(&osd->o_requests); + while (m) { + struct ceph_osd_request *req = rb_entry(m, + struct ceph_osd_request, r_node); + m = rb_next(m); + + if (req->r_abort_on_full && + (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || + pool_full(osdc, req->r_t.target_oloc.pool))) + abort_request(req, -ENOSPC); + } + } +out: + dout("return abort_on_full barrier=%u\n", osdc->epoch_barrier); +} + static void check_pool_dne(struct ceph_osd_request *req) { struct ceph_osd_client *osdc = req->r_osdc; @@ -3252,11 +3357,13 @@ done: pausewr = ceph_osdmap_flag(osdc, CEPH_OSDMAP_PAUSEWR) || ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || have_pool_full(osdc); - if (was_pauserd || was_pausewr || pauserd || pausewr) + if (was_pauserd || was_pausewr || pauserd || pausewr || + osdc->osdmap->epoch < osdc->epoch_barrier) maybe_request_map(osdc); kick_requests(osdc, &need_resend, &need_resend_linger); + ceph_osdc_abort_on_full(osdc); ceph_monc_got_map(&osdc->client->monc, CEPH_SUB_OSDMAP, osdc->osdmap->epoch); up_write(&osdc->lock); @@ -4126,7 +4233,7 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc) close_osd(osd); } up_write(&osdc->lock); - WARN_ON(atomic_read(&osdc->homeless_osd.o_ref) != 1); + WARN_ON(refcount_read(&osdc->homeless_osd.o_ref) != 1); osd_cleanup(&osdc->homeless_osd); WARN_ON(!list_empty(&osdc->osd_lru)); diff --git a/net/ceph/pagelist.c b/net/ceph/pagelist.c index 6864007e64fc..ce09f73be759 100644 --- a/net/ceph/pagelist.c +++ b/net/ceph/pagelist.c @@ -16,7 +16,7 @@ static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl) void ceph_pagelist_release(struct ceph_pagelist *pl) { - if (!atomic_dec_and_test(&pl->refcnt)) + if (!refcount_dec_and_test(&pl->refcnt)) return; ceph_pagelist_unmap_tail(pl); while (!list_empty(&pl->head)) { diff --git a/net/ceph/snapshot.c b/net/ceph/snapshot.c index 705414e78ae0..e14a5d038656 100644 --- a/net/ceph/snapshot.c +++ b/net/ceph/snapshot.c @@ -49,7 +49,7 @@ struct ceph_snap_context *ceph_create_snap_context(u32 snap_count, if (!snapc) return NULL; - atomic_set(&snapc->nref, 1); + refcount_set(&snapc->nref, 1); snapc->num_snaps = snap_count; return snapc; @@ -59,7 +59,7 @@ EXPORT_SYMBOL(ceph_create_snap_context); struct ceph_snap_context *ceph_get_snap_context(struct ceph_snap_context *sc) { if (sc) - atomic_inc(&sc->nref); + refcount_inc(&sc->nref); return sc; } EXPORT_SYMBOL(ceph_get_snap_context); @@ -68,7 +68,7 @@ void ceph_put_snap_context(struct ceph_snap_context *sc) { if (!sc) return; - if (atomic_dec_and_test(&sc->nref)) { + if (refcount_dec_and_test(&sc->nref)) { /*printk(" deleting snap_context %p\n", sc);*/ kfree(sc); } diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 6bd2f8fb0476..ae35cce3a40d 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c @@ -24,9 +24,13 @@ static siphash_key_t ts_secret __read_mostly; static __always_inline void net_secret_init(void) { - net_get_random_once(&ts_secret, sizeof(ts_secret)); net_get_random_once(&net_secret, sizeof(net_secret)); } + +static __always_inline void ts_secret_init(void) +{ + net_get_random_once(&ts_secret, sizeof(ts_secret)); +} #endif #ifdef CONFIG_INET @@ -47,7 +51,7 @@ static u32 seq_scale(u32 seq) #endif #if IS_ENABLED(CONFIG_IPV6) -static u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr) +u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr) { const struct { struct in6_addr saddr; @@ -60,12 +64,14 @@ static u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr) if (sysctl_tcp_timestamps != 1) return 0; + ts_secret_init(); return siphash(&combined, offsetofend(typeof(combined), daddr), &ts_secret); } +EXPORT_SYMBOL(secure_tcpv6_ts_off); -u32 secure_tcpv6_seq_and_tsoff(const __be32 *saddr, const __be32 *daddr, - __be16 sport, __be16 dport, u32 *tsoff) +u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr, + __be16 sport, __be16 dport) { const struct { struct in6_addr saddr; @@ -78,14 +84,14 @@ u32 secure_tcpv6_seq_and_tsoff(const __be32 *saddr, const __be32 *daddr, .sport = sport, .dport = dport }; - u64 hash; + u32 hash; + net_secret_init(); hash = siphash(&combined, offsetofend(typeof(combined), dport), &net_secret); - *tsoff = secure_tcpv6_ts_off(saddr, daddr); return seq_scale(hash); } -EXPORT_SYMBOL(secure_tcpv6_seq_and_tsoff); +EXPORT_SYMBOL(secure_tcpv6_seq); u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) @@ -107,11 +113,12 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral); #endif #ifdef CONFIG_INET -static u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr) +u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr) { if (sysctl_tcp_timestamps != 1) return 0; + ts_secret_init(); return siphash_2u32((__force u32)saddr, (__force u32)daddr, &ts_secret); } @@ -121,15 +128,15 @@ static u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr) * it would be easy enough to have the former function use siphash_4u32, passing * the arguments as separate u32. */ -u32 secure_tcp_seq_and_tsoff(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport, u32 *tsoff) +u32 secure_tcp_seq(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) { - u64 hash; + u32 hash; + net_secret_init(); hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, (__force u32)sport << 16 | (__force u32)dport, &net_secret); - *tsoff = secure_tcp_ts_off(saddr, daddr); return seq_scale(hash); } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index b99168b0fabf..f75482bdee9a 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -951,7 +951,7 @@ static struct proto dccp_v4_prot = { .orphan_count = &dccp_orphan_count, .max_header = MAX_DCCP_HEADER, .obj_size = sizeof(struct dccp_sock), - .slab_flags = SLAB_DESTROY_BY_RCU, + .slab_flags = SLAB_TYPESAFE_BY_RCU, .rsk_prot = &dccp_request_sock_ops, .twsk_prot = &dccp_timewait_sock_ops, .h.hashinfo = &dccp_hashinfo, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index d9b6a4e403e7..840f14aaa016 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1014,7 +1014,7 @@ static struct proto dccp_v6_prot = { .orphan_count = &dccp_orphan_count, .max_header = MAX_DCCP_HEADER, .obj_size = sizeof(struct dccp6_sock), - .slab_flags = SLAB_DESTROY_BY_RCU, + .slab_flags = SLAB_TYPESAFE_BY_RCU, .rsk_prot = &dccp6_request_sock_ops, .twsk_prot = &dccp6_timewait_sock_ops, .h.hashinfo = &dccp_hashinfo, diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 482730cd8a56..eeb5fc561f80 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -110,7 +110,7 @@ struct neigh_table dn_neigh_table = { static int dn_neigh_construct(struct neighbour *neigh) { struct net_device *dev = neigh->dev; - struct dn_neigh *dn = (struct dn_neigh *)neigh; + struct dn_neigh *dn = container_of(neigh, struct dn_neigh, n); struct dn_dev *dn_db; struct neigh_parms *parms; @@ -339,7 +339,7 @@ int dn_to_neigh_output(struct net *net, struct sock *sk, struct sk_buff *skb) struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *) dst; struct neighbour *neigh = rt->n; - struct dn_neigh *dn = (struct dn_neigh *)neigh; + struct dn_neigh *dn = container_of(neigh, struct dn_neigh, n); struct dn_dev *dn_db; bool use_long; @@ -391,7 +391,7 @@ int dn_neigh_router_hello(struct net *net, struct sock *sk, struct sk_buff *skb) neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); - dn = (struct dn_neigh *)neigh; + dn = container_of(neigh, struct dn_neigh, n); if (neigh) { write_lock(&neigh->lock); @@ -451,7 +451,7 @@ int dn_neigh_endnode_hello(struct net *net, struct sock *sk, struct sk_buff *skb neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); - dn = (struct dn_neigh *)neigh; + dn = container_of(neigh, struct dn_neigh, n); if (neigh) { write_lock(&neigh->lock); @@ -510,7 +510,7 @@ static void neigh_elist_cb(struct neighbour *neigh, void *_info) if (neigh->dev != s->dev) return; - dn = (struct dn_neigh *) neigh; + dn = container_of(neigh, struct dn_neigh, n); if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) return; @@ -549,7 +549,7 @@ int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) static inline void dn_neigh_format_entry(struct seq_file *seq, struct neighbour *n) { - struct dn_neigh *dn = (struct dn_neigh *) n; + struct dn_neigh *dn = container_of(n, struct dn_neigh, n); char buf[DN_ASCBUF_LEN]; read_lock(&n->lock); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 5e313c1ac94f..1054d330bf9d 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -794,6 +794,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk, /* listeners have SOCK_RCU_FREE, not the children */ sock_reset_flag(newsk, SOCK_RCU_FREE); + inet_sk(newsk)->mc_list = NULL; + newsk->sk_mark = inet_rsk(req)->ir_mark; atomic64_set(&newsk->sk_cookie, atomic64_read(&inet_rsk(req)->ir_cookie)); diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 40977413fd48..4ec9affb2252 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -546,12 +546,13 @@ static int vti_fill_info(struct sk_buff *skb, const struct net_device *dev) struct ip_tunnel *t = netdev_priv(dev); struct ip_tunnel_parm *p = &t->parms; - nla_put_u32(skb, IFLA_VTI_LINK, p->link); - nla_put_be32(skb, IFLA_VTI_IKEY, p->i_key); - nla_put_be32(skb, IFLA_VTI_OKEY, p->o_key); - nla_put_in_addr(skb, IFLA_VTI_LOCAL, p->iph.saddr); - nla_put_in_addr(skb, IFLA_VTI_REMOTE, p->iph.daddr); - nla_put_u32(skb, IFLA_VTI_FWMARK, t->fwmark); + if (nla_put_u32(skb, IFLA_VTI_LINK, p->link) || + nla_put_be32(skb, IFLA_VTI_IKEY, p->i_key) || + nla_put_be32(skb, IFLA_VTI_OKEY, p->o_key) || + nla_put_in_addr(skb, IFLA_VTI_LOCAL, p->iph.saddr) || + nla_put_in_addr(skb, IFLA_VTI_REMOTE, p->iph.daddr) || + nla_put_u32(skb, IFLA_VTI_FWMARK, t->fwmark)) + return -EMSGSIZE; return 0; } diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 496b97e17aaf..0257d965f111 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -16,6 +16,7 @@ #include <linux/siphash.h> #include <linux/kernel.h> #include <linux/export.h> +#include <net/secure_seq.h> #include <net/tcp.h> #include <net/route.h> @@ -203,7 +204,7 @@ EXPORT_SYMBOL_GPL(__cookie_v4_check); struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, - struct dst_entry *dst) + struct dst_entry *dst, u32 tsoff) { struct inet_connection_sock *icsk = inet_csk(sk); struct sock *child; @@ -213,6 +214,7 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, NULL, &own_req); if (child) { atomic_set(&req->rsk_refcnt, 1); + tcp_sk(child)->tsoffset = tsoff; sock_rps_save_rxhash(child, skb); inet_csk_reqsk_queue_add(sk, req, child); } else { @@ -292,6 +294,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) struct rtable *rt; __u8 rcv_wscale; struct flowi4 fl4; + u32 tsoff = 0; if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies || !th->ack || th->rst) goto out; @@ -311,6 +314,11 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) memset(&tcp_opt, 0, sizeof(tcp_opt)); tcp_parse_options(skb, &tcp_opt, 0, NULL); + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcp_ts_off(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr); + tcp_opt.rcv_tsecr -= tsoff; + } + if (!cookie_timestamp_decode(&tcp_opt)) goto out; @@ -381,7 +389,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst); - ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst); + ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst, tsoff); /* ip_queue_xmit() depends on our flow being setup * Normal sockets get it right from inet_csk_route_child_sock() */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9739962bfb3f..5a3ad09e2786 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -85,7 +85,6 @@ int sysctl_tcp_dsack __read_mostly = 1; int sysctl_tcp_app_win __read_mostly = 31; int sysctl_tcp_adv_win_scale __read_mostly = 1; EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); -EXPORT_SYMBOL(sysctl_tcp_timestamps); /* rfc5961 challenge ack rate limiting */ int sysctl_tcp_challenge_ack_limit = 1000; @@ -6347,8 +6346,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, if (security_inet_conn_request(sk, skb, req)) goto drop_and_free; - if (isn && tmp_opt.tstamp_ok) - af_ops->init_seq_tsoff(skb, &tcp_rsk(req)->ts_off); + if (tmp_opt.tstamp_ok) + tcp_rsk(req)->ts_off = af_ops->init_ts_off(skb); if (!want_cookie && !isn) { /* Kill the following clause, if you dislike this way. */ @@ -6368,7 +6367,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, goto drop_and_release; } - isn = af_ops->init_seq_tsoff(skb, &tcp_rsk(req)->ts_off); + isn = af_ops->init_seq(skb); } if (!dst) { dst = af_ops->route_req(sk, &fl, req); @@ -6380,7 +6379,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, if (want_cookie) { isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); - tcp_rsk(req)->ts_off = 0; req->cookie_ts = tmp_opt.tstamp_ok; if (!tmp_opt.tstamp_ok) inet_rsk(req)->ecn_ok = 0; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cbbafe546c0f..5ab2aac5ca19 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -94,12 +94,18 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, struct inet_hashinfo tcp_hashinfo; EXPORT_SYMBOL(tcp_hashinfo); -static u32 tcp_v4_init_seq_and_tsoff(const struct sk_buff *skb, u32 *tsoff) +static u32 tcp_v4_init_seq(const struct sk_buff *skb) { - return secure_tcp_seq_and_tsoff(ip_hdr(skb)->daddr, - ip_hdr(skb)->saddr, - tcp_hdr(skb)->dest, - tcp_hdr(skb)->source, tsoff); + return secure_tcp_seq(ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr, + tcp_hdr(skb)->dest, + tcp_hdr(skb)->source); +} + +static u32 tcp_v4_init_ts_off(const struct sk_buff *skb) +{ + return secure_tcp_ts_off(ip_hdr(skb)->daddr, + ip_hdr(skb)->saddr); } int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) @@ -145,7 +151,6 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) struct flowi4 *fl4; struct rtable *rt; int err; - u32 seq; struct ip_options_rcu *inet_opt; struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; @@ -232,13 +237,13 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) rt = NULL; if (likely(!tp->repair)) { - seq = secure_tcp_seq_and_tsoff(inet->inet_saddr, - inet->inet_daddr, - inet->inet_sport, - usin->sin_port, - &tp->tsoffset); if (!tp->write_seq) - tp->write_seq = seq; + tp->write_seq = secure_tcp_seq(inet->inet_saddr, + inet->inet_daddr, + inet->inet_sport, + usin->sin_port); + tp->tsoffset = secure_tcp_ts_off(inet->inet_saddr, + inet->inet_daddr); } inet->inet_id = tp->write_seq ^ jiffies; @@ -1239,7 +1244,8 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { .cookie_init_seq = cookie_v4_init_sequence, #endif .route_req = tcp_v4_route_req, - .init_seq_tsoff = tcp_v4_init_seq_and_tsoff, + .init_seq = tcp_v4_init_seq, + .init_ts_off = tcp_v4_init_ts_off, .send_synack = tcp_v4_send_synack, }; @@ -2389,7 +2395,7 @@ struct proto tcp_prot = { .sysctl_rmem = sysctl_tcp_rmem, .max_header = MAX_TCP_HEADER, .obj_size = sizeof(struct tcp_sock), - .slab_flags = SLAB_DESTROY_BY_RCU, + .slab_flags = SLAB_TYPESAFE_BY_RCU, .twsk_prot = &tcp_timewait_sock_ops, .rsk_prot = &tcp_request_sock_ops, .h.hashinfo = &tcp_hashinfo, diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 60111a0fc201..4858e190f6ac 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1514,6 +1514,7 @@ static void tcp_cwnd_application_limited(struct sock *sk) static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) { + const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; struct tcp_sock *tp = tcp_sk(sk); /* Track the maximum number of outstanding packets in each @@ -1536,7 +1537,8 @@ static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) tp->snd_cwnd_used = tp->packets_out; if (sysctl_tcp_slow_start_after_idle && - (s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto) + (s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto && + !ca_ops->cong_control) tcp_cwnd_application_limited(sk); /* The following conditions together indicate the starvation diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 77a4bd526d6e..8d297a79b568 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3548,6 +3548,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, */ static struct notifier_block ipv6_dev_notf = { .notifier_call = addrconf_notify, + .priority = ADDRCONF_NOTIFY_PRIORITY, }; static void addrconf_type_change(struct net_device *dev, unsigned long event) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 2f1136627dcb..dc61b0b5e64e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3709,7 +3709,10 @@ static int ip6_route_dev_notify(struct notifier_block *this, struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct net *net = dev_net(dev); - if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { + if (!(dev->flags & IFF_LOOPBACK)) + return NOTIFY_OK; + + if (event == NETDEV_REGISTER) { net->ipv6.ip6_null_entry->dst.dev = dev; net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES @@ -3718,6 +3721,12 @@ static int ip6_route_dev_notify(struct notifier_block *this, net->ipv6.ip6_blk_hole_entry->dst.dev = dev; net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); #endif + } else if (event == NETDEV_UNREGISTER) { + in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); + in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); +#endif } return NOTIFY_OK; @@ -4024,7 +4033,7 @@ static struct pernet_operations ip6_route_net_late_ops = { static struct notifier_block ip6_route_dev_notifier = { .notifier_call = ip6_route_dev_notify, - .priority = 0, + .priority = ADDRCONF_NOTIFY_PRIORITY - 10, }; void __init ip6_route_init_special_entries(void) diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 895ff650db43..5abc3692b901 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -18,6 +18,7 @@ #include <linux/random.h> #include <linux/siphash.h> #include <linux/kernel.h> +#include <net/secure_seq.h> #include <net/ipv6.h> #include <net/tcp.h> @@ -143,6 +144,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) int mss; struct dst_entry *dst; __u8 rcv_wscale; + u32 tsoff = 0; if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies || !th->ack || th->rst) goto out; @@ -162,6 +164,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) memset(&tcp_opt, 0, sizeof(tcp_opt)); tcp_parse_options(skb, &tcp_opt, 0, NULL); + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + tsoff = secure_tcpv6_ts_off(ipv6_hdr(skb)->daddr.s6_addr32, + ipv6_hdr(skb)->saddr.s6_addr32); + tcp_opt.rcv_tsecr -= tsoff; + } + if (!cookie_timestamp_decode(&tcp_opt)) goto out; @@ -242,7 +250,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst); - ret = tcp_get_cookie_sock(sk, skb, req, dst); + ret = tcp_get_cookie_sock(sk, skb, req, dst, tsoff); out: return ret; out_free: diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8e42e8f54b70..7a8237acd210 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -101,12 +101,18 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) } } -static u32 tcp_v6_init_seq_and_tsoff(const struct sk_buff *skb, u32 *tsoff) +static u32 tcp_v6_init_seq(const struct sk_buff *skb) { - return secure_tcpv6_seq_and_tsoff(ipv6_hdr(skb)->daddr.s6_addr32, - ipv6_hdr(skb)->saddr.s6_addr32, - tcp_hdr(skb)->dest, - tcp_hdr(skb)->source, tsoff); + return secure_tcpv6_seq(ipv6_hdr(skb)->daddr.s6_addr32, + ipv6_hdr(skb)->saddr.s6_addr32, + tcp_hdr(skb)->dest, + tcp_hdr(skb)->source); +} + +static u32 tcp_v6_init_ts_off(const struct sk_buff *skb) +{ + return secure_tcpv6_ts_off(ipv6_hdr(skb)->daddr.s6_addr32, + ipv6_hdr(skb)->saddr.s6_addr32); } static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, @@ -122,7 +128,6 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, struct flowi6 fl6; struct dst_entry *dst; int addr_type; - u32 seq; int err; struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; @@ -282,13 +287,13 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, sk_set_txhash(sk); if (likely(!tp->repair)) { - seq = secure_tcpv6_seq_and_tsoff(np->saddr.s6_addr32, - sk->sk_v6_daddr.s6_addr32, - inet->inet_sport, - inet->inet_dport, - &tp->tsoffset); if (!tp->write_seq) - tp->write_seq = seq; + tp->write_seq = secure_tcpv6_seq(np->saddr.s6_addr32, + sk->sk_v6_daddr.s6_addr32, + inet->inet_sport, + inet->inet_dport); + tp->tsoffset = secure_tcpv6_ts_off(np->saddr.s6_addr32, + sk->sk_v6_daddr.s6_addr32); } if (tcp_fastopen_defer_connect(sk, &err)) @@ -749,7 +754,8 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { .cookie_init_seq = cookie_v6_init_sequence, #endif .route_req = tcp_v6_route_req, - .init_seq_tsoff = tcp_v6_init_seq_and_tsoff, + .init_seq = tcp_v6_init_seq, + .init_ts_off = tcp_v6_init_ts_off, .send_synack = tcp_v6_send_synack, }; @@ -1911,7 +1917,7 @@ struct proto tcpv6_prot = { .sysctl_rmem = sysctl_tcp_rmem, .max_header = MAX_TCP_HEADER, .obj_size = sizeof(struct tcp6_sock), - .slab_flags = SLAB_DESTROY_BY_RCU, + .slab_flags = SLAB_TYPESAFE_BY_RCU, .twsk_prot = &tcp6_timewait_sock_ops, .rsk_prot = &tcp6_request_sock_ops, .h.hashinfo = &tcp_hashinfo, diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index cb4fff785cbf..8364fe5b59e4 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -142,7 +142,7 @@ static struct proto llc_proto = { .name = "LLC", .owner = THIS_MODULE, .obj_size = sizeof(struct llc_sock), - .slab_flags = SLAB_DESTROY_BY_RCU, + .slab_flags = SLAB_TYPESAFE_BY_RCU, }; /** diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 8bc5a1bd2d45..9b02c13d258b 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -506,7 +506,7 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap, again: sk_nulls_for_each_rcu(rc, node, laddr_hb) { if (llc_estab_match(sap, daddr, laddr, rc)) { - /* Extra checks required by SLAB_DESTROY_BY_RCU */ + /* Extra checks required by SLAB_TYPESAFE_BY_RCU */ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) goto again; if (unlikely(llc_sk(rc)->sap != sap || @@ -565,7 +565,7 @@ static struct sock *__llc_lookup_listener(struct llc_sap *sap, again: sk_nulls_for_each_rcu(rc, node, laddr_hb) { if (llc_listener_match(sap, laddr, rc)) { - /* Extra checks required by SLAB_DESTROY_BY_RCU */ + /* Extra checks required by SLAB_TYPESAFE_BY_RCU */ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) goto again; if (unlikely(llc_sk(rc)->sap != sap || diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 5404d0d195cc..63b6ab056370 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -328,7 +328,7 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap, again: sk_nulls_for_each_rcu(rc, node, laddr_hb) { if (llc_dgram_match(sap, laddr, rc)) { - /* Extra checks required by SLAB_DESTROY_BY_RCU */ + /* Extra checks required by SLAB_TYPESAFE_BY_RCU */ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) goto again; if (unlikely(llc_sk(rc)->sap != sap || diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6db09fa18269..364d4e137649 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -66,6 +66,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, 2 + (IEEE80211_MAX_SUPP_RATES - 8) + 2 + sizeof(struct ieee80211_ht_cap) + 2 + sizeof(struct ieee80211_ht_operation) + + 2 + sizeof(struct ieee80211_vht_cap) + + 2 + sizeof(struct ieee80211_vht_operation) + ifibss->ie_len; presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL); if (!presp) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 89dff563b1ec..0ea9712bd99e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4382,6 +4382,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) return -EINVAL; + /* If a reconfig is happening, bail out */ + if (local->in_reconfig) + return -EBUSY; + if (assoc) { rcu_read_lock(); have_sta = sta_info_get(sdata, cbss->bssid); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3c8f1ed2f555..e847dbaa0c6b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -911,7 +911,7 @@ static unsigned int early_drop_list(struct net *net, continue; /* kill only if still in same netns -- might have moved due to - * SLAB_DESTROY_BY_RCU rules. + * SLAB_TYPESAFE_BY_RCU rules. * * We steal the timer reference. If that fails timer has * already fired or someone else deleted it. Just drop ref @@ -1114,7 +1114,7 @@ __nf_conntrack_alloc(struct net *net, /* * Do not use kmem_cache_zalloc(), as this cache uses - * SLAB_DESTROY_BY_RCU. + * SLAB_TYPESAFE_BY_RCU. */ ct = kmem_cache_alloc(nf_conntrack_cachep, gfp); if (ct == NULL) @@ -1159,7 +1159,7 @@ void nf_conntrack_free(struct nf_conn *ct) struct net *net = nf_ct_net(ct); /* A freed object has refcnt == 0, that's - * the golden rule for SLAB_DESTROY_BY_RCU + * the golden rule for SLAB_TYPESAFE_BY_RCU */ NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 0); @@ -1929,7 +1929,7 @@ int nf_conntrack_init_start(void) nf_conntrack_cachep = kmem_cache_create("nf_conntrack", sizeof(struct nf_conn), NFCT_INFOMASK + 1, - SLAB_DESTROY_BY_RCU | SLAB_HWCACHE_ALIGN, NULL); + SLAB_TYPESAFE_BY_RCU | SLAB_HWCACHE_ALIGN, NULL); if (!nf_conntrack_cachep) goto err_cachep; diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 5b6ee21368a6..6793d7348cc8 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -101,7 +101,7 @@ struct proto smc_proto = { .unhash = smc_unhash_sk, .obj_size = sizeof(struct smc_sock), .h.smc_hash = &smc_v4_hashinfo, - .slab_flags = SLAB_DESTROY_BY_RCU, + .slab_flags = SLAB_TYPESAFE_BY_RCU, }; EXPORT_SYMBOL_GPL(smc_proto); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 570fc95dc507..c3bc9da30cff 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2764,8 +2764,8 @@ static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev, nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]); /* bits 0 and 63 are reserved and must be zero */ - if ((mumimo_groups[0] & BIT(7)) || - (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0))) + if ((mumimo_groups[0] & BIT(0)) || + (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(7))) return -EINVAL; params->vht_mumimo_groups = mumimo_groups; diff --git a/security/inode.c b/security/inode.c index 2cb14162ff8d..eccd58ef2ae8 100644 --- a/security/inode.c +++ b/security/inode.c @@ -28,7 +28,7 @@ static int mount_count; static int fill_super(struct super_block *sb, void *data, int silent) { - static struct tree_descr files[] = {{""}}; + static const struct tree_descr files[] = {{""}}; return simple_fill_super(sb, SECURITYFS_MAGIC, files); } diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ce7171884223..50062e70140d 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1496,7 +1496,7 @@ static const struct file_operations sel_avc_cache_stats_ops = { static int sel_make_avc_files(struct dentry *dir) { int i; - static struct tree_descr files[] = { + static const struct tree_descr files[] = { { "cache_threshold", &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR }, { "hash_stats", &sel_avc_hash_stats_ops, S_IRUGO }, @@ -1805,7 +1805,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode; struct inode_security_struct *isec; - static struct tree_descr selinux_files[] = { + static const struct tree_descr selinux_files[] = { [SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR}, [SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR}, [SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO}, diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 366b8356f75b..f6482e53d55a 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -2855,7 +2855,7 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) int rc; struct inode *root_inode; - static struct tree_descr smack_files[] = { + static const struct tree_descr smack_files[] = { [SMK_LOAD] = { "load", &smk_load_ops, S_IRUGO|S_IWUSR}, [SMK_CIPSO] = { diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index ea6e373edc27..93eede4e8fbe 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -170,7 +170,7 @@ qemu_append="`identify_qemu_append "$QEMU"`" # Pull in Kconfig-fragment boot parameters boot_args="`configfrag_boot_params "$boot_args" "$config_template"`" # Generate kernel-version-specific boot parameters -boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`" +boot_args="`per_version_boot_params "$boot_args" $resdir/.config $seconds`" if test -n "$TORTURE_BUILDONLY" then |