Maybe a bit over the top, but you could use l3regex to achieve this
\documentclass{article}
\usepackage{l3regex,xparse}
\ExplSyntaxOn
\cs_generate_variant:Nn \tl_rescan:nn { nV }
\NewDocumentCommand \upsc { m }
{
\tl_set:Nn \l_tmpa_tl {#1}
\regex_replace_all:nnN { ([A-Z]+) }
{ \c{textsc} \cB\{ \c{lowercase} \cB\{ \1 \cE\} \cE\} } \l_tmpa_tl
\tl_use:N \l_tmpa_tl
}
\ExplSyntaxOff
\begin{document}
\upsc{ABCabcDEF}
\end{document}
This uses the latest experimental version of l3regex, which is on CTAN and which has an 'extended regex' system to allow the inclusion of category-code information in the search and replace text.
You could set up a search for upper-case letters in the same way using alternative methods (such as xstring).
Explanation of the code
The basic idea here is to store the text, do a replacement then print it again. I've chosen to replace each upper case <Letter> by
\textsc{\lowercase{<Letter>}}
The search part is a simple regex ([A-Z]+), which will capture the letter as \1 (in the replace part). There, \c{textsc} will create the control sequence \textsc in the updated text and \c{lowercase} creates \lowercase. \1 is the captured letter from the search part, while \cB\{ and \cE\} possibly need a bit of explanation. In the replacement text, \cB\{ creates the character { (which needs to be escaped) with category code 'Begin group'. Similarly, \cE\} creates the character } with category code 'End group'.
The final stage is to insert the result into the input stream. If you want to see what is happening, try adding \tl_show:N \l_tmpa_tl after the \tl_use:N line.