Given your additional information that there will be "[n]o mixed characters, it will always be a single character or a repeat of a single character," this formula should produce the result you want:
=ArrayFormula(QUERY(FLATTEN(SPLIT(REGEXREPLACE(QUERY(FLATTEN(W2:Y),"SELECT * WHERE Col1 Is Not Null"),"(.)","$1~"),"~",0,1)),"SELECT Col1, COUNT(Col1) WHERE Col1 Is Not Null GROUP BY Col1 Label COUNT(Col1) ''"))
IMPORTANT: In your post example, you place the results directly underneath the raw data. That is never a good idea, because you'd have to modify the location or the formula every time you add raw data. You should keep your raw-data columns allocated solely to that data and place such a formula as I've provided here to one side or the other, or in a separate sheet (understanding that the latter would require adding the raw-data sheet name to the target range in the formula).
As for how this formula works, please verify that it does, in fact, product the results you want and report back. Once I know that it's what you're after, I'll add an explanation.